You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Loosely scoped: session-start notifier for open conflict-journal records (Claude Code, Codex) #2540
Not urgent — capturing the idea and what's already been verified about it, not a fully-specified task yet.
The conflict journal (ADR-068) and its pull-based CLI/agent query surface (#2537) let an agent check for open sync conflicts if it thinks to ask. This issue is about a push complement: proactively surfacing "NodeSpace has open sync conflicts" into an agent's session at start, via each harness's own session-lifecycle hook mechanism, piggybacking on the skill installer's existing footprint in each harness's config directory.
Mechanism, precisely (verified against real harness docs, not guessed): this is not a persistent event listener or a live callback connection. It's a spawn-and-inject callback — you register a shell command in the harness's own config file (e.g. .claude/settings.json's SessionStart hooks array), the harness spawns that command as a one-shot subprocess whenever the lifecycle event fires (session start/resume/clear/etc.), the subprocess does its check and writes a result to stdout, and the harness injects that stdout directly into the agent's context for that turn. Stateless per invocation — no daemon-side listener, no persistent connection.
Verified harness support (real documentation, not inferred)
Claude Code — confirmed. SessionStart event, config at ~/.claude/settings.json (user) or .claude/settings.json (project, committable), hooks merge across levels rather than requiring exclusive ownership, stdout explicitly documented as injected into context.
Codex CLI — confirmed. Full lifecycle hook set including SessionStart, config via hooks.json or config.toml, stdout added as "extra developer context." Reached general availability per OpenAI's announcement.
Antigravity CLI (the harness NodeSpace is migrating to per Replace Gemini CLI with Antigravity CLI as a supported PTY agent #2473, superseding Gemini CLI) — confirmed absent. Its documented hook set is PreToolUse/PostToolUse/PreInvocation/PostInvocation/Stop — no session-start-equivalent at all. Not weaker, genuinely missing. (Gemini CLI, the predecessor, does have a real SessionStart hook — irrelevant since NodeSpace is moving away from it.)
OpenCode — confirmed no, not just unverified. The exact feature was requested (anomalyco/opencode#5409) and closed by maintainers as "not planned." The closest existing event (session.created) fires lazily on first prompt, not process start, and has open reliability issues.
Pi — has a real session_start event and a plausible context-injection API (pi.sendMessage()), less thoroughly verified than the above two. Excluded here regardless, since Pi isn't in the skill installer's AGENTS list at all yet (Pi is a spawnable PTY agent but gets no skill install (missing from AGENTS list) #2539) — hook support on a harness without base skill install would be solving things out of order.
Scope this to Claude Code and Codex only, when it's picked up. Revisit Antigravity/OpenCode/Pi individually if their situations change (a documented hook lands, a maintainer reverses course, #2539 ships).
Key risks that must shape the design, not be left to implementation-time judgment
Global hook, unrelated work. These hooks register at the user/global config level, not per-project. The hook script itself must cheaply check NodeSpace relevance (is this a NodeSpace project? is nodespace on PATH? does CWD or an ancestor have a NodeSpace marker?) and exit silently (no output, exit 0) if not relevant — first thing it does, before anything else.
Latency on every session start, including sessions with nothing to do with NodeSpace. The relevance check must short-circuit before spawning the nodespace binary where possible. The actual conflict-check call needs a hard, short timeout (~1-2s, not the ~30s pattern used elsewhere) and must fail silent/open on timeout — never block or error session start.
Multiple local NodeSpace databases (per ADR-053, one daemon can serve several DBs). The hook must resolve the same DB the CLI/daemon would resolve for the current working directory/session context — reuse that resolution, don't invent a separate one. Otherwise it'll surface conflicts from an unrelated database.
Naming collision: packages/skill/src/agents.ts's Claude Code shim already has a file called nodespace-hook.ts, which means something different (ReAct-loop tool registration, not a lifecycle hook). Whatever this becomes must not be named "hook" in a way that collides with that existing concept in the same directory.
Opt-in, off by default. This is a real behavior change (uninvited proactive output into sessions unrelated to NodeSpace) versus the existing skill install (passive, zero session-start cost). Should be an explicit install flag (e.g. nodespace skill install --with-hooks), not silently bundled into the default install path.
Explicitly not decided yet
Exact CLI flag/prompt shape for opt-in
Exact hook script naming and location within the shim structure
Uninstall handling (removing a hook entry from settings.json/config.toml without disturbing a user's other hooks — this is new surface, the installer doesn't currently write to these particular config keys)
References
ADR-068: nodespace-docs/decisions/068-convergence-conflicts-are-records-not-flags.md (the journal this would query)
Verified detail on Claude Code's SessionStart timing, for whoever picks this up:
Fires before the user's first message is processed — not lazily alongside it (unlike OpenCode's rejected session.created, which was disqualified partly for firing on first prompt rather than at true start).
Fires on every session boundary, not just true initialization: matchers are startup, resume, clear, compact, fork. A naive hook with no matcher filter re-runs on all five, which the "relevance check must be cheap and first" requirement above already anticipates, but worth being explicit that "SessionStart" really means "session-boundary event."
What this is
Not urgent — capturing the idea and what's already been verified about it, not a fully-specified task yet.
The conflict journal (ADR-068) and its pull-based CLI/agent query surface (#2537) let an agent check for open sync conflicts if it thinks to ask. This issue is about a push complement: proactively surfacing "NodeSpace has open sync conflicts" into an agent's session at start, via each harness's own session-lifecycle hook mechanism, piggybacking on the skill installer's existing footprint in each harness's config directory.
Mechanism, precisely (verified against real harness docs, not guessed): this is not a persistent event listener or a live callback connection. It's a spawn-and-inject callback — you register a shell command in the harness's own config file (e.g.
.claude/settings.json'sSessionStarthooks array), the harness spawns that command as a one-shot subprocess whenever the lifecycle event fires (session start/resume/clear/etc.), the subprocess does its check and writes a result to stdout, and the harness injects that stdout directly into the agent's context for that turn. Stateless per invocation — no daemon-side listener, no persistent connection.Verified harness support (real documentation, not inferred)
SessionStartevent, config at~/.claude/settings.json(user) or.claude/settings.json(project, committable), hooks merge across levels rather than requiring exclusive ownership, stdout explicitly documented as injected into context.SessionStart, config viahooks.jsonorconfig.toml, stdout added as "extra developer context." Reached general availability per OpenAI's announcement.PreToolUse/PostToolUse/PreInvocation/PostInvocation/Stop— no session-start-equivalent at all. Not weaker, genuinely missing. (Gemini CLI, the predecessor, does have a realSessionStarthook — irrelevant since NodeSpace is moving away from it.)anomalyco/opencode#5409) and closed by maintainers as "not planned." The closest existing event (session.created) fires lazily on first prompt, not process start, and has open reliability issues.session_startevent and a plausible context-injection API (pi.sendMessage()), less thoroughly verified than the above two. Excluded here regardless, since Pi isn't in the skill installer'sAGENTSlist at all yet (Pi is a spawnable PTY agent but gets no skill install (missing from AGENTS list) #2539) — hook support on a harness without base skill install would be solving things out of order.Scope this to Claude Code and Codex only, when it's picked up. Revisit Antigravity/OpenCode/Pi individually if their situations change (a documented hook lands, a maintainer reverses course, #2539 ships).
Key risks that must shape the design, not be left to implementation-time judgment
nodespaceon PATH? does CWD or an ancestor have a NodeSpace marker?) and exit silently (no output, exit 0) if not relevant — first thing it does, before anything else.nodespacebinary where possible. The actual conflict-check call needs a hard, short timeout (~1-2s, not the ~30s pattern used elsewhere) and must fail silent/open on timeout — never block or error session start.packages/skill/src/agents.ts's Claude Code shim already has a file callednodespace-hook.ts, which means something different (ReAct-loop tool registration, not a lifecycle hook). Whatever this becomes must not be named "hook" in a way that collides with that existing concept in the same directory.nodespace skill install --with-hooks), not silently bundled into the default install path.Explicitly not decided yet
settings.json/config.tomlwithout disturbing a user's other hooks — this is new surface, the installer doesn't currently write to these particular config keys)References
nodespace-docs/decisions/068-convergence-conflicts-are-records-not-flags.md(the journal this would query)packages/skill/src/agents.ts/packages/skill/src/installer.ts(where this would live)