Hooks and sirioctl notify
How an agent tells Sirio it is running, waiting or done, and where the hooks that tell it come from.
sirioctl notify is the command agents call to report their state. A hook runs it from inside the agent’s terminal, and Sirio takes the call as the strongest evidence of what the agent is doing; see Activity states. A chat needs no hooks, since Sirio drives its agent directly.
The call
sirioctl notify --session "$SIRIO_PANE_ID" --status running
sirioctl notify --session "$SIRIO_PANE_ID" --status needs-input
sirioctl notify --session "$SIRIO_PANE_ID" --status done--status accepts running, needs-input, done and error. --session names the pane and defaults to $SIRIO_PANE_ID, which every Sirio terminal exports. With neither, outside a Sirio terminal, the command does nothing and exits cleanly, so a hook in your own configuration stays quiet when you run the agent anywhere else.
With --title, the same command posts a desktop notification instead:
sirioctl notify --title "Tests finished" --body "All 212 passed"It takes --title, and optionally --subtitle and --body. sirioctl refuses a call that mixes --title with --session, --status, --agent-session or --stdin-json, because it cannot tell which of the two you meant. On macOS the notification comes from Sirio itself once you allow notifications in Settings → Permissions, through Script Editor until then, and not at all if you deny them; Tray, notifications and persistence has the other platforms.
Install Hooks
Settings → General → Agent Hooks → Install Hooks adds Sirio’s hooks to each agent’s user-level configuration, for agents you start yourself in a Sirio terminal. The card then lists each agent with the file it wrote:
- Claude Code:
settings.jsonin~/.claude, or in$CLAUDE_CONFIG_DIR.SessionStart,StopandNotificationreportneeds-input,UserPromptSubmitreportsrunning, andSessionEndreportsdone. Sirio replaces those five hook lists and keeps every other key in the file, and it writes a fresh file over one that does not parse as a JSON object. - Codex: the
notifykey inconfig.tomlunder~/.codex, or$CODEX_HOME, which reportsneeds-input. The rest of the file keeps its comments and its order, and a file that no longer parses stays as it is while the card reports the failure. - OpenCode: a plugin,
sirio-session.js, in thepluginsfolder of OpenCode’s config directory (~/.config/opencodeunless$OPENCODE_CONFIG_DIRor$XDG_CONFIG_HOMEmoves it). It tells Sirio the OpenCode session id throughsirioctl session-refand reports no state. - Pi and Oh-My-Pi: nothing. Pi has no hooks, and Oh-My-Pi reads a hook file only from its command line.
These hooks name no pane. sirioctl takes the pane from SIRIO_PANE_ID, so one file serves every Sirio terminal and does nothing outside one.
Hooks Sirio writes on launch
When Sirio starts an agent’s CLI in a terminal itself, the adapter writes hooks that name the pane outright, inside the worktree or on the command line. The five adapters says when that happens.
- Claude Code:
.claude/settings.local.json, with the same five hooks. - Codex: a
-c notify=[…]command-line override. Sirio writes the JSON inside it without escaped slashes, because Codex parses the override as TOML. - Oh-My-Pi:
.sirio/omp-hook.ts, which Sirio passes with--hook. It reportsrunningwhen a session or a turn starts,needs-inputwhen a turn ends anddonewhen the session shuts down. - OpenCode:
.opencode/plugin/sirio-session.js, the same session-id plugin, which names the pane.
Pi gets nothing. Sirio reads OpenCode’s state from its terminal title and its process, and Pi’s from its title.
Turning it off
Turning off the control socket in Settings → General leaves the hooks nothing to reach, so agents fall back to their title, their screen and their process.