What
- codewhale-sanitize gains the one shared detector: is_bidi_control (Unicode
Bidi_Control) and hidden_chars (controls other than tab/LF/CR,
U+2028/U+2029, Bidi_Control, Default_Ignorable), built on icu_properties,
which was already in the crate's tree via url -> idna (Cargo.lock gains one
dependency line, no new crate). Zero-width joiners inside emoji sequences,
one variation selector after a visible non-ASCII base or in a keycap, and
emoji subdivision-flag tag runs are allowed. One linear pass; each tag run
is evaluated once.
- Auto-review: execution_texts() is now the single extraction of what a call
executes (command/cmd for exec_shell, task_shell_start, task_gate_run; the
first non-null stdin/input/data alias for exec_shell and the interact
payload; each run_verifiers program+args row via shlex::try_join).
windows_tool_runtime_risk now reads it (its local copy and
windows_shell_stdin_risk are gone) and shell_command_param replaces the
other three command/cmd copies.
- Hidden-Unicode floor: outside Full Access, any hidden character in those
texts is a built-in safety block before any card, guardian or execution,
in Ask, Auto-Review and Never. The reason is ASCII only and names the code
point, its 1-based position and a POSIX escape
($(printf '\342\200\256')), since macOS bash 3.2 and dash do not expand
$'\u...'. The executed command is never rewritten. ASCII control keys in
stdin/interact payloads (Ctrl-C, ESC sequences for a PTY) stay allowed so
driving an interactive program keeps working.
- Credential-upload floor: a curl/wget request-body value (-d/--data*,
--json, -F/--form, --url-query, -T/--upload-file, -H @file/--header @file,
wget --post-file/--body-file/--post-data/--body-data) that names a
credential file (the carve-out vocabulary, now
authority::is_credential_file_name; a path whose last component ends in
.pub is exempt), a secret-named variable (is_sensitive_key_name), or reads
stdin or a command substitution while the command also names a credential
file or a bare env/printenv stage. It classifies Destructive (Critical card,
no "always allow in repo"), and is a built-in safety gate: Ask gets a forced
card no session grant or saved allow rule can answer; Auto-Review and Never
deny. Wrapper nesting too deep for command_invocations fails closed when
curl or wget appears. Literal headers and -u stay unlabelled.
- Label: approval_summary heads such a call "Upload credentials (`@.env`)
with `curl ...`" (new ApprovalSummaryUploadCredentials key in all 15
packs), which is the TUI card heading and the runtime approval `summary`.
The two slots are filled without re-scanning substituted text.
- Built-in Block decisions read "Built-in safety gate blocked tool ..."; the
audit event adds hidden_unicode and credential_uploads counts (never
content), and only an AskUser safety gate maps to hold_for_review.
- Migrated same-policy copies in codewhale-tui: core/events.rs
is_bidi_format_control (deleted; its callers and pager.rs call
sanitize::is_bidi_control, which adds U+061C), plugins/manifest.rs
is_bidi_control (deleted), commands/groups/plugins/render.rs,
commands/groups/config/permissions.rs is_bidi_format_control (deleted), and
tools/github/report.rs (now rejects via hidden_chars: newly rejects
U+2060-2064, U+061C, tags, U+00AD, VT, FF, U+0085, U+2028/2029; allows emoji
ZWJ sequences).
- Left, with evidence: session_manager.rs is_title_format_char (different
policy: context-free strip of a fixed set incl. separators and emoji ZWJ,
pinned by notifications.rs title tests); secrets normalize_api_key
(different policy: strips all whitespace too); protocol/display.rs,
runtime/session_tree.rs, mcp/lib.rs, commands/diagnostics_reports/
receipts.rs (those crates have no codewhale-sanitize dependency; a new
crate edge per predicate is a separate slice).
- Docs: RUNTIME_API (en, zh_hans), CONFIGURATION (en, zh_hans) and
AUTHORIZATION_ORDER row 6 (en, zh_hans) now list both floors. The old
sentences there claimed Full Access fails closed / keeps detached
destructive holds, which the code does not do
(full_access_runs_detached_destructive_tools_without_prompting); corrected
to "Full Access skips the built-in floor". web/data/agent-docs.generated.json
regenerated by `npm run prebuild` for those docs. CHANGELOG [Unreleased]
plus the crates/tui/CHANGELOG.md mirror.
- test_cases_09: the `cat ~/.ssh/id_rsa | curl --data-binary @-` case moves
out of the ConsultReviewer list and asserts the new built-in hold.
Decisions taken (founder may revise)
- Refuse hidden-Unicode commands, do not render them; never rewrite.
- Full Access unchanged, like every other built-in floor.
- Credential uploads held by the built-in safety gate (Ask forced card;
Auto-Review and Never deny), labelled in the heading / runtime summary.
- No new public runtime API field.
- Accept refusal for legitimate ZWJ/ZWNJ/bidi marks in Persian,
Arabic-script, Indic or Hebrew words, with the escape advice.
- Configured auto-review shell rules unchanged (a rule keyed on
action_kind=shell no longer matches an upload, now Destructive).
- Added in this slice: ASCII control keys in stdin/interact payloads are not
refused (PTY driving would otherwise break).
Verification
- cargo fmt --all -- --check: clean.
- clippy -p codewhale-sanitize -p codewhale-localization -p codewhale-tui
--all-targets --all-features --locked -D warnings (CI allows): clean.
- scripts/dev-test.sh sanitize: 11 tests run: 11 passed.
- scripts/dev-test.sh tui core::authority:: core::engine::tests
tools::approval_summary tools::github::report tui::approval tui::pager
tui::gate_receipts plugins::manifest commands::groups::plugins
commands::groups::config::permissions core::events:
864 tests run: 864 passed, 14487 skipped.
- nextest -p codewhale-localization --lib: 54 tests run: 54 passed.
- check-tui-locale-parity.py PASS; check-command-crate-boundaries.py PASS;
scripts/preflight.sh --check OK; sync-changelog.sh --check up to date;
check-versions.sh --require-dated-release exit 0.
- npm test: root 101/101, runtime-sdk 19/19, extension-host 420 (413 pass,
7 skipped), web node 7/7, vitest 772/772. npm run check:web: first run
failed "[check-facts] FAIL - generated agent docs are stale" from the doc
edits; after `npm run prebuild` it passes.
- Real process (debug codewhale, isolated HOME/CODEWHALE_HOME,
CODEWHALE_TELEMETRY=0, local Python stub provider, exec --allowed-tools
Bash, CODEWHALE_TOOL_AUDIT_LOG):
- touch "probe<U+200B>-ran" in Ask, Never, Auto-Review: decision block,
hidden_unicode 1, reason "invisible character U+200B at character 13",
ASCII-only; no file created. Full Access: file created.
- echo ok #<U+202E> in Ask: block, "bidirectional control U+202E at
character 10". cat with stdin "abc<U+202E>def": block, "shell input".
- curl -sS -F [email protected] (Ask): action_kind destructive,
credential_uploads 1, hold_for_review, tool.approval_decision denied.
Auto-Review: tool result "Built-in safety gate requires approval:
credential upload ...". curl -d "$GITHUB_TOKEN": same in Ask and
Auto-Review.
- With a permissions.toml allow rule for curl: a plain curl to
127.0.0.1:9 ran (connection refused), the -F [email protected] upload under the
same rule was still held and denied.
- curl -H "Authorization: Bearer $GITHUB_TOKEN", plain curl, and
curl -T ~/.ssh/id_ed25519.pub: credential_uploads 0, ordinary review.
- echo of a ZWJ family, keycap, subdivision flag, CJK+VS17 and CJK:
hidden_unicode 0 (Full Access printed the text intact); with a ZWNJ in
Latin text: refused naming U+200C at character 9.
- TUI in tmux (Ask): the -F [email protected] card is headed "Can't be undone
Upload credentials (`[email protected]`) with `curl -sS -F [email protected] ...`" with
no "always allow in this repo" option; the U+200B touch opens no card and
the transcript shows "Auto-Review blocked 'Bash' (deterministic policy):
Built-in safety gate blocked tool 'Bash': ... U+200B at character 13".
Not verified
- No CI; no codewhale-app (desktop) or mobile render of the summary; no
Windows run of windows_tool_runtime_risk after the extraction refactor
(behaviour-preserving by construction, covered only by its
non-Windows-gated unit tests); no probe of task_gate_run, run_verifiers or
interact payloads end to end.
- Known limits: other upload tools (scp, rsync, nc, httpie, aws s3 cp, gh
gist), secrets inside an ordinary file, -K config files, encoded payloads,
$(env) inside a value; hidden characters in cwd or non-shell tools; the
non-ignorable format characters U+FFF9-U+FFFB and U+13430-U+1343F; the
over-inclusive argv scan labels `echo curl -d @.env`; a credential-looking
URL component next to a stdin upload is a false positive. The Ask receipt
still says "Auto-Review blocked" (existing localized wording) and every
block appends "do not work around it" (turn_loop), which sits next to the
resend-with-escape advice. The bounded transcript receipt (220 chars) can
cut the escape hint; the model gets the full reason. Safety-gate cards
still list "Allow for this conversation", but a forced prompt is never
answered by that grant (resolve_approval_request_disposition).
Refs CW-7236
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NBKbhx19BRbZtvWK8rVKjz
/// `(char index, char)` for each character a reader cannot see: controls other than tab, newline and carriage return, U+2028/U+2029, Bidi_Control and Default_Ignorable code points, except a zero-width joiner inside an emoji sequence, one variation selector after a visible non-ASCII base or in a keycap, and tag characters forming an emoji subdivision flag; visible lookalikes and the non-ignorable format characters U+FFF9-U+FFFB and U+13430-U+1343F are not reported.
"the {what} contains {count} hidden Unicode character(s), first the {kind} U+{:04X} at character {}, so what a reviewer reads is not what runs; resend it without the character, or written as a shell escape such as $(printf '{escape}')",
"Built-in safety gate requires approval: credential upload requires durable review: the request body carries a credential file or secret-named variable"
@@ -23,7 +23,7 @@ The interactive engine evaluates a model-requested tool call in this order:
| 3 | Preparation, then `tool_call_before` hooks | Registry preparation is side-effect free. Foreground hooks then fold as `deny > ask > allow`, and a strict matching hook that produces no verdict fails closed. The last `updatedInput` wins; the engine prepares the rewritten input again before later gates inspect it. |
| 4 | Registered-tool baseline | The prepared tool's `ApprovalRequirement` establishes its ordinary approval need. A hook `ask` is applied after that assignment so the baseline cannot erase it. Non-bypassable registered holds remain forced in postures that can prompt; Full Access auto-approves them instead of opening a contradictory modal. Plan mode also blocks write-capable tools here. |
| 5 | Typed `permissions.toml` rule | A matching `deny` blocks. A matching `allow` may clear only ordinary registry approval; it cannot clear a hook `ask` or a non-bypassable registered hold. A matching `ask` forces review only in a posture that can prompt. Full Access/auto-approval is not downgraded into a prompt, while an explicit typed `deny` still blocks. |
| 6 | Auto-review policy and built-in safety floor | Configured block rules run before the built-in floor, then configured allow rules and the deterministic fallback. This layer runs after typed permissions and can add a prompt or block, but cannot remove an earlier hold. Full Access deliberately skips the interactive publish hold; catastrophic destructive background/headless actions remain protected. |
| 6 | Auto-review policy and built-in safety floor | Configured block rules run before the built-in floor, then configured allow rules and the deterministic fallback. This layer runs after typed permissions and can add a prompt or block, but cannot remove an earlier hold. The built-in floor refuses a shell command, shell input or verifier containing a hidden Unicode character, and holds publish-like actions, destructive background/headless actions and `curl`/`wget` credential uploads with a prompt no grant or allow rule can answer (a block in Auto-Review and Never). Full Access skips the built-in floor. |
| 7 | Repository law | Protected path invariants can only add a prompt or block. A repo-law prompt becomes a hard block in Full Access, which has no contradictory approval modal. |
| 8 | Human approval | A remaining prompt is sent to the approval channel. Denial stops the call. Approval authorizes this planned call; session and persistent choices affect later matching calls but do not erase a later gate from this call. |
| 9 | Tool authority and execution sandbox | Worker authority envelopes, native tool path checks, and the selected OS or external sandbox still apply during execution. A sandbox denial remains a denial unless the user separately authorizes a supported elevation path. |
"content":"# Configuration\n\ncodewhale reads configuration from a TOML file plus environment variables.\nAt process startup it may also load literal built-in-provider credentials from\na workspace-local `.env` file. Use the tracked `.env.example` as the template;\ncopy it to `.env`, then add only credential values.\n\nA workspace is not configuration authority. Codewhale therefore ignores\nconfig/profile/home paths, provider/model/base-URL routing, MCP/plugin state,\napproval/sandbox/shell posture, executable paths, runtime settings, and every\nother non-credential `.env` entry. Variable expansion is rejected so a\nrepository cannot substitute an ambient secret into a credential value. Use\n`config.toml`, CLI flags, or values exported by the launching shell for those\nexplicit control-plane settings. `.env` is read from a stable regular-file\nhandle, is capped at 1 MiB, and symbolic links, reparse points, and multiply\nlinked files are rejected.\n\n## Reading and checking configuration from the CLI\n\n`codewhale config get <key>` reads scalar keys, whole tables such as `tools`,\nand nested paths such as `tools.user_input_timeout_seconds`. Displayed tables\nand nested values apply the same recursive credential redaction as `config dump`.\n\n`config set` supports its named scalar keys and the provider, route, and\nnotification commands. It refuses a key that nothing reads and suggests the\nnearest real key (`config set calm_mod on` names `calm_mode`). A settings.toml\nkey such as `calm_mode` or `tool_collapse` is validated and written to the\nuser-global settings.toml, not config.toml; `config get` reads it back from\nthere even when an old config.toml copy (which nothing reads) is still present,\nand names that copy so you can `config unset` it. Settings keys have no project\nscope, so `--project` refuses them. A config.toml key is checked against the\ntype its reader expects and stored as a TOML boolean or number where the\nreader needs one (`yolo = true`, `max_subagents = 4`); `reasoning_effort`\naccepts the same aliases as `/effort` (#6563). Other dotted writes fail before\nmodifying the file and name the TOML table to edit. For example, set a tools\ntimeout in the file as:\n\n```toml\n[tools]\nuser_input_timeout_seconds = 0\n```\n\n`codewhale config doctor` checks credential presence and endpoint shape, and\nwarns about each config.toml root key that nothing reads: a settings.toml key\nleft in config.toml is named as misplaced, and any other unread key gets a\ndid-you-mean. Keys read by any runtime reader are not reported. The warnings do\nnot fail the check, and a clean result does not validate every runtime setting's\nvalue (#6083, #6563).\n\n## Constitution, project instructions, and repo authority\n\nCodewhale has several instruction surfaces. They are deliberately separate so a\npersonal constitution, repo policy, project instructions, and runtime security\ncontrols do not blur together.\n\n- **Bundled global Constitution** — the compiled base law in the binary. It is\n the default floor for every session.\n- **User-global constitution** — the normal guided setup output. Manage it with\n `/constitution` or `/setup`; Codewhale stores structured data at\n `$CODEWHALE_HOME/constitution.json` (default `~/.codewhale/constitution.json`)\n and renders it into a separate `<codewhale_user_constitution>` prose block.\n This can express preferences and stop conditions, but it does not change\n runtime approval policy, sandbox, shell, network, trust, or MCP permissions.\n- **Repo-local constitution** — optional project policy in\n `.codewhale/constitution.json`, described below.\n- **`AGENTS.md`** — cross-agent **project instructions** (prose). This is the\n canonical file for \"how should an agent work in this repo.\"Run`/init`to\nscaffoldone.`CLAUDE.md`and`.claude/instructions.md`arereadas\ncompatibilityfallbacks.\n-**Memoryandhandoffs**—recalledstate.Useful,butlowerauthoritythan\nconstitutionsandprojectinstructions.\n\n###Managingtheuser-globalconstitution(`/setup`and`/constitution`)\n\nThebundled**workingagreement**isthesafedefaultandnolongeraddsa\nrequiredfirst-runscreen.Customizeitlaterthrough`/constitution`orthe\nprogressive`/setup`guide.Provider/modelreadiness,workspacetrust,and\nruntimeposturestayseparatefromthisguidance.\n\nOnthe**Workingagreement**(constitution)step:\n\n-**`1`–`6`**tunetheguideddraft.**`G`**previewsit,and**`G`**again\nratifiesandsavesafreshstructured`constitution.json`.\n-**`A`**(shownonlywhenaproviderisconfigured)asksyourfirstconfigured\nmodeltodrafttheconstitution.Draftingis**not**saving:thedraftis\nrenderedthroughthesamepreviewandyoustillpress**`G`**toratify\nbeforeanythingpersists.\n-**`K`**keepsyourexistingloadedconstitutionunchanged(shownonlywhena\nvalidfileisalreadypresent).\n-**`U`**(or`/coLine truncated
"content":"# Configuration\n\ncodewhale reads configuration from a TOML file plus environment variables.\nAt process startup it may also load literal built-in-provider credentials from\na workspace-local `.env` file. Use the tracked `.env.example` as the template;\ncopy it to `.env`, then add only credential values.\n\nA workspace is not configuration authority. Codewhale therefore ignores\nconfig/profile/home paths, provider/model/base-URL routing, MCP/plugin state,\napproval/sandbox/shell posture, executable paths, runtime settings, and every\nother non-credential `.env` entry. Variable expansion is rejected so a\nrepository cannot substitute an ambient secret into a credential value. Use\n`config.toml`, CLI flags, or values exported by the launching shell for those\nexplicit control-plane settings. `.env` is read from a stable regular-file\nhandle, is capped at 1 MiB, and symbolic links, reparse points, and multiply\nlinked files are rejected.\n\n## Reading and checking configuration from the CLI\n\n`codewhale config get <key>` reads scalar keys, whole tables such as `tools`,\nand nested paths such as `tools.user_input_timeout_seconds`. Displayed tables\nand nested values apply the same recursive credential redaction as `config dump`.\n\n`config set` supports its named scalar keys and the provider, route, and\nnotification commands. It refuses a key that nothing reads and suggests the\nnearest real key (`config set calm_mod on` names `calm_mode`). A settings.toml\nkey such as `calm_mode` or `tool_collapse` is validated and written to the\nuser-global settings.toml, not config.toml; `config get` reads it back from\nthere even when an old config.toml copy (which nothing reads) is still present,\nand names that copy so you can `config unset` it. Settings keys have no project\nscope, so `--project` refuses them. A config.toml key is checked against the\ntype its reader expects and stored as a TOML boolean or number where the\nreader needs one (`yolo = true`, `max_subagents = 4`); `reasoning_effort`\naccepts the same aliases as `/effort` (#6563). Other dotted writes fail before\nmodifying the file and name the TOML table to edit. For example, set a tools\ntimeout in the file as:\n\n```toml\n[tools]\nuser_input_timeout_seconds = 0\n```\n\n`codewhale config doctor` checks credential presence and endpoint shape, and\nwarns about each config.toml root key that nothing reads: a settings.toml key\nleft in config.toml is named as misplaced, and any other unread key gets a\ndid-you-mean. Keys read by any runtime reader are not reported. The warnings do\nnot fail the check, and a clean result does not validate every runtime setting's\nvalue (#6083, #6563).\n\n## Constitution, project instructions, and repo authority\n\nCodewhale has several instruction surfaces. They are deliberately separate so a\npersonal constitution, repo policy, project instructions, and runtime security\ncontrols do not blur together.\n\n- **Bundled global Constitution** — the compiled base law in the binary. It is\n the default floor for every session.\n- **User-global constitution** — the normal guided setup output. Manage it with\n `/constitution` or `/setup`; Codewhale stores structured data at\n `$CODEWHALE_HOME/constitution.json` (default `~/.codewhale/constitution.json`)\n and renders it into a separate `<codewhale_user_constitution>` prose block.\n This can express preferences and stop conditions, but it does not change\n runtime approval policy, sandbox, shell, network, trust, or MCP permissions.\n- **Repo-local constitution** — optional project policy in\n `.codewhale/constitution.json`, described below.\n- **`AGENTS.md`** — cross-agent **project instructions** (prose). This is the\n canonical file for \"how should an agent work in this repo.\"Run`/init`to\nscaffoldone.`CLAUDE.md`and`.claude/instructions.md`arereadas\ncompatibilityfallbacks.\n-**Memoryandhandoffs**—recalledstate.Useful,butlowerauthoritythan\nconstitutionsandprojectinstructions.\n\n###Managingtheuser-globalconstitution(`/setup`and`/constitution`)\n\nThebundled**workingagreement**isthesafedefaultandnolongeraddsa\nrequiredfirst-runscreen.Customizeitlaterthrough`/constitution`orthe\nprogressive`/setup`guide.Provider/modelreadiness,workspacetrust,and\nruntimeposturestayseparatefromthisguidance.\n\nOnthe**Workingagreement**(constitution)step:\n\n-**`1`–`6`**tunetheguideddraft.**`G`**previewsit,and**`G`**again\nratifiesandsavesafreshstructured`constitution.json`.\n-**`A`**(shownonlywhenaproviderisconfigured)asksyourfirstconfigured\nmodeltodrafttheconstitution.Draftingis**not**saving:thedraftis\nrenderedthroughthesamepreviewandyoustillpress**`G`**toratify\nbeforeanythingpersists.\n-**`K`**keepsyourexistingloadedconstitutionunchanged(shownonlywhena\nvalidfileisalreadypresent).\n-**`U`**(or`/coLine truncated
"content":"# Configuration\n\ncodewhale reads configuration from a TOML file plus environment variables.\nAt process startup it may also load literal built-in-provider credentials from\na workspace-local `.env` file. Use the tracked `.env.example` as the template;\ncopy it to `.env`, then add only credential values.\n\nA workspace is not configuration authority. Codewhale therefore ignores\nconfig/profile/home paths, provider/model/base-URL routing, MCP/plugin state,\napproval/sandbox/shell posture, executable paths, runtime settings, and every\nother non-credential `.env` entry. Variable expansion is rejected so a\nrepository cannot substitute an ambient secret into a credential value. Use\n`config.toml`, CLI flags, or values exported by the launching shell for those\nexplicit control-plane settings. `.env` is read from a stable regular-file\nhandle, is capped at 1 MiB, and symbolic links, reparse points, and multiply\nlinked files are rejected.\n\n## Reading and checking configuration from the CLI\n\n`codewhale config get <key>` reads scalar keys, whole tables such as `tools`,\nand nested paths such as `tools.user_input_timeout_seconds`. Displayed tables\nand nested values apply the same recursive credential redaction as `config dump`.\n\n`config set` supports its named scalar keys and the provider, route, and\nnotification commands. It refuses a key that nothing reads and suggests the\nnearest real key (`config set calm_mod on` names `calm_mode`). A settings.toml\nkey such as `calm_mode` or `tool_collapse` is validated and written to the\nuser-global settings.toml, not config.toml; `config get` reads it back from\nthere even when an old config.toml copy (which nothing reads) is still present,\nand names that copy so you can `config unset` it. Settings keys have no project\nscope, so `--project` refuses them. A config.toml key is checked against the\ntype its reader expects and stored as a TOML boolean or number where the\nreader needs one (`yolo = true`, `max_subagents = 4`); `reasoning_effort`\naccepts the same aliases as `/effort` (#6563). Other dotted writes fail before\nmodifying the file and name the TOML table to edit. For example, set a tools\ntimeout in the file as:\n\n```toml\n[tools]\nuser_input_timeout_seconds = 0\n```\n\n`codewhale config doctor` checks credential presence and endpoint shape, and\nwarns about each config.toml root key that nothing reads: a settings.toml key\nleft in config.toml is named as misplaced, and any other unread key gets a\ndid-you-mean. Keys read by any runtime reader are not reported. The warnings do\nnot fail the check, and a clean result does not validate every runtime setting's\nvalue (#6083, #6563).\n\n## Constitution, project instructions, and repo authority\n\nCodewhale has several instruction surfaces. They are deliberately separate so a\npersonal constitution, repo policy, project instructions, and runtime security\ncontrols do not blur together.\n\n- **Bundled global Constitution** — the compiled base law in the binary. It is\n the default floor for every session.\n- **User-global constitution** — the normal guided setup output. Manage it with\n `/constitution` or `/setup`; Codewhale stores structured data at\n `$CODEWHALE_HOME/constitution.json` (default `~/.codewhale/constitution.json`)\n and renders it into a separate `<codewhale_user_constitution>` prose block.\n This can express preferences and stop conditions, but it does not change\n runtime approval policy, sandbox, shell, network, trust, or MCP permissions.\n- **Repo-local constitution** — optional project policy in\n `.codewhale/constitution.json`, described below.\n- **`AGENTS.md`** — cross-agent **project instructions** (prose). This is the\n canonical file for \"how should an agent work in this repo.\"Run`/init`to\nscaffoldone.`CLAUDE.md`and`.claude/instructions.md`arereadas\ncompatibilityfallbacks.\n-**Memoryandhandoffs**—recalledstate.Useful,butlowerauthoritythan\nconstitutionsandprojectinstructions.\n\n###Managingtheuser-globalconstitution(`/setup`and`/constitution`)\n\nThebundled**workingagreement**isthesafedefaultandnolongeraddsa\nrequiredfirst-runscreen.Customizeitlaterthrough`/constitution`orthe\nprogressive`/setup`guide.Provider/modelreadiness,workspacetrust,and\nruntimeposturestayseparatefromthisguidance.\n\nOnthe**Workingagreement**(constitution)step:\n\n-**`1`–`6`**tunetheguideddraft.**`G`**previewsit,and**`G`**again\nratifiesandsavesafreshstructured`constitution.json`.\n-**`A`**(shownonlywhenaproviderisconfigured)asksyourfirstconfigured\nmodeltodrafttheconstitution.Draftingis**not**saving:thedraftis\nrenderedthroughthesamepreviewandyoustillpress**`G`**toratify\nbeforeanythingpersists.\n-**`K`**keepsyourexistingloadedconstitutionunchanged(shownonlywhena\nvalidfileisalreadypresent).\n-**`U`**(or`/coLine truncated
"content":"# Configuration\n\ncodewhale reads configuration from a TOML file plus environment variables.\nAt process startup it may also load literal built-in-provider credentials from\na workspace-local `.env` file. Use the tracked `.env.example` as the template;\ncopy it to `.env`, then add only credential values.\n\nA workspace is not configuration authority. Codewhale therefore ignores\nconfig/profile/home paths, provider/model/base-URL routing, MCP/plugin state,\napproval/sandbox/shell posture, executable paths, runtime settings, and every\nother non-credential `.env` entry. Variable expansion is rejected so a\nrepository cannot substitute an ambient secret into a credential value. Use\n`config.toml`, CLI flags, or values exported by the launching shell for those\nexplicit control-plane settings. `.env` is read from a stable regular-file\nhandle, is capped at 1 MiB, and symbolic links, reparse points, and multiply\nlinked files are rejected.\n\n## Reading and checking configuration from the CLI\n\n`codewhale config get <key>` reads scalar keys, whole tables such as `tools`,\nand nested paths such as `tools.user_input_timeout_seconds`. Displayed tables\nand nested values apply the same recursive credential redaction as `config dump`.\n\n`config set` supports its named scalar keys and the provider, route, and\nnotification commands. It refuses a key that nothing reads and suggests the\nnearest real key (`config set calm_mod on` names `calm_mode`). A settings.toml\nkey such as `calm_mode` or `tool_collapse` is validated and written to the\nuser-global settings.toml, not config.toml; `config get` reads it back from\nthere even when an old config.toml copy (which nothing reads) is still present,\nand names that copy so you can `config unset` it. Settings keys have no project\nscope, so `--project` refuses them. A config.toml key is checked against the\ntype its reader expects and stored as a TOML boolean or number where the\nreader needs one (`yolo = true`, `max_subagents = 4`); `reasoning_effort`\naccepts the same aliases as `/effort` (#6563). Other dotted writes fail before\nmodifying the file and name the TOML table to edit. For example, set a tools\ntimeout in the file as:\n\n```toml\n[tools]\nuser_input_timeout_seconds = 0\n```\n\n`codewhale config doctor` checks credential presence and endpoint shape, and\nwarns about each config.toml root key that nothing reads: a settings.toml key\nleft in config.toml is named as misplaced, and any other unread key gets a\ndid-you-mean. Keys read by any runtime reader are not reported. The warnings do\nnot fail the check, and a clean result does not validate every runtime setting's\nvalue (#6083, #6563).\n\n## Constitution, project instructions, and repo authority\n\nCodewhale has several instruction surfaces. They are deliberately separate so a\npersonal constitution, repo policy, project instructions, and runtime security\ncontrols do not blur together.\n\n- **Bundled global Constitution** — the compiled base law in the binary. It is\n the default floor for every session.\n- **User-global constitution** — the normal guided setup output. Manage it with\n `/constitution` or `/setup`; Codewhale stores structured data at\n `$CODEWHALE_HOME/constitution.json` (default `~/.codewhale/constitution.json`)\n and renders it into a separate `<codewhale_user_constitution>` prose block.\n This can express preferences and stop conditions, but it does not change\n runtime approval policy, sandbox, shell, network, trust, or MCP permissions.\n- **Repo-local constitution** — optional project policy in\n `.codewhale/constitution.json`, described below.\n- **`AGENTS.md`** — cross-agent **project instructions** (prose). This is the\n canonical file for \"how should an agent work in this repo.\"Run`/init`to\nscaffoldone.`CLAUDE.md`and`.claude/instructions.md`arereadas\ncompatibilityfallbacks.\n-**Memoryandhandoffs**—recalledstate.Useful,butlowerauthoritythan\nconstitutionsandprojectinstructions.\n\n###Managingtheuser-globalconstitution(`/setup`and`/constitution`)\n\nThebundled**workingagreement**isthesafedefaultandnolongeraddsa\nrequiredfirst-runscreen.Customizeitlaterthrough`/constitution`orthe\nprogressive`/setup`guide.Provider/modelreadiness,workspacetrust,and\nruntimeposturestayseparatefromthisguidance.\n\nOnthe**Workingagreement**(constitution)step:\n\n-**`1`–`6`**tunetheguideddraft.**`G`**previewsit,and**`G`**again\nratifiesandsavesafreshstructured`constitution.json`.\n-**`A`**(shownonlywhenaproviderisconfigured)asksyourfirstconfigured\nmodeltodrafttheconstitution.Draftingis**not**saving:thedraftis\nrenderedthroughthesamepreviewandyoustillpress**`G`**toratify\nbeforeanythingpersists.\n-**`K`**keepsyourexistingloadedconstitutionunchanged(shownonlywhena\nvalidfileisalreadypresent).\n-**`U`**(or`/coLine truncated
"content":"# Configuration\n\ncodewhale reads configuration from a TOML file plus environment variables.\nAt process startup it may also load literal built-in-provider credentials from\na workspace-local `.env` file. Use the tracked `.env.example` as the template;\ncopy it to `.env`, then add only credential values.\n\nA workspace is not configuration authority. Codewhale therefore ignores\nconfig/profile/home paths, provider/model/base-URL routing, MCP/plugin state,\napproval/sandbox/shell posture, executable paths, runtime settings, and every\nother non-credential `.env` entry. Variable expansion is rejected so a\nrepository cannot substitute an ambient secret into a credential value. Use\n`config.toml`, CLI flags, or values exported by the launching shell for those\nexplicit control-plane settings. `.env` is read from a stable regular-file\nhandle, is capped at 1 MiB, and symbolic links, reparse points, and multiply\nlinked files are rejected.\n\n## Reading and checking configuration from the CLI\n\n`codewhale config get <key>` reads scalar keys, whole tables such as `tools`,\nand nested paths such as `tools.user_input_timeout_seconds`. Displayed tables\nand nested values apply the same recursive credential redaction as `config dump`.\n\n`config set` supports its named scalar keys and the provider, route, and\nnotification commands. It refuses a key that nothing reads and suggests the\nnearest real key (`config set calm_mod on` names `calm_mode`). A settings.toml\nkey such as `calm_mode` or `tool_collapse` is validated and written to the\nuser-global settings.toml, not config.toml; `config get` reads it back from\nthere even when an old config.toml copy (which nothing reads) is still present,\nand names that copy so you can `config unset` it. Settings keys have no project\nscope, so `--project` refuses them. A config.toml key is checked against the\ntype its reader expects and stored as a TOML boolean or number where the\nreader needs one (`yolo = true`, `max_subagents = 4`); `reasoning_effort`\naccepts the same aliases as `/effort` (#6563). Other dotted writes fail before\nmodifying the file and name the TOML table to edit. For example, set a tools\ntimeout in the file as:\n\n```toml\n[tools]\nuser_input_timeout_seconds = 0\n```\n\n`codewhale config doctor` checks credential presence and endpoint shape, and\nwarns about each config.toml root key that nothing reads: a settings.toml key\nleft in config.toml is named as misplaced, and any other unread key gets a\ndid-you-mean. Keys read by any runtime reader are not reported. The warnings do\nnot fail the check, and a clean result does not validate every runtime setting's\nvalue (#6083, #6563).\n\n## Constitution, project instructions, and repo authority\n\nCodewhale has several instruction surfaces. They are deliberately separate so a\npersonal constitution, repo policy, project instructions, and runtime security\ncontrols do not blur together.\n\n- **Bundled global Constitution** — the compiled base law in the binary. It is\n the default floor for every session.\n- **User-global constitution** — the normal guided setup output. Manage it with\n `/constitution` or `/setup`; Codewhale stores structured data at\n `$CODEWHALE_HOME/constitution.json` (default `~/.codewhale/constitution.json`)\n and renders it into a separate `<codewhale_user_constitution>` prose block.\n This can express preferences and stop conditions, but it does not change\n runtime approval policy, sandbox, shell, network, trust, or MCP permissions.\n- **Repo-local constitution** — optional project policy in\n `.codewhale/constitution.json`, described below.\n- **`AGENTS.md`** — cross-agent **project instructions** (prose). This is the\n canonical file for \"how should an agent work in this repo.\"Run`/init`to\nscaffoldone.`CLAUDE.md`and`.claude/instructions.md`arereadas\ncompatibilityfallbacks.\n-**Memoryandhandoffs**—recalledstate.Useful,butlowerauthoritythan\nconstitutionsandprojectinstructions.\n\n###Managingtheuser-globalconstitution(`/setup`and`/constitution`)\n\nThebundled**workingagreement**isthesafedefaultandnolongeraddsa\nrequiredfirst-runscreen.Customizeitlaterthrough`/constitution`orthe\nprogressive`/setup`guide.Provider/modelreadiness,workspacetrust,and\nruntimeposturestayseparatefromthisguidance.\n\nOnthe**Workingagreement**(constitution)step:\n\n-**`1`–`6`**tunetheguideddraft.**`G`**previewsit,and**`G`**again\nratifiesandsavesafreshstructured`constitution.json`.\n-**`A`**(shownonlywhenaproviderisconfigured)asksyourfirstconfigured\nmodeltodrafttheconstitution.Draftingis**not**saving:thedraftis\nrenderedthroughthesamepreviewandyoustillpress**`G`**toratify\nbeforeanythingpersists.\n-**`K`**keepsyourexistingloadedconstitutionunchanged(shownonlywhena\nvalidfileisalreadypresent).\n-**`U`**(or`/coLine truncated
"content":"# Configuration\n\ncodewhale reads configuration from a TOML file plus environment variables.\nAt process startup it may also load literal built-in-provider credentials from\na workspace-local `.env` file. Use the tracked `.env.example` as the template;\ncopy it to `.env`, then add only credential values.\n\nA workspace is not configuration authority. Codewhale therefore ignores\nconfig/profile/home paths, provider/model/base-URL routing, MCP/plugin state,\napproval/sandbox/shell posture, executable paths, runtime settings, and every\nother non-credential `.env` entry. Variable expansion is rejected so a\nrepository cannot substitute an ambient secret into a credential value. Use\n`config.toml`, CLI flags, or values exported by the launching shell for those\nexplicit control-plane settings. `.env` is read from a stable regular-file\nhandle, is capped at 1 MiB, and symbolic links, reparse points, and multiply\nlinked files are rejected.\n\n## Reading and checking configuration from the CLI\n\n`codewhale config get <key>` reads scalar keys, whole tables such as `tools`,\nand nested paths such as `tools.user_input_timeout_seconds`. Displayed tables\nand nested values apply the same recursive credential redaction as `config dump`.\n\n`config set` supports its named scalar keys and the provider, route, and\nnotification commands. It refuses a key that nothing reads and suggests the\nnearest real key (`config set calm_mod on` names `calm_mode`). A settings.toml\nkey such as `calm_mode` or `tool_collapse` is validated and written to the\nuser-global settings.toml, not config.toml; `config get` reads it back from\nthere even when an old config.toml copy (which nothing reads) is still present,\nand names that copy so you can `config unset` it. Settings keys have no project\nscope, so `--project` refuses them. A config.toml key is checked against the\ntype its reader expects and stored as a TOML boolean or number where the\nreader needs one (`yolo = true`, `max_subagents = 4`); `reasoning_effort`\naccepts the same aliases as `/effort` (#6563). Other dotted writes fail before\nmodifying the file and name the TOML table to edit. For example, set a tools\ntimeout in the file as:\n\n```toml\n[tools]\nuser_input_timeout_seconds = 0\n```\n\n`codewhale config doctor` checks credential presence and endpoint shape, and\nwarns about each config.toml root key that nothing reads: a settings.toml key\nleft in config.toml is named as misplaced, and any other unread key gets a\ndid-you-mean. Keys read by any runtime reader are not reported. The warnings do\nnot fail the check, and a clean result does not validate every runtime setting's\nvalue (#6083, #6563).\n\n## Constitution, project instructions, and repo authority\n\nCodewhale has several instruction surfaces. They are deliberately separate so a\npersonal constitution, repo policy, project instructions, and runtime security\ncontrols do not blur together.\n\n- **Bundled global Constitution** — the compiled base law in the binary. It is\n the default floor for every session.\n- **User-global constitution** — the normal guided setup output. Manage it with\n `/constitution` or `/setup`; Codewhale stores structured data at\n `$CODEWHALE_HOME/constitution.json` (default `~/.codewhale/constitution.json`)\n and renders it into a separate `<codewhale_user_constitution>` prose block.\n This can express preferences and stop conditions, but it does not change\n runtime approval policy, sandbox, shell, network, trust, or MCP permissions.\n- **Repo-local constitution** — optional project policy in\n `.codewhale/constitution.json`, described below.\n- **`AGENTS.md`** — cross-agent **project instructions** (prose). This is the\n canonical file for \"how should an agent work in this repo.\"Run`/init`to\nscaffoldone.`CLAUDE.md`and`.claude/instructions.md`arereadas\ncompatibilityfallbacks.\n-**Memoryandhandoffs**—recalledstate.Useful,butlowerauthoritythan\nconstitutionsandprojectinstructions.\n\n###Managingtheuser-globalconstitution(`/setup`and`/constitution`)\n\nThebundled**workingagreement**isthesafedefaultandnolongeraddsa\nrequiredfirst-runscreen.Customizeitlaterthrough`/constitution`orthe\nprogressive`/setup`guide.Provider/modelreadiness,workspacetrust,and\nruntimeposturestayseparatefromthisguidance.\n\nOnthe**Workingagreement**(constitution)step:\n\n-**`1`–`6`**tunetheguideddraft.**`G`**previewsit,and**`G`**again\nratifiesandsavesafreshstructured`constitution.json`.\n-**`A`**(shownonlywhenaproviderisconfigured)asksyourfirstconfigured\nmodeltodrafttheconstitution.Draftingis**not**saving:thedraftis\nrenderedthroughthesamepreviewandyoustillpress**`G`**toratify\nbeforeanythingpersists.\n-**`K`**keepsyourexistingloadedconstitutionunchanged(shownonlywhena\nvalidfileisalreadypresent).\n-**`U`**(or`/coLine truncated
"content":"# Configuration\n\ncodewhale reads configuration from a TOML file plus environment variables.\nAt process startup it may also load literal built-in-provider credentials from\na workspace-local `.env` file. Use the tracked `.env.example` as the template;\ncopy it to `.env`, then add only credential values.\n\nA workspace is not configuration authority. Codewhale therefore ignores\nconfig/profile/home paths, provider/model/base-URL routing, MCP/plugin state,\napproval/sandbox/shell posture, executable paths, runtime settings, and every\nother non-credential `.env` entry. Variable expansion is rejected so a\nrepository cannot substitute an ambient secret into a credential value. Use\n`config.toml`, CLI flags, or values exported by the launching shell for those\nexplicit control-plane settings. `.env` is read from a stable regular-file\nhandle, is capped at 1 MiB, and symbolic links, reparse points, and multiply\nlinked files are rejected.\n\n## Reading and checking configuration from the CLI\n\n`codewhale config get <key>` reads scalar keys, whole tables such as `tools`,\nand nested paths such as `tools.user_input_timeout_seconds`. Displayed tables\nand nested values apply the same recursive credential redaction as `config dump`.\n\n`config set` supports its named scalar keys and the provider, route, and\nnotification commands. It refuses a key that nothing reads and suggests the\nnearest real key (`config set calm_mod on` names `calm_mode`). A settings.toml\nkey such as `calm_mode` or `tool_collapse` is validated and written to the\nuser-global settings.toml, not config.toml; `config get` reads it back from\nthere even when an old config.toml copy (which nothing reads) is still present,\nand names that copy so you can `config unset` it. Settings keys have no project\nscope, so `--project` refuses them. A config.toml key is checked against the\ntype its reader expects and stored as a TOML boolean or number where the\nreader needs one (`yolo = true`, `max_subagents = 4`); `reasoning_effort`\naccepts the same aliases as `/effort` (#6563). Other dotted writes fail before\nmodifying the file and name the TOML table to edit. For example, set a tools\ntimeout in the file as:\n\n```toml\n[tools]\nuser_input_timeout_seconds = 0\n```\n\n`codewhale config doctor` checks credential presence and endpoint shape, and\nwarns about each config.toml root key that nothing reads: a settings.toml key\nleft in config.toml is named as misplaced, and any other unread key gets a\ndid-you-mean. Keys read by any runtime reader are not reported. The warnings do\nnot fail the check, and a clean result does not validate every runtime setting's\nvalue (#6083, #6563).\n\n## Constitution, project instructions, and repo authority\n\nCodewhale has several instruction surfaces. They are deliberately separate so a\npersonal constitution, repo policy, project instructions, and runtime security\ncontrols do not blur together.\n\n- **Bundled global Constitution** — the compiled base law in the binary. It is\n the default floor for every session.\n- **User-global constitution** — the normal guided setup output. Manage it with\n `/constitution` or `/setup`; Codewhale stores structured data at\n `$CODEWHALE_HOME/constitution.json` (default `~/.codewhale/constitution.json`)\n and renders it into a separate `<codewhale_user_constitution>` prose block.\n This can express preferences and stop conditions, but it does not change\n runtime approval policy, sandbox, shell, network, trust, or MCP permissions.\n- **Repo-local constitution** — optional project policy in\n `.codewhale/constitution.json`, described below.\n- **`AGENTS.md`** — cross-agent **project instructions** (prose). This is the\n canonical file for \"how should an agent work in this repo.\"Run`/init`to\nscaffoldone.`CLAUDE.md`and`.claude/instructions.md`arereadas\ncompatibilityfallbacks.\n-**Memoryandhandoffs**—recalledstate.Useful,butlowerauthoritythan\nconstitutionsandprojectinstructions.\n\n###Managingtheuser-globalconstitution(`/setup`and`/constitution`)\n\nThebundled**workingagreement**isthesafedefaultandnolongeraddsa\nrequiredfirst-runscreen.Customizeitlaterthrough`/constitution`orthe\nprogressive`/setup`guide.Provider/modelreadiness,workspacetrust,and\nruntimeposturestayseparatefromthisguidance.\n\nOnthe**Workingagreement**(constitution)step:\n\n-**`1`–`6`**tunetheguideddraft.**`G`**previewsit,and**`G`**again\nratifiesandsavesafreshstructured`constitution.json`.\n-**`A`**(shownonlywhenaproviderisconfigured)asksyourfirstconfigured\nmodeltodrafttheconstitution.Draftingis**not**saving:thedraftis\nrenderedthroughthesamepreviewandyoustillpress**`G`**toratify\nbeforeanythingpersists.\n-**`K`**keepsyourexistingloadedconstitutionunchanged(shownonlywhena\nvalidfileisalreadypresent).\n-**`U`**(or`/coLine truncated
"content":"# Configuration\n\ncodewhale reads configuration from a TOML file plus environment variables.\nAt process startup it may also load literal built-in-provider credentials from\na workspace-local `.env` file. Use the tracked `.env.example` as the template;\ncopy it to `.env`, then add only credential values.\n\nA workspace is not configuration authority. Codewhale therefore ignores\nconfig/profile/home paths, provider/model/base-URL routing, MCP/plugin state,\napproval/sandbox/shell posture, executable paths, runtime settings, and every\nother non-credential `.env` entry. Variable expansion is rejected so a\nrepository cannot substitute an ambient secret into a credential value. Use\n`config.toml`, CLI flags, or values exported by the launching shell for those\nexplicit control-plane settings. `.env` is read from a stable regular-file\nhandle, is capped at 1 MiB, and symbolic links, reparse points, and multiply\nlinked files are rejected.\n\n## Reading and checking configuration from the CLI\n\n`codewhale config get <key>` reads scalar keys, whole tables such as `tools`,\nand nested paths such as `tools.user_input_timeout_seconds`. Displayed tables\nand nested values apply the same recursive credential redaction as `config dump`.\n\n`config set` supports its named scalar keys and the provider, route, and\nnotification commands. It refuses a key that nothing reads and suggests the\nnearest real key (`config set calm_mod on` names `calm_mode`). A settings.toml\nkey such as `calm_mode` or `tool_collapse` is validated and written to the\nuser-global settings.toml, not config.toml; `config get` reads it back from\nthere even when an old config.toml copy (which nothing reads) is still present,\nand names that copy so you can `config unset` it. Settings keys have no project\nscope, so `--project` refuses them. A config.toml key is checked against the\ntype its reader expects and stored as a TOML boolean or number where the\nreader needs one (`yolo = true`, `max_subagents = 4`); `reasoning_effort`\naccepts the same aliases as `/effort` (#6563). Other dotted writes fail before\nmodifying the file and name the TOML table to edit. For example, set a tools\ntimeout in the file as:\n\n```toml\n[tools]\nuser_input_timeout_seconds = 0\n```\n\n`codewhale config doctor` checks credential presence and endpoint shape, and\nwarns about each config.toml root key that nothing reads: a settings.toml key\nleft in config.toml is named as misplaced, and any other unread key gets a\ndid-you-mean. Keys read by any runtime reader are not reported. The warnings do\nnot fail the check, and a clean result does not validate every runtime setting's\nvalue (#6083, #6563).\n\n## Constitution, project instructions, and repo authority\n\nCodewhale has several instruction surfaces. They are deliberately separate so a\npersonal constitution, repo policy, project instructions, and runtime security\ncontrols do not blur together.\n\n- **Bundled global Constitution** — the compiled base law in the binary. It is\n the default floor for every session.\n- **User-global constitution** — the normal guided setup output. Manage it with\n `/constitution` or `/setup`; Codewhale stores structured data at\n `$CODEWHALE_HOME/constitution.json` (default `~/.codewhale/constitution.json`)\n and renders it into a separate `<codewhale_user_constitution>` prose block.\n This can express preferences and stop conditions, but it does not change\n runtime approval policy, sandbox, shell, network, trust, or MCP permissions.\n- **Repo-local constitution** — optional project policy in\n `.codewhale/constitution.json`, described below.\n- **`AGENTS.md`** — cross-agent **project instructions** (prose). This is the\n canonical file for \"how should an agent work in this repo.\"Run`/init`to\nscaffoldone.`CLAUDE.md`and`.claude/instructions.md`arereadas\ncompatibilityfallbacks.\n-**Memoryandhandoffs**—recalledstate.Useful,butlowerauthoritythan\nconstitutionsandprojectinstructions.\n\n###Managingtheuser-globalconstitution(`/setup`and`/constitution`)\n\nThebundled**workingagreement**isthesafedefaultandnolongeraddsa\nrequiredfirst-runscreen.Customizeitlaterthrough`/constitution`orthe\nprogressive`/setup`guide.Provider/modelreadiness,workspacetrust,and\nruntimeposturestayseparatefromthisguidance.\n\nOnthe**Workingagreement**(constitution)step:\n\n-**`1`–`6`**tunetheguideddraft.**`G`**previewsit,and**`G`**again\nratifiesandsavesafreshstructured`constitution.json`.\n-**`A`**(shownonlywhenaproviderisconfigured)asksyourfirstconfigured\nmodeltodrafttheconstitution.Draftingis**not**saving:thedraftis\nrenderedthroughthesamepreviewandyoustillpress**`G`**toratify\nbeforeanythingpersists.\n-**`K`**keepsyourexistingloadedconstitutionunchanged(shownonlywhena\nvalidfileisalreadypresent).\n-**`U`**(or`/coLine truncated
"content":"# Configuration\n\ncodewhale reads configuration from a TOML file plus environment variables.\nAt process startup it may also load literal built-in-provider credentials from\na workspace-local `.env` file. Use the tracked `.env.example` as the template;\ncopy it to `.env`, then add only credential values.\n\nA workspace is not configuration authority. Codewhale therefore ignores\nconfig/profile/home paths, provider/model/base-URL routing, MCP/plugin state,\napproval/sandbox/shell posture, executable paths, runtime settings, and every\nother non-credential `.env` entry. Variable expansion is rejected so a\nrepository cannot substitute an ambient secret into a credential value. Use\n`config.toml`, CLI flags, or values exported by the launching shell for those\nexplicit control-plane settings. `.env` is read from a stable regular-file\nhandle, is capped at 1 MiB, and symbolic links, reparse points, and multiply\nlinked files are rejected.\n\n## Reading and checking configuration from the CLI\n\n`codewhale config get <key>` reads scalar keys, whole tables such as `tools`,\nand nested paths such as `tools.user_input_timeout_seconds`. Displayed tables\nand nested values apply the same recursive credential redaction as `config dump`.\n\n`config set` supports its named scalar keys and the provider, route, and\nnotification commands. It refuses a key that nothing reads and suggests the\nnearest real key (`config set calm_mod on` names `calm_mode`). A settings.toml\nkey such as `calm_mode` or `tool_collapse` is validated and written to the\nuser-global settings.toml, not config.toml; `config get` reads it back from\nthere even when an old config.toml copy (which nothing reads) is still present,\nand names that copy so you can `config unset` it. Settings keys have no project\nscope, so `--project` refuses them. A config.toml key is checked against the\ntype its reader expects and stored as a TOML boolean or number where the\nreader needs one (`yolo = true`, `max_subagents = 4`); `reasoning_effort`\naccepts the same aliases as `/effort` (#6563). Other dotted writes fail before\nmodifying the file and name the TOML table to edit. For example, set a tools\ntimeout in the file as:\n\n```toml\n[tools]\nuser_input_timeout_seconds = 0\n```\n\n`codewhale config doctor` checks credential presence and endpoint shape, and\nwarns about each config.toml root key that nothing reads: a settings.toml key\nleft in config.toml is named as misplaced, and any other unread key gets a\ndid-you-mean. Keys read by any runtime reader are not reported. The warnings do\nnot fail the check, and a clean result does not validate every runtime setting's\nvalue (#6083, #6563).\n\n## Constitution, project instructions, and repo authority\n\nCodewhale has several instruction surfaces. They are deliberately separate so a\npersonal constitution, repo policy, project instructions, and runtime security\ncontrols do not blur together.\n\n- **Bundled global Constitution** — the compiled base law in the binary. It is\n the default floor for every session.\n- **User-global constitution** — the normal guided setup output. Manage it with\n `/constitution` or `/setup`; Codewhale stores structured data at\n `$CODEWHALE_HOME/constitution.json` (default `~/.codewhale/constitution.json`)\n and renders it into a separate `<codewhale_user_constitution>` prose block.\n This can express preferences and stop conditions, but it does not change\n runtime approval policy, sandbox, shell, network, trust, or MCP permissions.\n- **Repo-local constitution** — optional project policy in\n `.codewhale/constitution.json`, described below.\n- **`AGENTS.md`** — cross-agent **project instructions** (prose). This is the\n canonical file for \"how should an agent work in this repo.\"Run`/init`to\nscaffoldone.`CLAUDE.md`and`.claude/instructions.md`arereadas\ncompatibilityfallbacks.\n-**Memoryandhandoffs**—recalledstate.Useful,butlowerauthoritythan\nconstitutionsandprojectinstructions.\n\n###Managingtheuser-globalconstitution(`/setup`and`/constitution`)\n\nThebundled**workingagreement**isthesafedefaultandnolongeraddsa\nrequiredfirst-runscreen.Customizeitlaterthrough`/constitution`orthe\nprogressive`/setup`guide.Provider/modelreadiness,workspacetrust,and\nruntimeposturestayseparatefromthisguidance.\n\nOnthe**Workingagreement**(constitution)step:\n\n-**`1`–`6`**tunetheguideddraft.**`G`**previewsit,and**`G`**again\nratifiesandsavesafreshstructured`constitution.json`.\n-**`A`**(shownonlywhenaproviderisconfigured)asksyourfirstconfigured\nmodeltodrafttheconstitution.Draftingis**not**saving:thedraftis\nrenderedthroughthesamepreviewandyoustillpress**`G`**toratify\nbeforeanythingpersists.\n-**`K`**keepsyourexistingloadedconstitutionunchanged(shownonlywhena\nvalidfileisalreadypresent).\n-**`U`**(or`/coLine truncated
"content":"# Configuration\n\ncodewhale reads configuration from a TOML file plus environment variables.\nAt process startup it may also load literal built-in-provider credentials from\na workspace-local `.env` file. Use the tracked `.env.example` as the template;\ncopy it to `.env`, then add only credential values.\n\nA workspace is not configuration authority. Codewhale therefore ignores\nconfig/profile/home paths, provider/model/base-URL routing, MCP/plugin state,\napproval/sandbox/shell posture, executable paths, runtime settings, and every\nother non-credential `.env` entry. Variable expansion is rejected so a\nrepository cannot substitute an ambient secret into a credential value. Use\n`config.toml`, CLI flags, or values exported by the launching shell for those\nexplicit control-plane settings. `.env` is read from a stable regular-file\nhandle, is capped at 1 MiB, and symbolic links, reparse points, and multiply\nlinked files are rejected.\n\n## Reading and checking configuration from the CLI\n\n`codewhale config get <key>` reads scalar keys, whole tables such as `tools`,\nand nested paths such as `tools.user_input_timeout_seconds`. Displayed tables\nand nested values apply the same recursive credential redaction as `config dump`.\n\n`config set` supports its named scalar keys and the provider, route, and\nnotification commands. It refuses a key that nothing reads and suggests the\nnearest real key (`config set calm_mod on` names `calm_mode`). A settings.toml\nkey such as `calm_mode` or `tool_collapse` is validated and written to the\nuser-global settings.toml, not config.toml; `config get` reads it back from\nthere even when an old config.toml copy (which nothing reads) is still present,\nand names that copy so you can `config unset` it. Settings keys have no project\nscope, so `--project` refuses them. A config.toml key is checked against the\ntype its reader expects and stored as a TOML boolean or number where the\nreader needs one (`yolo = true`, `max_subagents = 4`); `reasoning_effort`\naccepts the same aliases as `/effort` (#6563). Other dotted writes fail before\nmodifying the file and name the TOML table to edit. For example, set a tools\ntimeout in the file as:\n\n```toml\n[tools]\nuser_input_timeout_seconds = 0\n```\n\n`codewhale config doctor` checks credential presence and endpoint shape, and\nwarns about each config.toml root key that nothing reads: a settings.toml key\nleft in config.toml is named as misplaced, and any other unread key gets a\ndid-you-mean. Keys read by any runtime reader are not reported. The warnings do\nnot fail the check, and a clean result does not validate every runtime setting's\nvalue (#6083, #6563).\n\n## Constitution, project instructions, and repo authority\n\nCodewhale has several instruction surfaces. They are deliberately separate so a\npersonal constitution, repo policy, project instructions, and runtime security\ncontrols do not blur together.\n\n- **Bundled global Constitution** — the compiled base law in the binary. It is\n the default floor for every session.\n- **User-global constitution** — the normal guided setup output. Manage it with\n `/constitution` or `/setup`; Codewhale stores structured data at\n `$CODEWHALE_HOME/constitution.json` (default `~/.codewhale/constitution.json`)\n and renders it into a separate `<codewhale_user_constitution>` prose block.\n This can express preferences and stop conditions, but it does not change\n runtime approval policy, sandbox, shell, network, trust, or MCP permissions.\n- **Repo-local constitution** — optional project policy in\n `.codewhale/constitution.json`, described below.\n- **`AGENTS.md`** — cross-agent **project instructions** (prose). This is the\n canonical file for \"how should an agent work in this repo.\"Run`/init`to\nscaffoldone.`CLAUDE.md`and`.claude/instructions.md`arereadas\ncompatibilityfallbacks.\n-**Memoryandhandoffs**—recalledstate.Useful,butlowerauthoritythan\nconstitutionsandprojectinstructions.\n\n###Managingtheuser-globalconstitution(`/setup`and`/constitution`)\n\nThebundled**workingagreement**isthesafedefaultandnolongeraddsa\nrequiredfirst-runscreen.Customizeitlaterthrough`/constitution`orthe\nprogressive`/setup`guide.Provider/modelreadiness,workspacetrust,and\nruntimeposturestayseparatefromthisguidance.\n\nOnthe**Workingagreement**(constitution)step:\n\n-**`1`–`6`**tunetheguideddraft.**`G`**previewsit,and**`G`**again\nratifiesandsavesafreshstructured`constitution.json`.\n-**`A`**(shownonlywhenaproviderisconfigured)asksyourfirstconfigured\nmodeltodrafttheconstitution.Draftingis**not**saving:thedraftis\nrenderedthroughthesamepreviewandyoustillpress**`G`**toratify\nbeforeanythingpersists.\n-**`K`**keepsyourexistingloadedconstitutionunchanged(shownonlywhena\nvalidfileisalreadypresent).\n-**`U`**(or`/coLine truncated
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.