Date: 2026-09-11 Date: 2026-09-10

Hooks and automation

Use this lesson to build a practical, evidence-based Nova workflow for this topic.

What hooks are

Hooks are local commands that Nova runs at defined lifecycle boundaries. They are useful when a rule must be enforced mechanically rather than remembered in a prompt. Typical uses include:
  • rejecting unsafe tool inputs before execution;
  • running local checks after selected tool calls;
  • adding bounded context when a session or prompt starts;
  • recording local audit signals without exposing secrets;
  • notifying another local process when a lifecycle event occurs.
Hooks execute code on the machine. Treat every project hook as executable repository content: inspect it before use, keep it narrow, and never assume a cloned project’s hooks are trustworthy.

Supported events

Nova currently recognises these exact event names: Event names are case-sensitive in hook paths.

Hook locations

Nova discovers hooks from:
  • .compass/hooks/ in the project;
  • ~/.compass/hooks/ for personal hooks.
Project hooks take precedence over personal hooks with the same event and hook name. This lets a repository define its own enforcement policy, but it is also why project hooks require careful review. Supported layouts include:
Nova discovers .yaml, .yml, and .md hook files. It also supports extensionless shebang scripts in recognised event paths. For same-source duplicates, .yaml has precedence over .yml, then .md, then an extensionless file.

Frontmatter

A configured hook can use YAML-style frontmatter followed by the command body:
Supported frontmatter fields are:
  • description — human-readable purpose;
  • enabled — set to false to skip the hook;
  • tools — tool-name glob patterns for PreToolUse and PostToolUse;
  • timeout — process timeout in milliseconds.
The hook type model includes a match map for input-field glob matching, but the current frontmatter reader is intentionally flat and does not reliably parse nested mappings. Do not depend on match in a published hook; put input matching in the script itself.

A portable PreToolUse example

An extensionless Node.js hook avoids platform-specific shell syntax. Save this as .compass/hooks/PreToolUse/protect-env:
Extensionless hooks must begin with a valid shebang. Nova invokes the named interpreter directly; on Windows it also resolves common Git for Windows bash or sh locations when those interpreters are requested.

Hook input

Nova sends one event-specific JSON object to standard input. Every event includes:
  • session_id;
  • transcript_path;
  • cwd;
  • hook_event_name.
Tool events also include tool_name, tool_input, and tool_use_id. PostToolUse adds tool_response. Other events add their own fields, such as prompt, message, agent_id, or source. Nova also supplies environment variables such as HOOK_EVENT, HOOK_NAME, HOOK_CWD, and tool-specific values. Prefer the JSON input because it preserves structure and is easier to validate. Treat all hook input as untrusted. Parse JSON defensively, validate fields, quote paths, and never evaluate input as code. For malformed input, choose and document fail-open or fail-closed behaviour; the policy-enforcement example above deliberately fails closed.

Exit status and output

For PreToolUse:
  • exit code 0 allows processing to continue;
  • a non-zero exit blocks the tool call;
  • standard error, then standard output, is used as the block explanation when available.
For successful hooks, structured JSON output can add context with:
SessionStart and UserPromptSubmit also accept successful plain-text output as additional context. Other events require the structured form for context injection. Nova limits hook execution and output: the default per-hook timeout is 30 seconds, configured timeouts are capped at 120 seconds, and process output is bounded. Hooks should therefore be fast, local, and deterministic.

Enable or disable hooks

Hooks are enabled by default in the runtime. Configuration can explicitly change that setting:
Use nova doctor when hook execution appears disabled or the wider installation may be unhealthy.

Design guidance

  1. Use NOVA.md for guidance and hooks for enforcement. A hook is appropriate only when a deterministic lifecycle check is needed.
  2. Fail closed only for high-confidence checks. A noisy PreToolUse hook can block legitimate work.
  3. Keep hooks quick. Long network operations make every affected tool call slower and less reliable.
  4. Do not print secrets. Hook output can become visible in diagnostics or injected context.
  5. Do not duplicate Nova approvals. Hooks can add organisation-specific constraints, but they should not weaken or work around the approval manager.
  6. Test scripts outside Nova first. Feed representative JSON through standard input and verify exit codes on the target operating system.
  7. Review project hooks after pulling changes. They are executable policy, not passive documentation.

Troubleshooting

  • Confirm the directory and exact event spelling.
  • Confirm the extension is supported, or that an extensionless file starts with a shebang.
  • Check that the configured interpreter exists on the current machine.
  • Keep paths valid for the target shell; .yaml, .yml, and .md bodies use the platform shell.
  • Verify the hook’s tools pattern matches the runtime tool name.
  • Reproduce the script with captured test JSON and inspect its exit code.
  • Shorten slow work or raise timeout only within Nova’s cap.
  • Run nova doctor to check whether hooks are disabled by configuration.

What you learned

You can now apply the core practices in this lesson during a Nova session.

Try it yourself

Use this lesson’s guidance in a small, non-destructive task in a local project, then review the result before continuing.

Continue the course