CLI Reference

The binary is agentmonitors ("Durable observation and inbox delivery for AI agents"). This page is a quick-scan reference card — synopsis, key flags, and a runnable example per command. It is not the contract: for full behavior, exit codes, and JSON shapes see spec 005 — CLI Reference (this page was built from that spec's current revision). New to the CLI? Start with Getting Started.

Every command also has its own --help, which always reflects the installed version:

agentmonitors <command> --help

Output formats (--format)

Structured-output commands (events list, scan, monitor history, monitor explain, and source list) support three values:

ValueDescription
toonCompact TOON encoding, optimized for agent context windows.
jsonJSON.stringify(value, null, 2) — stable, byte-for-byte unchanged for existing JSON consumers.
textHuman-readable columnar/plain text for interactive terminal use.

When --format is omitted on those commands, the CLI auto-detects: an agentic TUI (Claude Code, Cursor, Gemini CLI, etc.) gets toon; an interactive human terminal gets text. An explicit --format always wins. Commands with a fixed text/json pair (no toon) default to text unless noted otherwise below.

Transport: in-process vs. daemon socket

Some commands run entirely in-process against the filesystem and/or local SQLite database (init, validate, scan, monitor test, source list, schema generate, inbox *, daemon once, doctor). Others round-trip the daemon over a Unix domain socket (daemon run/status/stop, session *, events *, hook *). monitor history and monitor explain are socket-first but fall back to reading persisted state in-process when no daemon is reachable. Socket resolution for every --socket-accepting command is: --socket flag → AGENTMONITORS_SOCKET env var → the global default (~/.local/share/agentmonitors/agentmonitors.sock). The session-lifecycle commands (session start/end) additionally use the enabled workspace's persisted socket from .claude/agentmonitors.local.md as their effective override, so hook-driven sessions and manual commands can target the same daemon. See Troubleshooting ("Which session ID do I use") for the related session-id distinction.


init — bootstrap the project, or scaffold a monitor

agentmonitors init [name] [options]

With no [name], init runs the bootstrap form: enables the project, fixes .gitignore, optionally scaffolds a first monitor, validates it, and prints next steps. With [name], it runs the scaffold form: creates one MONITOR.md.

FlagDefaultDescription
[name]Monitor name (kebab-case). Omit to bootstrap the whole project instead.
--dir <dir>.claude/monitorsBase directory for monitors
--type <type>file-fingerprintfile-fingerprint, api-poll, command-poll, schedule, incoming-changes
--enable-onlyBootstrap only: enable the project and fix .gitignore, then stop
--yesBootstrap non-interactively: accept defaults, scaffold a starter monitor

No --format flag — output is always human-readable text.

agentmonitors init --yes           # one-shot project bootstrap, no prompts
agentmonitors init my-monitor      # scaffold a single file-fingerprint monitor

validate — validate MONITOR.md files

agentmonitors validate [path] [options]
FlagDefaultDescription
[path].claude/monitorsDirectory to validate
--format <format>texttext, json
agentmonitors validate .claude/monitors --format json

Checks every monitor's watch config against its source's full JSON Schema and rejects duplicate monitor IDs. Exits 1 if any monitor is invalid.

scan — discover and summarize monitors

agentmonitors scan [dir] [options]
FlagDefaultDescription
[dir].claude/monitorsDirectory to scan
--format <format>auto-detecttoon, json, text
agentmonitors scan .claude/monitors

Discovery only — never validates. Exits 0 on any scan result (including zero monitors); argument errors (missing directory, path is a file) exit non-zero.


inbox — manage inbox items

The legacy inbox state machine (queued → acked → in-progress → completed|failed → archived). All subcommands are in-process. See 002-runtime-delivery.md §12 for how this relates to the primary monitor-events pipeline.

inbox list

agentmonitors inbox list [options]
FlagDefaultDescription
--state <state>queued, acked, in-progress, completed, failed, archived
--urgency <urgency>low, normal, high
--tags <tags>Comma-separated tag filter
--monitor <id>Filter by monitor ID
--since <date>ISO 8601; items created after this date
--until <date>ISO 8601; items created before this date
--format <format>texttext, json
agentmonitors inbox list --state queued --format json

inbox ack / start / complete / fail / archive

agentmonitors inbox ack <id>
agentmonitors inbox start <id>
agentmonitors inbox complete <id>
agentmonitors inbox fail <id> [--error <message>]
agentmonitors inbox archive <id>

State-transition commands. No --format flag — always plain text (Acknowledged: <id>, etc.); errors go to stderr and exit 1.

agentmonitors inbox ack itm_01hz3k9x2p

monitor — test and diagnose a single monitor

monitor test — dry-run an observation source

agentmonitors monitor test <path> [options]
FlagDefaultDescription
<path>Path to a single MONITOR.md file
--format <format>texttext, json
agentmonitors monitor test .claude/monitors/watch-src/MONITOR.md

Runs a live observation cycle without writing to the database. For stateful sources, automatically runs a second observation after 100 ms to demonstrate change detection. In-process, no daemon required.

monitor history — observation audit trail

agentmonitors monitor history [monitorId] [--socket <path>] [--limit <n>] [--format <toon|text|json>]
FlagDefaultDescription
[monitorId]Filter to a single monitor id
--limit <n>50Maximum rows (newest first)
--formatauto-detecttoon, text, json
agentmonitors monitor history watch-src --limit 10

Each row reports one of triggered, suppressed, no-change, no-files-matched, errored, or rebaselined. Socket-first with an in-process fallback to persisted state when no daemon is reachable — the text output is prefixed with a "No daemon running" banner in that case.

monitor explain — pipeline diagnosis

agentmonitors monitor explain <monitorId> [--dir <path>] [--workspace <path>] [--socket <path>] [--history-limit <n>] [--event-limit <n>] [--format <toon|text|json>]
FlagDefaultDescription
<monitorId>Monitor id to diagnose
--dir <path>.claude/monitorsDirectory containing monitor definitions
--workspace <path>current working dirWorkspace path used for session projection
--history-limit <n>10Observation history rows included
--event-limit <n>10Materialized event rows included
--formatauto-detecttoon, text, json
agentmonitors monitor explain watch-src --format text

Answers "why didn't my monitor fire?" by walking six pipeline stages (definition → scheduling → observation → notify → materialization → delivery) and naming the one where the signal actually stopped. See Troubleshooting ("My monitor never fires") for a worked example. Socket-first with the same no-daemon in-process fallback as monitor history.


source — manage observation source plugins

source list

agentmonitors source list [--format <format>]
FlagDefaultDescription
--format <format>auto-detecttoon, json, text
agentmonitors source list --format json

Lists the sources registered by registerCoreSources(): file-fingerprint, api-poll, command-poll, schedule, incoming-changes.

source search / install / update / remove — not yet implemented

agentmonitors source search [query]
agentmonitors source install <name>
agentmonitors source update [name]
agentmonitors source remove <name>

These are placeholders: each prints a [not yet implemented] message to stderr and exits 1. source search and source install additionally name the manual workaround (pnpm add --prefix ~/.config/agentmonitors <package-name>); update and remove do not.


schema — JSON Schema management

schema generate

agentmonitors schema generate [-o <file>]
FlagDefaultDescription
-o, --output <file>Write schema to file; omit to print to stdout
agentmonitors schema generate -o monitor.schema.json

Generates a combined JSON Schema from every registered source, pretty-printed. No --format flag.


daemon — runtime loop management

daemon once — single in-process tick

agentmonitors daemon once [monitorsDir] [options]
FlagDefaultDescription
[monitorsDir].claude/monitorsDirectory containing MONITOR.md files
--workspace <path>process.cwd()Workspace path for session projection
--format <format>texttext, json
agentmonitors daemon once .claude/monitors

Runs createRuntime().tick() directly — no socket is contacted, even though it lives under daemon. Useful in CI or scripts where a long-running daemon isn't wanted.

daemon run — continuous loop

agentmonitors daemon run [monitorsDir] [options]
FlagDefaultDescription
[monitorsDir].claude/monitorsDirectory containing MONITOR.md files
--workspace <path>process.cwd()Workspace path for session projection
--poll-ms <ms>30000Loop-wake cadence; per-monitor observation is still gated by its own schedule
--socket <path>resolved defaultUnix domain socket path
--reap-after-ms <ms>300000Stop after this many ms with no active sessions; 0 disables idle reaping
agentmonitors daemon run --poll-ms 5000

Starts a Unix socket server and polls runtime.tick(). Refuses to start if another daemon is already listening on the resolved socket. SIGINT/SIGTERM trigger a graceful stop.

daemon status

agentmonitors daemon status [options]
FlagDefaultDescription
--socket <path>resolved defaultUnix domain socket path
--format <format>texttext, json
agentmonitors daemon status --format json

Queries via the socket when reachable; otherwise falls back to reading the local database in-process.

daemon stop

agentmonitors daemon stop [--socket <path>]
agentmonitors daemon stop

Sends a stop message over the socket. No --format flag.


doctor — unified workspace health check

agentmonitors doctor [--dir <path>] [--workspace <path>] [--socket <path>] [--format <text|json>]
FlagDefaultDescription
--dir <path><workspace>/.claude/monitorsDirectory containing monitor definitions
--workspace <path>current working dirWorkspace to diagnose
--socket <path>resolved defaultOnly used for the daemon-reachable ping
--format <format>texttext, json
agentmonitors doctor --format json

Answers "is my monitoring working, and if not, where?" in one command: project-enabled monitors-directorymonitors-validdaemon-reachablelead-session → one monitor:<id> rollup line per discovered monitor. Diagnoses only — never mutates state, and never needs a running daemon (it reads the persisted store directly; the socket is used only for the reachability ping). Exits 0 only when every check passes.


session — manage agent sessions

All subcommands route through the daemon socket except start/end, which lazy-boot the daemon.

session open

agentmonitors session open --host-session-id <id> [options]
FlagDefaultDescription
--host-session-id <id>requiredHost session id from the integrating runtime
--workspace <path>process.cwd()Workspace path for the session
--socket <path>resolved defaultUnix domain socket path
--agent-identity <id>Explicit AgentMon agent identity
--hook-state-path <path>Override hook-state file path
--role <role>leadlead, subagent
--format <format>texttext, json, id
agentmonitors session open --host-session-id claude-abc123

--format id prints just the bare session id — no JSON parsing needed to pull it out of a verification script.

session close

agentmonitors session close <sessionId> [options]
agentmonitors session close 01hz3k9x2pabcdefg

session list

agentmonitors session list [options]
agentmonitors session list --format text

session start — lazy-boot daemon and register session

agentmonitors session start

No flags. Designed to run as a Claude Code SessionStart hook: reads its context from the hook JSON payload on stdin (session_id, cwd) — there is no CLAUDE_CODE_SESSION_ID environment variable. Boots the daemon if none is listening, opens a session, and — on a compact-resume with unread events — emits the recap SessionStart hook JSON.

printf '{"session_id":"claude-abc123","cwd":"%s","hook_event_name":"SessionStart"}' "$PWD" \
  | agentmonitors session start

session end — deregister session

agentmonitors session end

No flags; same stdin hook payload as session start. Designed as a SessionEnd hook (hook_event_name: "SessionEnd").

printf '{"session_id":"claude-abc123","cwd":"%s"}' "$PWD" | agentmonitors session end

events — query or acknowledge runtime events

events list

agentmonitors events list --session <id> [options]
FlagDefaultDescription
--session <id>requiredAgentMon session id
--socket <path>resolved defaultUnix domain socket path
--monitor <id>Filter by monitor id
--urgency <urgency>low, normal, high
--tag <tag>[]Repeatable — --tag foo --tag bar
--scope <pairs>key=value,key2=value2
--unreadOnly unread events
--since-baselineOnly events since the session baseline
--format <format>auto-detecttoon, json, text
agentmonitors events list --session 01hz3k9x2pabcdefg --unread

events ack

agentmonitors events ack --session <id> [options]
FlagDefaultDescription
--session <id>requiredAgentMon session id
--socket <path>resolved defaultUnix domain socket path
--event-ids <ids>Comma-separated event ids; omit to ack all unread
agentmonitors events ack --session 01hz3k9x2pabcdefg

No --format flag — errors always go to stderr.

Omitting --event-ids acknowledges every unread event for the session except any still leased by in-flight delivery pushes (for example, channel messages that are still being surfaced) — those rows are left unread so they can still be redelivered, and each becomes eligible for a future no---event-ids ack once its push resolves.


hook — claim hook-delivery payloads

hook claim

agentmonitors hook claim --session <id> --lifecycle <lifecycle> [options]
FlagDefaultDescription
--session <id>requiredAgentMon session id
--lifecycle <lifecycle>requiredturn-interruptible, turn-idle, post-compact
--socket <path>resolved defaultUnix domain socket path
--format <format>jsontext, json — the only command whose default is json
agentmonitors hook claim --session 01hz3k9x2pabcdefg --lifecycle turn-interruptible

hook deliver

agentmonitors hook deliver [--lifecycle <lifecycle>] [--format <format>] [--socket <path>] [--debug]
FlagDefaultDescription
--lifecycle <lifecycle>derived from payloadOptional override: turn-interruptible, turn-idle, post-compact
--format <format>hook wire JSONjson emits compact Claude Code hook JSON; text emits only additionalContext
--socket <path>from .local.mdOverride daemon socket path
--debugfalseWrite a step-by-step diagnosis to stderr; stdout is byte-identical to a non---debug run
printf '{"session_id":"claude-abc123","cwd":"%s","hook_event_name":"UserPromptSubmit"}' "$PWD" \
  | agentmonitors hook deliver

Designed to run as a Claude Code lifecycle hook. Reads the hook payload as JSON on stdin (never env vars). Always exits 0 — an internal error is swallowed rather than blocking the agent's turn. See Troubleshooting ("It fired but my agent wasn't told") for how to interpret its output.

Diagnosing empty output: run the same payload with --debug appended. Empty stdout + exit 0 means either nothing is pending or the invocation is misconfigured — indistinguishable without --debug, which writes the difference to stderr (session resolution, workspace/socket state, pending-event counts by urgency, and why anything isn't deliverable yet: settle-window, already-claimed, coalesced-until-ack, or deferred-by-cap). Stdout never changes:

printf '{"session_id":"claude-abc123","cwd":"%s","hook_event_name":"UserPromptSubmit"}' "$PWD" \
  | agentmonitors hook deliver --debug

channel — Claude Code channel server

channel serve

agentmonitors channel serve [--socket <path>] [--poll-ms <ms>] [--host-session-id <id>] [--workspace <path>]
FlagDefaultDescription
--socket <path>resolved defaultDaemon Unix domain socket path
--poll-ms <ms>3000Delivery poll interval in milliseconds
--host-session-id <id>$CLAUDE_CODE_SESSION_IDHost session id
--workspace <path>$CLAUDE_PROJECT_DIRWorkspace path
agentmonitors channel serve

Runs AgentMon as an MCP server over stdio, pushing pending turn-interruptible deliveries into the session and exposing an agentmon_ack tool. No --format flag — the stdio channel is the transport; stdout carries only the MCP JSON-RPC frames (no human-readable output). Intended to be spawned by Claude Code via a channel plugin, not run by hand. See Agent integration & delivery for the hooks-only vs. MCP tradeoffs.


Planned: agent-facing verbs (not yet shipped)

Spec 005 §14 defines five read-only/declaration-only verbs — snapshot, diff, summary, watch, inspect — that let an agent pull a stored snapshot, diff two points in time, get a cheap orientation summary, declare an ephemeral session-scoped monitor, or inspect received/pending/armed signal state, all without an extra source observation. None of these exist in the CLI today — the commands above are the complete, currently-installed surface. See 005-cli-reference.md §14 and spec 007 for the full target contract.


Exit codes

ConditionExit codeOutput target
Success0
Validation/argument error1stderr (text) or stdout ({ "error": "..." } in JSON)
Daemon socket unavailable / timeout1stderr
Unknown source / parse failure1stderr or JSON error
Placeholder command invoked1stderr

hook deliver is the one exception — it always exits 0 so a delivery-check failure can never block a Claude Code tool call. All other commands set process.exitCode = 1 rather than calling process.exit(1), so in-flight async work and cleanup handlers still complete. The daemon socket timeout is 2000 ms (callDaemon()); the reachability ping (doctor's daemon-reachable check, daemon status) uses 500 ms.

Next steps