Skip to content

Hooks

Hooks connect editor events, CI runs, agent turns, and session lifecycle to foxctl skills and commands. They are the primary integration surface for automating context injection, memory management, code analysis, and workflow gating.

This page covers hook configuration, the event model, merge semantics, safety rules, and the full catalog of installed hook scripts.

PathScope
<workspace>/.foxctl/hooks.yamlWorkspace-level hooks
~/.foxctl/hooks.yamlGlobal hooks

Workspace config overrides global config by hook id. Hooks are loaded and merged at startup.

SettingDefaultDescription
Merge behaviorLater file wins by idWorkspace overrides global
Execution orderingAscending priority per eventLower priority numbers run first
Default run timeout2000ms per run entryPrevents runaway hooks
Default failure modeFail-openHook failure does not block unless overridden

Hook scripts live in configs/hooks/. For Claude Code, hooks are registered in .claude/settings.json. Other editors and CI systems use their own registration mechanisms pointing at the same scripts.

Hooks fire on these events during session and agent lifecycle:

EventWhen it fires
SessionStartNew session begins
MessageReceivedInbound message arrives
UserPromptSubmitUser submits a prompt
LLMRequestRequest sent to LLM provider
LLMResponseResponse received from LLM
PreToolUseBefore a tool call executes
PostToolUseAfter a tool call completes
StopRequestedSession stop requested
PostAgentTurnAgent turn finishes
ContextBudgetExceededContext window budget exhausted
SessionEndSession terminates
SubagentStartSubagent spawned
SubagentStopSubagent completes

The hook input (hooks.Input) includes:

  • Event identity (event name, hook ID)
  • Principal, workspace, and session metadata
  • Provider capabilities
  • Tool metadata (tool_name, tool_canonical, tool_kind, input/observation)
  • Optional hook-specific config

The hook output (hooks.Output) includes:

FieldPurpose
decisionnone, approve, or block
reasonHuman-readable explanation (especially for block)
contextContext text to inject
updated_tool_inputLast-wins mutation for pre-tool execution
updated_assistant_textLast-wins mutation for post-turn text
actions[]Ordered structured actions
metaDebug and observability metadata

Actions are ordered, typed operations that the dispatcher executes:

ActionPurpose
run_skillExecute a skill
inject_contextImmediately inject context into the session
enqueue_contextQueue context for later drain
send_mailboxSend a message to an agent mailbox
bb_postPost to a bulletin board
bb_claimClaim a bulletin board entry

When multiple hooks fire on the same event, their outputs are merged deterministically:

RuleBehavior
Decision precedenceblock > approve > none
Reason selectionFirst non-empty reason for the final decision class
Tool input mutationLast-wins
Assistant text mutationLast-wins
ContextConcatenated in execution order, separated by \n\n
ActionsConcatenated in execution order
MetaShallow merge, last-wins by key

Not all events support all output types:

  • PreToolUse cannot directly inject context — use the enqueue_context action for later drain
  • Inject-capable events (PostToolUse, UserPromptSubmit, SessionStart) can apply immediate context injection
  • Blocking support depends on provider capabilities — the dispatcher honors decision:block only when the provider supports it
  1. Select enabled hooks matching the event
  2. Evaluate matchers (actor, tool, path, namespace, prompt)
  3. Execute each run entry via the registry runner (skill or shell) with timeout and failure mode
  4. Collect outputs and merge deterministically
  5. Emit observability metadata and return the final merged output

Skills are resolved via the hook resolver/registry from installed skill paths. Shell-based hooks are supported through the shell runner.

All hooks must respect these invariants:

  • JSON envelopes only on stdout — skill stdout must remain valid Protocol v1 JSON envelopes; no freeform text
  • Logs to stderr — hook logs and diagnostic output go to stderr, never stdout
  • Secrets must be redacted — never expose API keys, tokens, or credentials in hook output
  • Path access through policy — file access must go through policy.PathValidator
  • Deterministic for CI — test-feedback and review hooks should be deterministic enough for CI use

All hook scripts live in configs/hooks/. Most are thin wrappers over foxctl hooks <name> commands.

ScriptPurpose
session-init.shSession initialization (wrapper over foxctl hooks session-start)
session-end.shSession cleanup (wrapper over foxctl hooks session-end)
session-compact.shContext compaction logic
session-restore-postcompact.shRestore context after compaction
ScriptPurpose
subagent-stop.shSubagent completion handler
overseer-inbox.shOverseer inbox processing
overseer-inbox-post.shPost-processing for overseer inbox
task-continuity-summary.shPrompt-ready wrapper for foxctl context task-history-summary
task-file-link.shLink task context to files
task-guard.shTask boundary enforcement
ScriptPurpose
memory-detector.shDetect memory-worthy patterns
memory-recall.shRecall relevant memories
memory-lifecycle.shMemory lifecycle management
context-updater-drain.shDrain queued context updates
anchor-detect.shDetect semantic anchors
ScriptPurpose
code-analysis.shRun code analysis on changes
live-index.shUpdate repo index incrementally
lsp-diagnostics.shCapture LSP diagnostic data
embedding-flush.shFlush embedding queues
ScriptPurpose
plan-sync.shSynchronize plan state
graph-maintenance.shRepo graph maintenance tasks
ScriptPurpose
todo-sync.shSynchronize TODO state
todo-continuation.shContinue TODO-driven work
todo-advisor.shSuggest next TODO actions
ScriptPurpose
build-guard.shGuard against build failures
security-scanner.shRun security scans on changes
test-feedback.shCapture and relay test results
ScriptPurpose
foxctl-mode.shMode enforcement
foxctl-mode-enforce.shStrict mode enforcement
bash-advisor.shBash best-practice suggestions
skill-advisor.shSkill recommendation logic
counsel-detect.shCounsel pattern detection
counsel-suggest.shCounsel suggestion generation
knowledge-router.shRoute knowledge queries
hooks-error-drain.shDrain hook errors
context-detect.shDetect context patterns

Use the structured command for Codex, scripts, and agent runtimes:

Terminal window
foxctl context task-history-summary

Use the shell wrapper only when a hook needs prompt-ready JSON:

Terminal window
configs/hooks/task-continuity-summary.sh
  1. Create a script in configs/hooks/
  2. Register it in .claude/settings.json (for Claude Code) or your editor’s hook configuration
  3. The script should output context injection text to stdout (or nothing if no injection needed)
  4. Logs go to stderr

Hook scripts should follow the output contract: valid JSON envelopes on stdout, human-readable logs on stderr.