Codewhale documentation
ReleaseLatest release v0.10.0 · 22 wrz 2026These pages describe v0.10.0, the published release.Changelog →

Run commands on events

Hooks run a command of yours at set moments in a Codewhale session. Use them to block a risky command, add context to a message, log what happened, or get told when Codewhale is waiting for you.

Add your first hook

Hooks live in ~/.codewhale/config.toml. This one prints a line whenever a session starts:

[hooks]
enabled = true

[[hooks.hooks]]
name = "announce"
event = "session_start"
command = "echo 'Codewhale session started'"

Start a session, then run /hooks to see every configured hook, whether hooks are on, and any entry that was rejected. /hooks events lists the event names.

Block a command before it runs

A tool_call_before hook sees each tool call before it executes and can allow it, deny it, or force an approval prompt. This one refuses force-pushes. Save the script and make it executable:

#!/bin/sh
# ~/.codewhale/hooks/no-force-push.sh
case "$DEEPSEEK_TOOL_ARGS" in
  *"push --force"*|*"push -f"*)
    echo '{"decision": "deny", "reason": "Force-push is blocked by a hook."}' ;;
esac
exit 0
[[hooks.hooks]]
name = "no-force-push"
event = "tool_call_before"
command = "~/.codewhale/hooks/no-force-push.sh"
condition = { type = "tool_name", name = "bash" }

The hook reads the call from environment variables and answers with JSON on standard output: allow, deny, or ask, plus an optional reason, a rewritten input (updatedInput), or extra context for the model (additionalContext). Exit code 2 always denies. When several hooks answer, deny beats ask, and ask beats allow.

Note: ask forces a prompt in Ask and Auto-Review. Full Access never shows approval prompts, so there ask does not add one.

Choose the moment

Three events can change what happens next. The rest only observe; their output is ignored and a failure is a warning.

message_submit
Before your message reaches the model. Can replace the text or block it.
tool_call_before
Before each tool call. Can allow, deny, ask, rewrite the input, or add context.
shell_env
Before each shell command. Can add environment variables.
session_start / session_end
When a session opens or closes cleanly.
turn_end
After a turn finishes, with its status, duration, and token usage.
tool_call_after
After each tool result, with its exit code when there is one.
waiting_for_user
When Codewhale starts waiting for an approval, an answer, or a paused goal.
session_idle / session_busy
When the session settles or starts working again.
session_error / on_error
When a turn fails for good, or on any error or failed tool.
mode_change
When you switch between Plan, Work, and Operate.
subagent_spawn / subagent_complete
When a sub-agent starts or finishes.

A condition narrows when a hook fires: by tool name (with * globs), tool category, mode, or exit code, and combinations with all and any. A condition that can never match its event is rejected when the config loads, so a gate you think is armed never sits silently inert.

Set timeouts and failure behavior

timeout_secs
How long the hook may run. Default 30.
continue_on_error
true (default): a failing hook only warns. false: the failure blocks.
background
true runs the hook as an observer only; it cannot block or rewrite.
working_dir
Under [hooks]: where hooks run. Default: the session's workspace.

Note: [hooks] default_timeout_secs replaces every hook's own timeout_secs, not just the missing ones. Leave it unset if you want per-hook timeouts.

Use hooks a repository ships

A repository can include hooks in .codewhale/hooks.toml. Because they run commands on your machine, they load only after you trust the workspace and approve that exact file:

/hooks review
/hooks approve <digest>
/hooks revoke

/hooks review shows the commands and a digest of the file; approving that digest enables those exact bytes from the next session. Any change to the file needs a new approval. Review the scripts the commands call, too.

Use hooks in scripts and CI

Hooks run in the interactive session. codewhale exec fires none by default; add --hooks to fire tool_call_before and shell_env. With no one to answer, an ask becomes a deny.

codewhale exec --auto --hooks "run the test suite and fix the first failure"

Next

Set modes and approvals

How hook decisions combine with Ask, Auto-Review, and Full Access.

Connect tools with MCP

Gate MCP tools with the same tool_call_before hooks.

Change settings

Where config.toml lives and what a project may override.