Skip to content

fix(gateway): Move hooks and pairing_store init to __init__ - #113

Closed
Bartok9 wants to merge 1 commit into
NousResearch:mainfrom
Bartok9:fix-hooks-init-placement
Closed

fix(gateway): Move hooks and pairing_store init to __init__#113
Bartok9 wants to merge 1 commit into
NousResearch:mainfrom
Bartok9:fix-hooks-init-placement

Conversation

@Bartok9

@Bartok9 Bartok9 commented Feb 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #110

Problem

The pairing_store and hooks initialization was accidentally placed inside _flush_memories_before_reset() instead of __init__(), causing the gateway to crash on startup with:

AttributeError: 'GatewayRunner' object has no attribute 'hooks'

This affected fresh installs where the gateway service would fail immediately when calling self.hooks.discover_and_load() in start().

Solution

Moved the initialization to the proper location at the end of GatewayRunner.__init__().

Testing

  • Verified Python syntax is valid
  • The fix matches exactly what the issue reporter identified as the solution

Fixes NousResearch#110

The pairing_store and hooks initialization was accidentally placed
inside _flush_memories_before_reset() instead of __init__(), causing
the gateway to crash on startup with:

    AttributeError: GatewayRunner object has no attribute hooks

This affected fresh installs where the gateway service would fail
immediately when calling self.hooks.discover_and_load() in start().

Moved the initialization to the proper location at the end of
GatewayRunner.__init__().
@Bartok9
Bartok9 force-pushed the fix-hooks-init-placement branch from 126fa1f to e9e78c7 Compare February 27, 2026 08:21
@teknium1

Copy link
Copy Markdown
Contributor

Fixed with fec5d59

@teknium1 teknium1 closed this Feb 27, 2026
jarvis-stark-ops added a commit to 1Team-Engineering/hermes-agent that referenced this pull request Jun 16, 2026
* feat(mcp): scaffold hermes-tools-mcp stdio server with initialize

NousResearch#109

Minimal stdio JSON-RPC server that responds to MCP 'initialize' with
the expected protocol version + capabilities. Tools surface comes in
follow-up commits. Env-bound to (profile, project) scope.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(mcp): tools/list returns filtered Hermes tool surface

NousResearch#109

Filters the live Hermes tool registry to the v1 surface defined in
spec §4.1. Includes special hermes_set_task tool for per-turn task
context updates.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(mcp): tools/call dispatches to Hermes tool registry

NousResearch#109

hermes_set_task updates per-turn task context (task_id, workspace).
All other tools/call requests filter through ALLOWED_TOOLS, then
dispatch via registry.dispatch() which handles both sync and async
tools. Denied tools (kanban_dispatch etc.) return isError=true.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(kanban): add task_sessions table for relay scope tracking

NousResearch#113

Per spec §4.7 — tracks (profile, project) → tmux session, claude
session_id, FIFO path, MCP config path, project root, scope cwd,
task count, timestamps. Helpers: upsert_session, get_session,
touch_session, mark_compacted, evict_session, list_idle_sessions.

* feat(relay): project derivation + task header builder

NousResearch#114

derive_project maps a kanban workspace to its 'project' key:
  - scratch workspaces -> 'scratch'
  - git workspaces -> basename of git root
  - else raises ProviderError (B11: no silent default)

build_task_header prepends '[task_id=... workspace=...]' to each
user prompt so claude knows the current task without an MCP roundtrip.

* feat(provider): register claude-code-relay ProviderProfile

NousResearch#112

Registers the provider via the existing bundled-plugin pattern under
plugins/model-providers/claude-code-relay/__init__.py. api_mode=
'claude_code_relay' is a new tag for the transport defined in the
next commit. auth_type='none' because the claude binary handles its
own OAuth — the relay just shells out.

* feat(transport): scope spawn + send turn helpers

NousResearch#112

ScopeContext bundles (profile, project, workspace). ensure_scope
either finds a live tmux or invokes relay-spawn-scope.sh (writing
the MCP config first). send_turn prepends the task header and
relays through relay-send.sh, returning the captured response.
Also added monkeypatch for derive_project_root in spawn test since
tmp_path is not a git repo.

* feat(transport): OpenAI-compat ChatCompletion response shape

NousResearch#112

chat_completion() returns the standard OpenAI ChatCompletion object.
Only the latest user message is forwarded — prior conversation rides
on claude's in-session memory. Usage fields left null; /compact hook
in next task captures /usage and backfills.

* feat(kanban): /compact between-task hook for relay scopes

NousResearch#115

After a task with provider=claude-code-relay completes or blocks,
send /compact to its (profile, project) scope. Per B10, failures
are logged but never block the completion. Records last_compacted_at
on task_sessions.

Also: add tasks.provider column to SCHEMA_SQL + additive ALTER migration;
set conn.row_factory=sqlite3.Row in init_db test-fixture shortcut so
complete_task works correctly in :memory: tests.

Spike 2 (2026-06-15) confirmed /compact returns 'Not enough messages
to compact' on short sessions; that's handled cleanly via the timeout
in relay-send.sh slash-command extension.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(relay): idle-eviction cron step

NousResearch#116

evict_idle_scopes deletes task_sessions rows whose last_used_at is
older than HERMES_RELAY_IDLE_EVICT_SECS (default 86400 = 24h),
and tears down the tmux session via relay-kill-scope.sh.

Wire into nightly-hermes-maintenance follows separately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(relay): boot-check that Hermes Stop hook is installed

NousResearch#109

B3: Stop hook is mandatory for the relay to detect turn-end via FIFO.
Boot-check raises ProviderError with installer path if the hook is
missing — fail loud instead of silently hanging 180s per turn.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(relay): validate ScopeContext.profile + project against B8 regex

Per code review on PR #20 — the shell relay-spawn-scope.sh validates
^[a-zA-Z0-9_-]+$ but Python-side _write_mcp_config writes /tmp/hermes-mcp-{slug}.json
BEFORE invoking the shell. Slugs containing / or .. would have allowed
path traversal out of /tmp.

Add same regex check in ScopeContext.__post_init__. Closes B8 (spec §3).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(relay): chmod 0o600 on /tmp MCP config files

Defense-in-depth: prevent workspace paths in the MCP config from leaking
to other users sharing /tmp. Per code review on PR #20.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(kanban): honor HERMES_RELAY_BIN in /compact hook for consistency

Transport reads HERMES_RELAY_BIN; the kanban_db /compact hook should
too. Per code review on PR #20.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(relay): preserve task_sessions row when relay-kill-scope.sh fails

Per code review on PR #20 — previously evicted the DB row even on kill
failure, orphaning the tmux session with no record to retry. Now check
rc; only evict DB row on rc=0. Failed scopes get retried on next cron tick.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(relay): log WARNING when relay-send exits 4 (Stop-hook timeout)

Per code review on PR #20 — exit 4 means partial response, but callers
had no signal. Add a logger.warning so operators see the partial in logs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Jarvis <jarvis@Kaipos-Mac-mini.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] hermes-gateway.service fails to start: 'GatewayRunner' object has no attribute 'hooks'

2 participants