返回 CodeWhale
docs-hooks.ts
根目录 / web / lib / i18n / dictionaries / en / docs-hooks.ts
1 import type { DocsHooksDict } from "../types";
2
3 /**
4 * English reference dictionary for `app/[locale]/docs/hooks/page.tsx`
5 * ("Run commands on events"). Checked against docs/HOOKS.md — the
6 * authoritative event-by-event contract (15 events, steering events,
7 * conditions, environment variables, project-hook approval).
8 */
9 export const docsHooks: DocsHooksDict = {
10 metaTitle: "Run commands on events · Codewhale Docs",
11 metaDescription:
12 "Run your own scripts when a session starts, before a tool call, when a turn ends, or when Codewhale is waiting for you — to add context, enforce a rule, or get notified.",
13 bodyClassName: "text-ink-soft leading-relaxed",
14 title: "Run commands on events",
15 lede:
16 "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.",
17 sections: [
18 {
19 id: "first-hook",
20 title: "Add your first hook",
21 blocks: [
22 { p: "Hooks live in `~/.codewhale/config.toml`. This one prints a line whenever a session starts:" },
23 {
24 code: `[hooks]
25 enabled = true
26
27 [[hooks.hooks]]
28 name = "announce"
29 event = "session_start"
30 command = "echo 'Codewhale session started'"`,
31 lang: "config.toml",
32 },
33 {
34 p: "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.",
35 },
36 ],
37 },
38 {
39 id: "gate",
40 title: "Block a command before it runs",
41 blocks: [
42 {
43 p: "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:",
44 },
45 {
46 code: `#!/bin/sh
47 # ~/.codewhale/hooks/no-force-push.sh
48 case "$DEEPSEEK_TOOL_ARGS" in
49 *"push --force"*|*"push -f"*)
50 echo '{"decision": "deny", "reason": "Force-push is blocked by a hook."}' ;;
51 esac
52 exit 0`,
53 lang: "no-force-push.sh",
54 },
55 {
56 code: `[[hooks.hooks]]
57 name = "no-force-push"
58 event = "tool_call_before"
59 command = "~/.codewhale/hooks/no-force-push.sh"
60 condition = { type = "tool_name", name = "bash" }`,
61 lang: "config.toml",
62 },
63 {
64 p: "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.",
65 },
66 {
67 note: "`ask` forces a prompt in Ask and Auto-Review. Full Access never shows approval prompts, so there `ask` does not add one.",
68 },
69 ],
70 },
71 {
72 id: "events",
73 title: "Choose the moment",
74 blocks: [
75 {
76 p: "Three events can change what happens next. The rest only observe; their output is ignored and a failure is a warning.",
77 },
78 {
79 rows: [
80 ["message_submit", "Before your message reaches the model. Can replace the text or block it."],
81 ["tool_call_before", "Before each tool call. Can allow, deny, ask, rewrite the input, or add context."],
82 ["shell_env", "Before each shell command. Can add environment variables."],
83 ["session_start / session_end", "When a session opens or closes cleanly."],
84 ["turn_end", "After a turn finishes, with its status, duration, and token usage."],
85 ["tool_call_after", "After each tool result, with its exit code when there is one."],
86 ["waiting_for_user", "When Codewhale starts waiting for an approval, an answer, or a paused goal."],
87 ["session_idle / session_busy", "When the session settles or starts working again."],
88 ["session_error / on_error", "When a turn fails for good, or on any error or failed tool."],
89 ["mode_change", "When you switch between Plan, Work, and Operate."],
90 ["subagent_spawn / subagent_complete", "When a sub-agent starts or finishes."],
91 ],
92 codeTerms: true,
93 },
94 {
95 p: "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.",
96 },
97 ],
98 },
99 {
100 id: "options",
101 title: "Set timeouts and failure behavior",
102 blocks: [
103 {
104 rows: [
105 ["timeout_secs", "How long the hook may run. Default 30."],
106 ["continue_on_error", "`true` (default): a failing hook only warns. `false`: the failure blocks."],
107 ["background", "`true` runs the hook as an observer only; it cannot block or rewrite."],
108 ["working_dir", "Under `[hooks]`: where hooks run. Default: the session's workspace."],
109 ],
110 codeTerms: true,
111 },
112 {
113 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.",
114 },
115 ],
116 },
117 {
118 id: "project",
119 title: "Use hooks a repository ships",
120 blocks: [
121 {
122 p: "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:",
123 },
124 { code: "/hooks review\n/hooks approve <digest>\n/hooks revoke", lang: "Codewhale" },
125 {
126 p: "`/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.",
127 },
128 ],
129 },
130 {
131 id: "headless",
132 title: "Use hooks in scripts and CI",
133 blocks: [
134 {
135 p: "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.",
136 },
137 { code: 'codewhale exec --auto --hooks "run the test suite and fix the first failure"', lang: "Terminal" },
138 ],
139 },
140 ],
141 next: [
142 {
143 href: "/docs/modes",
144 label: "Set modes and approvals",
145 note: "How hook decisions combine with Ask, Auto-Review, and Full Access.",
146 },
147 {
148 href: "/docs/mcp",
149 label: "Connect tools with MCP",
150 note: "Gate MCP tools with the same `tool_call_before` hooks.",
151 },
152 {
153 href: "/docs/configuration",
154 label: "Change settings",
155 note: "Where `config.toml` lives and what a project may override.",
156 },
157 ],
158 sourceNote:
159 "Source documents: docs/HOOKS.md (authoritative), docs/CONFIGURATION.md · Update docs-map.ts when changing.",
160 };
161
161 lines TYPESCRIPT