CLI Commands
The agentihooks CLI is installed globally via uv tool install --editable . as part of agentihooks init. All subcommands are idempotent.
Table of contents
agentihooks initagentihooks settings-profileagentihooks broadcastagentihooks channelagentihooks refresh-rulesagentihooks sessionsagentihooks mcpagentihooks uninstallagentihooks claudeagentihooks ignoreagentihooks --list-profilesagentihooks bundleagentihooks link-profileagentihooks --queryagentihooks statusagentihooks lint-claudeagentihooks extract-skill- Standalone Python execution
- Exit codes
agentihooks init
The single entry point for installing agentihooks. Handles global setup and bundle linking.
agentihooks init [--bundle <path>] [--profile <name>]
What it does
- Links bundle directory (if
--bundleis provided) - Merges settings:
_base/settings.base.json-> profile.claude/settings.overrides.json - Substitutes
/app-> real repo path and__PYTHON__-> venv Python in all commands - Preserves personal keys (
model,autoUpdatesChannel,skipDangerousModePermissionPrompt) from any pre-existing unmanaged settings - Writes
~/.claude/settings.jsonwith hook wiring and tool permissions - Symlinks skills, agents, commands, and rules via 3-layer merge (agentihooks built-in -> bundle global -> each profile in chain)
- Writes
~/.claude/CLAUDE.md– single profile: file copy; chained profiles: concatenated with---separators and<!-- profile: name -->markers - Installs MCPs (hooks-utils + bundle
.claude/.mcp.json+ profile.claude/.mcp.json) - Installs the
agentihooksCLI globally viauv tool install --editable . - Writes managed bashrc block (
agentienvfunction +agentialias)
Step 8 has one extra behaviour when MCP_TRANSPORT names a network transport: it renders the systemd unit and starts the hooks-utils daemon, restarting it unconditionally. Reverting to stdio stops the daemon and removes the unit, so a downgrade cannot leave a process serving a port nothing points at. See agentihooks mcp and MCP Transport.
Per-repo init (
--repo/--local/.agentihooks.json) was removed 2026-05-07.agentihooks initis global-only.
Flags
| Flag | Description |
|---|---|
--bundle <path> | Path to bundle directory. First-time: links the bundle and runs global install. |
--profile <name> | Profile to install. Comma-separated for chaining: --profile coding,anton (default: default, env: AGENTIHOOKS_PROFILE) |
--force | Clean install — resets install state (state.json, sync hashes, session caches, PID files, prod_bypass/, controls_flags/, voice_flags/, force_refresh/) and re-symlinks ~/.claude/ assets. Preserves broadcasts, enforcements, brain data, logs, quota accounts, .env, .venv. |
Environment variables
| Variable | Description |
|---|---|
AGENTIHOOKS_PROFILE | Default profile when --profile is not passed (default: default) |
AGENTIHOOKS_SETTINGS_PROFILE | Default settings-only overlay profile (default: none) |
AGENTIHOOKS_MCP_FILE | Path to an MCP JSON file to auto-merge into ~/.claude.json during install |
CLAUDE_CODE_HOME_DIR | Home-directory root override – .claude is appended automatically (default: $HOME) |
AGENTIHOOKS_CLAUDE_HOME | Legacy: direct path to the .claude directory (default: ~/.claude) |
AGENTIHOOKS_HOME | Override the agentihooks state directory (default: ~/.agentihooks). Used for per-pod isolation on shared filesystems — set to /shared/.agentihooks-<pod-name> so each pod gets its own state without racing on state.json. |
AGENTIHOOKS_MCP_TRANSPORT | One-off override of MCP_TRANSPORT for a single init, without editing .env. |
AGENTIHOOKS_MCP_SUPERVISOR | auto (default), systemd, or pidfile. Forces the daemon backend instead of probing for a systemd user bus. |
Examples
# First-time install with bundle
agentihooks init --bundle ~/dev/my-tools --profile coding
# Re-run global install (uses linked bundle)
agentihooks init
# Install with a different profile
agentihooks init --profile admin
# Clean install (fresh state, preserves .env)
agentihooks init --force --profile coding
# Install with persona + settings overlay
agentihooks init --profile anton --settings-profile admin
# Quick-switch settings layer only (keeps persona intact)
agentihooks settings-profile admin
# Revert settings to persona defaults
agentihooks settings-profile --clear
# Same, using the environment variable
AGENTIHOOKS_PROFILE=coding agentihooks init
# Auto-merge a gateway MCP file during install
AGENTIHOOKS_MCP_FILE=/shared/gateway-mcp.json agentihooks init
agentihooks settings-profile
Quick-switch the settings layer without touching persona (rules, CLAUDE.md, skills, agents, commands).
agentihooks settings-profile [NAME] [--clear]
| Argument / Flag | Description |
|---|---|
NAME | Settings profile to apply. Only its settings.overrides.json and .mcp.json are used. |
--clear | Remove the settings overlay and revert to persona profile defaults. |
With no arguments, shows the current persona and settings profile.
Environment variable
export AGENTIHOOKS_SETTINGS_PROFILE=admin
agentihooks init --profile anton # automatically uses admin settings overlay
Examples
# Show current state
agentihooks settings-profile
# Switch to admin settings (keeps anton persona)
agentihooks settings-profile admin
# Revert to persona defaults
agentihooks settings-profile --clear
agentihooks broadcast
Send a message to all active Claude Code sessions simultaneously.
agentihooks broadcast [OPTIONS] MESSAGE
| Flag | Default | Description |
|---|---|---|
-s, --severity | alert | critical, alert, or info |
-t, --ttl | per severity | Time-to-live: 5m, 30m, 1h, 8h, 24h |
--persistent | per severity | Re-inject on every hook event until TTL expires |
--source | operator | Source tag: operator, system, cron, api |
--list | Show all active broadcasts | |
--clear [ID] | Clear all broadcasts, or a specific one by ID |
Severity behavior
| Severity | Injection | Default TTL | Persistent |
|---|---|---|---|
critical | Every turn + every tool call | 30 min | Yes |
alert | Every turn | 1 hour | Yes |
info | Once per session | 4 hours | No |
agentihooks broadcast emit
AI-assisted broadcast composition. Describe the message in natural language and Haiku selects the appropriate severity, TTL, and wording.
agentihooks broadcast emit NATURAL_LANGUAGE_DESCRIPTION
The subcommand sends the description to Claude Haiku, which returns a structured broadcast (severity, TTL, message text) and immediately posts it.
# Haiku picks severity=critical, TTL=30m
agentihooks broadcast emit "prod API is returning 500s, stop all deploys immediately"
# Haiku picks severity=alert, TTL=8h
agentihooks broadcast emit "deploy freeze tonight until the on-call engineer clears it"
# Haiku picks severity=info, TTL=4h
agentihooks broadcast emit "sonarqube is down for maintenance"
Examples
# Emergency (manual)
agentihooks broadcast -s critical "Production incident — do NOT deploy"
# Deploy freeze (manual)
agentihooks broadcast -s alert -t 8h "Deploy freeze until 6am"
# Info (manual)
agentihooks broadcast -s info "SonarQube is down"
# AI-assisted emit
agentihooks broadcast emit "prod database is read-only until the migration completes"
# List / clear
agentihooks broadcast --list
agentihooks broadcast --clear
agentihooks channel
Channel-scoped broadcast publishing and inspection. A session only receives a channel-tagged message if its subscription list (from AGENTIHOOKS_BASE_CHANNELS) includes that channel. Global broadcasts (no channel) reach everyone.
Subcommands
agentihooks channel publish CHANNEL MESSAGE [-s SEVERITY] [-t TTL]
agentihooks channel list
| Subcommand | Purpose |
|---|---|
publish | Publish a message to a named channel. Same severity tiers as broadcast (info / alert / critical). |
list | Show active channels in ~/.agentihooks/broadcast.json with message counts per channel. |
Subscriptions live in settings.json, not in CLI
There is intentionally no channel subscribe or channel unsubscribe subcommand. Subscriptions are operator-configured via the AGENTIHOOKS_BASE_CHANNELS env var, set in the profile’s settings.overrides.json env block (or per-repo via .claude/settings.local.json, or per-container via launch ENV). See Broadcast System → Channel Subscriptions.
Examples
# Tagged broadcast — only sessions subscribed to "deploy" see it
agentihooks channel publish deploy "Image roll-out paused on cluster-west" -s alert -t 1h
# Knowledge / brain content (the brain adapter publishes here automatically)
agentihooks channel publish brain "Hot arcs updated: 3 active" -s info -t 4h
# Inspect what's flowing
agentihooks channel list
agentihooks refresh-rules
Push profile rule updates into every running Claude Code session without a restart. Each target session consumes the refresh once on its next UserPromptSubmit.
agentihooks refresh-rules [--profile <name>] [--dry-run] [--clear]
How it works
- Reads the installed rules:
~/.claude/CLAUDE.mdand every~/.claude/rules/*.md. - Takes a snapshot of currently-alive session IDs from the broadcast registry.
- Writes
~/.agentihooks/force_refresh/rules-<profile>.jsoncontaining the payload + pending session list. - On each targeted session’s next
UserPromptSubmit, the hook injects the payload and removes the session from pending. - When pending drains → marker deleted. Otherwise marker auto-GCs after 24h.
Sessions started AFTER the push never see the marker — they get fresh rules at SessionStart, so re-injection would be redundant.
Flags
| Flag | Description |
|---|---|
--profile <name> | Profile name (default: detected from the ~/.claude/CLAUDE.md symlink target) |
--dry-run | Print what would be pushed (profile, content hash, payload size, target session IDs) without writing the marker |
--clear | Delete any existing pending marker for the profile (cancel a push in progress) |
Examples
# Preview which sessions would be hit
agentihooks refresh-rules --dry-run
# Push the current rules to all alive sessions
agentihooks refresh-rules
# Cancel a pending marker without waiting for TTL
agentihooks refresh-rules --clear
agentihooks sessions
Crash-recovery session picker. Lists recent Claude Code sessions (24h window) with names, lifetimes, and IDs. Reopen a session by index from the list.

agentihooks sessions list [--hours N] [--limit N]
agentihooks sessions reopen <IDX> [--force]
agentihooks sessions backfill [--hours N]
Columns
| Column | Meaning |
|---|---|
IDX | Index to pass to reopen |
STATUS | alive / closed / dead / superseded |
AGE | For alive: session lifetime (time since started_at). For others: time since last activity. |
NAME | Session title from Claude Code /rename or --name flag, or first user message snippet |
CWD | Working directory (home-relative, truncated if long) |
ID | Session UUID |
Subcommands
list(aliasls) — show recent sessions. Default: 10 most recent in the last 24h.--hourscontrols the lookback window;--limit 0shows all.reopen <IDX>(aliasopen) — relaunch Claude Code resuming the selected session. Uses Windows Terminal on WSL when available.backfill— seed the registry from~/.claude/projects/*.jsonlfor sessions that started before agentihooks was installed.reconcile— health-check the registry.
Sort behavior
Alive sessions appear first (longest-running on top), followed by closed, dead, and superseded. Supersede is used for session IDs that were cycled by /resume or /clear within the same PID — they’re kept for audit but can’t be reopened.
agentihooks mcp
Two unrelated jobs behind one word: a surface-area report, and the hooks-utils daemon’s lifecycle.
agentihooks mcp report [--project PATH] # tool/token surface across every configured server
agentihooks mcp status # daemon: configured vs. actually running
agentihooks mcp start
agentihooks mcp restart
agentihooks mcp stop
The daemon subcommands
These do nothing under stdio, which is the default — Claude Code spawns hooks-utils per session and there is no daemon. They exist for the network transports; see MCP Transport.
agentihooks init starts the daemon itself, so start is only needed after a reboot on a machine with no systemd user session, where the fallback backend has no supervisor behind it.
status and its exit codes
status is the one worth knowing. It prints the configured transport and endpoint, what ~/.claude.json declares, which supervisor is in play, whether the process is up, whether the port answers, and names every mismatch between them.
| Exit | Meaning |
|---|---|
0 | running, and matching config |
1 | stopped |
2 | running, but diverged from config |
The divergence case is why this exists. A daemon started before a config change keeps serving the old transport or port while ~/.claude.json names the new one, and nothing else reports it — the only symptom is tools that quietly fail to appear.
Supervisors
| Backend | Chosen when | Survives reboot |
|---|---|---|
systemd | systemctl --user reaches a user bus | yes |
pidfile | everything else — WSL2 without systemd=true, containers, macOS | no |
AGENTIHOOKS_MCP_SUPERVISOR=systemd\|pidfile forces one. An unrecognised value warns on stderr and falls back to detection.
The pidfile backend records ~/.agentihooks/mcp-daemon.pid and logs to ~/.agentihooks/logs/mcp-daemon.log, rolled to .log.1 past 5 MB.
agentihooks uninstall
Remove everything agentihooks installed from the system.
agentihooks uninstall [--yes]
What gets removed
~/.claude/settings.json– if managed by agentihooks (detected via_managedBymarker)- Skills, agents, commands, and rules symlinks in
~/.claude/– if they target the agentihooks repo ~/.claude/CLAUDE.md– if it points intoprofiles/- MCP servers in
~/.claude.json– from profile.mcp.jsonfiles andstate.json - The hooks-utils daemon – stopped under both backends, and its systemd unit removed. Uninstall verifies afterwards and warns if a process survived, since an orphaned daemon with the CLI gone has nothing left to manage it
- Bashrc block – the
agentienvfunction andagentialias are removed from~/.bashrc agentihooksCLI – viauv tool uninstall agentihooks
What is NOT removed
~/.agentihooks/ (user data: logs, memory, state.json) is left in place. To fully reset:
rm -rf ~/.agentihooks
Flags
| Flag | Description |
|---|---|
--yes | Skip confirmation prompt (for scripting) |
agentihooks claude
Launch Claude Code with --dangerously-skip-permissions and pass through any extra args.
agentihooks claude [extra-args...]
Alias: agenti (installed by agentihooks init in the bashrc block)
How it works
The launcher injects exactly one flag: --dangerously-skip-permissions. Any extra arguments are appended verbatim. Model, effort, and other Claude Code defaults come from ~/.claude/settings.json (rendered from each profile’s settings.overrides.json).
The
claude:block inprofile.ymlwas removed 2026-05-07; profile-level CLI flag mapping no longer exists.
Examples
# Launch
agentihooks claude
# Use the alias
agenti
# Pass extra args to claude
agenti --model haiku --verbose
agentihooks ignore
Create a .claudeignore in the current working directory (or a given path). Claude Code uses .claudeignore to exclude files from reading and indexing – keeping credentials, build artefacts, and binaries out of the context window.
agentihooks ignore [path] [--force]
What it creates
A .claudeignore covering:
| Section | Examples |
|---|---|
| Credentials & secrets | .env, .env.*, *.pem, *.key, secrets/ |
| Build artefacts | __pycache__/, dist/, node_modules/, target/, *.egg-info/ |
| Runtime data | *.log, *.sqlite, *.db, *.lock |
| Test output | .coverage, htmlcov/, junit*.xml |
| IDE / OS noise | .idea/, .vscode/, .DS_Store, Thumbs.db |
| Large binaries / media | archives, images, video, fonts |
| Virtual environments | .venv/, venv/, env/ |
| IaC state | .terraform/, *.tfstate, .terraform.lock.hcl |
.env.example is explicitly un-ignored (!.env.example) so the template remains visible.
Flags
| Flag | Description |
|---|---|
path | Target directory (default: current directory) |
--force | Overwrite an existing .claudeignore |
Examples
# Create in current directory
agentihooks ignore
# Create in a specific project
agentihooks ignore ~/dev/my-project
# Overwrite an existing file with a fresh template
agentihooks ignore --force
agentihooks --list-profiles
Print all available profiles and exit. Shows profiles from both the agentihooks repo and any linked bundle.
agentihooks --list-profiles
agentihooks bundle
Manage the linked bundle directory.
agentihooks bundle <action> [path] [--rebase]
Subcommands
| Subcommand | Description |
|---|---|
link <path> | Link a bundle directory. Stores the path in state.json. |
unlink | Unlink the current bundle. |
list | Show the linked bundle path, linked date, and available profiles. |
pull | Run git pull on the linked bundle directory. |
pull --rebase | Run git pull --rebase on the linked bundle directory. |
Examples
# Link a bundle
agentihooks bundle link ~/dev/my-tools
# Update bundle from remote
agentihooks bundle pull
# Update with rebase
agentihooks bundle pull --rebase
# Show bundle info
agentihooks bundle list
# Unlink
agentihooks bundle unlink
agentihooks link-profile
Link an external directory as a chain-able profile. Where bundle link registers a collection of profiles, link-profile registers a single profile dir at any path on disk and (by default) appends it to the active chain.
agentihooks link-profile link <path> [--name <alias>] [--no-append] [--no-init]
agentihooks link-profile unlink <name> [--no-init]
agentihooks link-profile list
Subcommands
| Subcommand | Description |
|---|---|
link <path> | Register <path> as a linked profile. Default behavior: append the basename to the active global chain and re-run agentihooks init so settings, CLAUDE.md, rules, and MCP all reflect the new chain. |
unlink <name> | Remove the linked profile from the registry, strip it from the active chain, sweep any symlinks pointing into it, and re-install. |
list | Show all linked profiles, their paths, the link date, and which are currently in the chain. Flags missing paths as [MISSING]. |
Flags
| Flag | Effect |
|---|---|
--name <alias> | Use <alias> instead of the directory basename. Required if the basename collides with a built-in or bundle profile (link will refuse otherwise). |
--no-append | Register the path in state.linked_profiles but do not modify the active chain. |
--no-init | Update state but skip the immediate re-install. Operator runs agentihooks init later. |
Examples
# Link an external profile dir → chain becomes anton,brain → install reapplied
agentihooks link-profile link ~/dev/brain-profile
# Link with explicit alias (avoids collision with built-in)
agentihooks link-profile link ~/dev/anton-fork --name anton2
# Register without touching the chain or running install
agentihooks link-profile link ~/dev/brain --no-append --no-init
# Show all linked profiles
agentihooks link-profile list
# Remove from chain and clean up symlinks
agentihooks link-profile unlink brain-profile
State
Linked profiles live in state.json under a linked_profiles array:
"linked_profiles": [
{"name": "brain", "path": "/abs/path/brain", "linked_at": "<iso>"}
]
_resolve_profile_dir consults this array as the third lookup tier (after built-in and bundle), so agentihooks init --profile anton,brain works as soon as brain is registered.
Stale paths
If a linked profile’s directory is later deleted from disk, agentihooks init will WARN-skip it and continue with the surviving chain members. The hint message names the exact unlink command:
[WARN] Linked profile 'brain' path is missing — run 'agentihooks link-profile unlink brain' to clean up. Skipping.
agentihooks --query
Print the currently active profile (or chain) and exit.
agentihooks --query
Single profile output:
anton
Chain output:
chain: [coding, anton]
agentihooks status
Show full system health, MCP fleet inventory with real tool counts, and cost guardrails.
agentihooks status
What it checks
| Check | What it does |
|---|---|
| Profile | Reads state.json for active profile and bundle path |
| Hooks | Parses ~/.claude/settings.json, counts hook event entries (expect 10/10) |
| Python | Extracts the Python binary from hook commands and verifies it runs |
| Redis | Pings Redis, categorizes all agenticore:* keys by type |
| OTEL | Checks if OpenTelemetry hook telemetry is enabled |
| Guardrails | Lists all 8 guardrails with descriptions and enabled/disabled state |
| Broadcast | If BROADCAST_ENABLED=true, reports active session count and pending message count from ~/.agentihooks/broadcast.json. Channel subscriptions aren’t summarised here — they’re visible per-session on statusline Line 3 (read from AGENTIHOOKS_BASE_CHANNELS). |
| MCP | Reads ~/.claude.json for all servers, resolves ${ENV_VAR} auth, queries each HTTP server via MCP protocol for real tool counts, shows fleet total vs active in current project |
MCP fleet introspection
The status checker connects to every HTTP MCP server (even disabled ones) to get real tool counts. Auth tokens are resolved from ${ENV_VAR} references in ~/.claude.json headers using env vars loaded by agentienv. Results are cached at ~/.agentihooks/mcp-tool-cache.json with a 1-hour TTL.
The output shows fleet total (all servers) vs active tools (enabled in current project context). Individual servers can be toggled via the /mcp UI — that state is stored in ~/.claude.json’s projects block.
In-session skill
The /agentihooks skill (delivered via the bundle at .claude/skills/agentihooks/) runs the same checker inside a Claude Code session with --session $CLAUDE_SESSION_ID --json, adding live session metrics: context fill %, burn rate, per-tool consumption from the context audit, and warning levels.
agentihooks lint-claude
Analyze a CLAUDE.md file for token cost and suggest sections to extract into on-demand skills.
agentihooks lint-claude [path]
Defaults to ~/.claude/CLAUDE.md if no path is given.
Output
- Total character and token estimate
- Per-section breakdown with classification (always-needed vs workflow-specific)
- Extraction candidates with token savings estimate
agentihooks extract-skill
Extract a section from CLAUDE.md into a standalone skill directory.
agentihooks extract-skill "<Section Heading>" --name <skill-name> [--source <path>] [--output-dir <path>]
Flags
| Flag | Description |
|---|---|
--name | Required. Name for the skill directory. |
--source | Path to CLAUDE.md (default: ~/.claude/CLAUDE.md). |
--output-dir | Output directory (default: source’s .claude/commands/). |
Standalone Python execution
The hook and MCP server modules can be run directly with Python:
# Run the MCP tool server
python -m hooks.mcp
# Run with specific categories
MCP_CATEGORIES=channels,enforcement python -m hooks.mcp
# Process a hook event manually
echo '{"hook_event_name":"SessionStart","session_id":"test-123"}' | python -m hooks
# Pipe a PreToolUse event
echo '{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"ls"}}' | python -m hooks
Exit codes
| Code | Meaning |
|---|---|
0 | Success |
1 | Error (installation failed, missing config, etc.) |
2 | Block (used by hook handlers to cancel tool execution) |