Skip to content
AFK / Docs

Search page titles and summaries. Shortcut: Ctrl / ⌘ K.

38 pages found

Hooks

Hooks are user-defined shell commands that fire in response to agent lifecycle and tool events. Use them to enforce policies, send notifications, log activity, or inject additional instructions.

Settings files and scope

Hooks can be configured in any of these files:

  • ~/.afk/hooks.json — daemon-owned user file on the selected machine; edit it from Preferences → Hooks. Project and local files stay with the checkout and are edited from /hooks.
  • <projectDir>/.afk/hooks.json — project-level AFK hooks
  • <projectDir>/.afk/hooks.local.json — project-local AFK hooks (gitignored)
  • ~/.afk/settings.json, <projectDir>/.afk/settings.json, and <projectDir>/.afk/settings.local.json — legacy compatibility read path only. The AFK editor writes to hooks files so it does not overwrite Claude Code-specific settings.
  • <pluginRoot>/hooks.json — plugin-provided hooks

Scope precedence (later overrides earlier for the same event):

  1. User settings/hooks
  2. User-scope plugin hooks
  3. Project settings/hooks
  4. Project-scope plugin hooks
  5. Project local settings/hooks

The selected daemon must be connected to load hooks. If loading fails, reconnect it and retry; an unavailable configuration is not treated as an empty file. Preferences → Hooks reads only the selected machine’s user configuration.

Hook file format

AFK uses a definition-first flat event-key format. Put reusable hook definitions under hooks and declare on keys such as SessionStart:spawn, BeforeToolUse:bash, and BeforeCompact:auto.

{
  "hooks": [
    {
      "name": "load-context-on-start",
      "on": ["SessionStart:spawn", "SessionStart:resume"],
      "prompt": "Load relevant context: $ARGUMENTS",
      "json_output": true
    },
    {
      "name": "guard-bash",
      "on": ["BeforeToolUse:bash"],
      "command": "python3 ./hooks/check-policy.py",
      "blocking": true
    }
  ]
}

Legacy top-level event buckets and Claude Code-style hook maps are still accepted as compatibility inputs, but AFK normalizes them into the same internal definition list.

Hook object fields

FieldDefaultDescription
onFlat event keys that trigger this hook definition.
commandShell command run via bash -lc in the project directory.
promptModel-evaluated prompt hook. Use $ARGUMENTS to insert hook input JSON.
blockingtrueWhether AFK waits for the command and allows it to block the event.
json_outputfalseParse stdout as JSON and merge it into AFK's hook result.
timeout_seconds30Optional timeout; hook is killed if it exceeds this.

Exit codes

Exit codeBehavior
0Proceed normally.
2Block the event. Stderr is used as the user-visible reason (falls back to stdout).
Any otherAFK logs the failure and continues.

Hook input and output

AFK sends structured event data to hook commands and can read structured JSON responses when json_output: true is enabled. Use this to block unsafe actions, add context, answer repeated prompts, or route notifications through team systems.

Hook commands run with the current project directory available in the environment. Keep hook scripts small, deterministic, and safe to run on developer machines or shared daemons.

For blocking hooks, exit code 2 means “stop this action”; stderr is shown as the user-visible reason. Other non-zero exits are treated as hook failures and AFK continues.

Supported event groups

Hooks can run around tool use, approvals, session lifecycle, messages, compaction, notifications, MCP prompts, worktrees, and sub-agent events. The hook editor in AFK shows the available event keys for your current version.

Event groupCommon uses
Tool executionBlock risky commands, log edits, or require local policy checks.
Session lifecycleLoad context on start, send completion notifications, or clean up resources.
Messages and compactionAdd recurring instructions or preserve important context during summaries.
MCP promptsApply team defaults to repeated structured prompts.
Worktrees and sub-agentsNotify teams when parallel work starts or finishes.

Practical examples

Block bash entirely

{
  "BeforeToolUse": {
    "command": "python3 ./hooks/check-policy.py",
    "blocking": true
  }
}

Add a reminder to every compaction

{
  "BeforeCompact": {
    "command": "echo '{\"additional_instructions\":\"Preserve pending release tasks and rollback notes.\"}'",
    "json_output": true
  }
}

Send notifications asynchronously

{
  "Notify": {
    "command": "./scripts/send-notification.sh",
    "blocking": false
  }
}

Troubleshooting

My hook never runs

  • Check the event name matches exactly, including capitalization.
  • Verify the settings file is valid JSON.
  • Confirm the hook command is runnable under bash -lc.
  • After changing hooks via the UI, the running session picks up changes — no restart needed.

My hook blocks unexpectedly

Exit code 2 is treated as an intentional block. Any stderr content becomes the user-visible reason shown in the browser.

My JSON output is ignored

  • Ensure json_output: true is set on the hook object.
  • Verify stdout contains valid JSON only (no extra logging to stdout).
  • Use only the JSON keys AFK consumes for that specific event.