Pre-release Harn is pre-1.0 — the language, standard library, and CLI may change between releases. See the release notes

Deliver signals to Claude Code and Codex

This guide connects running Claude Code and Codex sessions to the local signals inbox, so a signal fired on this machine reaches the session working on it. For how routing and delivery work, see Ambient signals. For every flag and file, see the signals reference.

You need harn on the PATH that the harness uses to run hooks.

Connect Claude Code#

Add the hooks to ~/.claude/settings.json so every session on the machine checks in. Merge them into any hooks you already have:

{
  "hooks": {
    "SessionStart": [
      {"hooks": [{"type": "command", "command": "harn signals hook --format claude-code --event SessionStart", "timeout": 10}]}
    ],
    "UserPromptSubmit": [
      {"hooks": [{"type": "command", "command": "harn signals hook --format claude-code --event UserPromptSubmit", "timeout": 10}]}
    ],
    "PostToolUse": [
      {"matcher": "*", "hooks": [{"type": "command", "command": "harn signals hook --format claude-code --event PostToolUse", "timeout": 10}]}
    ],
    "Stop": [
      {"hooks": [
        {"type": "command", "command": "harn signals hook --format claude-code --event Stop", "timeout": 10},
        {"type": "command", "command": "harn signals hook --format claude-code --event Stop --rewake", "asyncRewake": true}
      ]}
    ],
    "SessionEnd": [
      {"hooks": [{"type": "command", "command": "harn signals hook --format claude-code --event SessionEnd"}]}
    ]
  }
}

The second Stop entry is optional. It waits in the background while the session is idle and wakes the session when an urgent signal arrives. The wake carries only a fixed notice; the alert itself arrives as a system reminder through the first Stop entry when the woken turn ends. It waits nine minutes by default, inside the hook's default 600-second timeout. To watch longer, raise both: for example "timeout": 3600 with --max-wait 55m. Only one watcher runs per session, so a session that stops repeatedly does not collect watchers.

Start a new session, then confirm it registered:

harn signals sessions

Connect Codex#

Add the hooks to ~/.codex/hooks.json:

{
  "hooks": {
    "SessionStart": [
      {"hooks": [{"type": "command", "command": "harn signals hook --format codex --event SessionStart", "timeout": 10}]}
    ],
    "UserPromptSubmit": [
      {"hooks": [{"type": "command", "command": "harn signals hook --format codex --event UserPromptSubmit", "timeout": 10}]}
    ],
    "PostToolUse": [
      {"hooks": [{"type": "command", "command": "harn signals hook --format codex --event PostToolUse", "timeout": 10}]}
    ],
    "Stop": [
      {"hooks": [{"type": "command", "command": "harn signals hook --format codex --event Stop", "timeout": 10}]}
    ],
    "SessionEnd": [
      {"hooks": [{"type": "command", "command": "harn signals hook --format codex --event SessionEnd"}]}
    ]
  }
}

Codex asks you to review and trust new hooks before it runs them. Approve them once, then start a new session.

Codex has no hook that can wake an idle session, and its Stop hook can keep a session going only by sending a new user prompt, which an alert must never be. An urgent signal therefore reaches a Codex session at its next prompt or tool call.

Choose a fallback session#

A signal that matches no session's repository or working directory goes to a session registered with the fallback role, control by default. Start the session that should receive those signals with the role set:

HARN_EXT_SIGNALS_ROLE=control claude

Without a fallback session, unmatched signals wait in the inbox until a matching session checks in.

Send a test signal#

From any terminal, fire a signal for a repository a running session is working in:

harn signals fire \
  --key test:hello \
  --summary "Test signal from the terminal" \
  --source-url https://example.com/test \
  --repo OWNER/NAME

The session sees the reminder after its next tool call, and the hook that delivered it acks it. List the signal's delivery:

harn signals list

Resolve the signal to send the matching recovery reminder to the same session:

harn signals resolve test:hello

Hold signals back#

Mute signals, set a minimum severity, or set quiet hours in config.toml in the inbox directory. Every harness reading the inbox follows it:

min_severity = "warning"
muted = ["github.open_prs:*"]

[quiet_hours]
start = "22:00"
end = "07:00"
utc_offset = "-07:00"

During quiet hours only urgent signals route. Held signals wait in the inbox; harn signals list shows each one as held with the reason.

Run the monitor pack#

The monitor pack fires and resolves signals for red default-branch CI, a pull request backlog, offline self-hosted runners, a low GitHub rate limit, and Sentry, Grafana, or Honeycomb alerts. Copy examples/triggers/ambient-signals, set the repositories and thresholds in MONITORS in its lib.harn, export GITHUB_TOKEN, add GitHub App credentials for rate-limit entries, and serve it:

harn orchestrator serve --config path/to/ambient-signals/harn.toml

The GitHub monitors poll every five minutes and need no inbound network access.