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
The event channel carries no session-lifecycle signal. An ended session persists in the lane view as "idle" indefinitely, a session is invisible until its first instrumented skill emits, and the waiting-on-user state rides the least reliable skill emission point (end of turn). Session end has no skill emission point at all — ending is not a skill moment — and activity-based inference is ruled out: sessions legitimately sit idle for days.
Context
Both harnesses expose event hooks whose payloads carry session_id and cwd. Confirmed inventory: Claude Code SessionStart, SessionEnd, UserPromptSubmit, Stop; Rovo Dev on_session_start, on_session_end, on_user_prompt, on_complete (configured under eventHooks in ~/.rovodev/config.yml; config is read at startup, so changes require a session restart; a failing hook never blocks the agent).
Rovo Dev executes hook commands via the shell (/bin/sh -c) and delivers the event payload as JSON on stdin; hook exit codes are semantic (a hook can block the agent). Verified against the CLI itself — the vendor docs' map-keyed eventHooks.events shape is wrong and is rejected as corrupt config; real configs use a list of {name, commands: [{command}]} items. See the codeassembly KB: "Rovo Dev event-hooks config schema and execution semantics".
Claude Code interprets some non-zero hook exits as control signals (a Stop hook exiting 2 blocks the agent from stopping), so the relay's never-block contract means unconditionally exiting 0.
Proposed solution
One relay helper serving both harnesses, installed into each harness's scripts directory: read the hook payload from stdin, map {harness, hook name} to an event type via a static table, resolve repo and branch attribution against the payload's cwd, and append the event with the payload's session id.
Event
Claude Code
Rovo Dev
session.started
SessionStart
on_session_start
session.ended
SessionEnd
on_session_end
turn.started
UserPromptSubmit
on_user_prompt
turn.completed
Stop
on_complete
Waiting-on-user is derived state (latest event is turn.completed), not an event type. Start/end payload discriminators (Claude's source/reason, Rovo's switch/fork/exit) pass through in event payloads rather than minting distinct types.
Only these four hooks are relayed — not Notification or the tool-level hooks: tool events flood the log with detail the lane view does not render, and Notification overlaps the waiting signal Stop already provides. Distribution is CLI-based config injection, not a Claude Code plugin — a plugin cannot cover Rovo Dev.
Hook configuration is a discrete CLI step (configure-hooks) that install invokes by default — decoupling it later is a one-line removal. It injects the entries via the #1007/#1008 utilities, supports --skip-hooks on install, and offers configure-hooks --print emitting snippets for externally managed configs; touching the Rovo config prints its restart reminder. status reports each harness's hook entries as present, drifted, or absent via the same catalog, giving the check utilities their consumer. Ownership rides an inert --sentinel argument the relay accepts and ignores — not a shell comment, so it survives any execution semantics. Hooks carry the session-lifecycle family; skills keep the work-narration family (skill.*, artifact.written, pr.created) — two complementary channels, not a replacement.
Acceptance criteria
Must have
A session is visible in the lane view from session start, and ending it (exit or session switch) marks it ended, on both harnesses.
Turn boundaries are relayed on both harnesses: prompt submission emits turn.started; response completion emits turn.completed.
Relayed envelopes carry correct session, repo, and branch attribution.
A hook-relay failure never blocks or degrades the session it observes; the relay always exits 0.
status reports each harness's hook entries as present, drifted, or absent.
session.started, session.ended, turn.started, turn.completed join the declared vocabulary (no warnings on emit).
Hook configuration for both harnesses is documented: manual-adoption snippets matching the print mode's output, Rovo's restart requirement, and the new CLI surface.
New behavior is covered by tests.
Should have
Session-start/-end payload discriminators (source/reason, including fork and switch) pass through in event payloads.
Problem
The event channel carries no session-lifecycle signal. An ended session persists in the lane view as "idle" indefinitely, a session is invisible until its first instrumented skill emits, and the waiting-on-user state rides the least reliable skill emission point (end of turn). Session end has no skill emission point at all — ending is not a skill moment — and activity-based inference is ruled out: sessions legitimately sit idle for days.
Context
session_idandcwd. Confirmed inventory: Claude CodeSessionStart,SessionEnd,UserPromptSubmit,Stop; Rovo Devon_session_start,on_session_end,on_user_prompt,on_complete(configured undereventHooksin~/.rovodev/config.yml; config is read at startup, so changes require a session restart; a failing hook never blocks the agent)./bin/sh -c) and delivers the event payload as JSON on stdin; hook exit codes are semantic (a hook can block the agent). Verified against the CLI itself — the vendor docs' map-keyedeventHooks.eventsshape is wrong and is rejected as corrupt config; real configs use a list of{name, commands: [{command}]}items. See thecodeassemblyKB: "Rovo Dev event-hooks config schema and execution semantics".settings.json) and Add a managed event-hook utility for Rovo Dev config.yml #1008 (Rovoconfig.yml) provide sentinel-based ensure/check/remove utilities; this ticket supplies the actual entries and wiring, and reworks Add a managed event-hook utility for Rovo Dev config.yml #1008's utility to the verified list schema (it shipped modeling the map shape Rovo rejects).Stophook exiting 2 blocks the agent from stopping), so the relay's never-block contract means unconditionally exiting 0.Proposed solution
One relay helper serving both harnesses, installed into each harness's scripts directory: read the hook payload from stdin, map
{harness, hook name}to an event type via a static table, resolve repo and branch attribution against the payload'scwd, and append the event with the payload's session id.session.startedSessionStarton_session_startsession.endedSessionEndon_session_endturn.startedUserPromptSubmiton_user_promptturn.completedStopon_completeWaiting-on-user is derived state (latest event is
turn.completed), not an event type. Start/end payload discriminators (Claude'ssource/reason, Rovo's switch/fork/exit) pass through in event payloads rather than minting distinct types.Only these four hooks are relayed — not
Notificationor the tool-level hooks: tool events flood the log with detail the lane view does not render, andNotificationoverlaps the waiting signalStopalready provides. Distribution is CLI-based config injection, not a Claude Code plugin — a plugin cannot cover Rovo Dev.Hook configuration is a discrete CLI step (
configure-hooks) thatinstallinvokes by default — decoupling it later is a one-line removal. It injects the entries via the #1007/#1008 utilities, supports--skip-hooksoninstall, and offersconfigure-hooks --printemitting snippets for externally managed configs; touching the Rovo config prints its restart reminder.statusreports each harness's hook entries as present, drifted, or absent via the same catalog, giving the check utilities their consumer. Ownership rides an inert--sentinelargument the relay accepts and ignores — not a shell comment, so it survives any execution semantics. Hooks carry the session-lifecycle family; skills keep the work-narration family (skill.*,artifact.written,pr.created) — two complementary channels, not a replacement.Acceptance criteria
Must have
turn.started; response completion emitsturn.completed.install, with an opt-out and a print mode, touching only sentinel-marked entries (via Add a managed hook-entry utility for Claude Code settings.json #1007/Add a managed event-hook utility for Rovo Dev config.yml #1008).statusreports each harness's hook entries as present, drifted, or absent.session.started,session.ended,turn.started,turn.completedjoin the declared vocabulary (no warnings on emit).Should have