mirror of
https://github.com/codewhale-hq/Codewhale.git
synced 2026-11-08 01:48:20 -10:00
fix(authority): bound the credential-upload scan and close its stdin, .pub and wget gaps (CW-7236)
Fix-up for53ae15645cafter review. All six review findings are addressed. What - Performance: shell_command_credential_uploads returns at once unless the text names curl or wget (names_upload_program: one linear byte pass, ASCII case-folded like command_word, skipping ' " and \ so c'u'rl and CURL still count). Above 64 KiB (CREDENTIAL_SCAN_MAX_BYTES) a text that names curl/wget is not parsed and fails closed with the marker. Before, every exec_shell stdin, interact payload and verifier row went through command_invocations (O(words^2) clones per segment) two or more times per call and on every approval-card render frame. - Stdin fed from a secret: fed_from_credential is split into fed_from_credential_file (the old check) and fed_from_secret_variable: an argv headed by echo, printf or a <<< word with a secret-named variable, or printenv with a sensitive key name. The second applies only to body values, not -H @-, so a header read from stdin stays a header. The command is not scanned for $VAR wholesale, so -H "Authorization: Bearer $X" -d @- with a non-secret body stays unlabelled. - .pub exemption per path: names_credential_file splits the text on , { } | & > into path alternatives first and applies the last-component-.pub exemption to each, so -T "{.env,x.pub}", -F "[email protected],x.pub" and -T ~/.ssh/id_rsa{,.pub} are held, and cat ~/.netrc|curl ... is read as two words. - The <unparsed> marker is a named constant (UNPARSED_CREDENTIAL_UPLOAD). approval_summary drops it, so an unreadable call keeps its ordinary localized summary instead of "Upload credentials (`<unparsed>`)". The marker still counts in the audit credential_uploads field and still trips the safety gate. - wget long options: an unambiguous prefix of at least 6 characters of post-data, body-data, post-file or body-file is matched. GNU Wget 1.25.0 here accepts --post-d, --post-f, --body-d and --body-f, and rejects --post= and --post-= as ambiguous (exit 2). - Docs: CHANGELOG [Unreleased] (plus the crates/tui mirror via sync-changelog.sh), CONFIGURATION and RUNTIME_API (en, zh_hans) now say what the scan covers: stdin fed from a credential file, a secret-named variable or env/printenv, and holds for a curl/wget over 64 KiB or nested too deeply. web/data/agent-docs.generated.json regenerated by `npm run prebuild`. Verification (source: HEAD856eefaa53plus this diff; debug build target/debug/codewhale built after the last Rust edit) - cargo fmt --all -- --check: clean. - scripts/dev-cargo.sh clippy -p codewhale-tui --all-targets --all-features --locked -- -D warnings -A clippy::uninlined_format_args -A clippy::too_many_arguments -A clippy::unnecessary_map_or: clean. - scripts/dev-test.sh tui core::authority:: core::engine::tests tools::approval_summary tui::approval: 739 tests run: 739 passed, 14612 skipped. - sync-changelog.sh --check: up to date. scripts/release/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: the first run failed "[check-facts] FAIL - generated agent docs are stale" because of the doc edits. It passes after `npm run prebuild`. - Reviewer perf probe (review7236/perf.py: exec, Bash {command: "wc -w", stdin: "word " * N}, Never, isolated HOME, local stub provider, CODEWHALE_TELEMETRY=0), /usr/bin/time -l: - this debug build, N=10 / 2000 / 8000 / 16000: 2.47 / 2.18 / 2.19 / 2.20 s real; max RSS 577.7 / 580.0 / 580.3 / 580.2 MB; peak footprint 499.4 MB at every N. - installed 0.10.2 release (91dbd4f785), same N: 0.45 / 0.35 / 0.34 / 0.34 s; max RSS 171.3 / 172.0 / 172.1 / 172.3 MB. - Both are flat in N. The debug build's constant of about 2.2 s and 578 MB matches the review's N=2000 figure (2.4 s, 580 MB). The review measured a debug build of53ae15645cat 6.0 s / 1.33 GB for N=8000 and 18.1 s / 4.64 GB for N=16000. - Reviewer runner probes (review7236/runner.py, Never, GITHUB_TOKEN set): R0 -d @.env, R1 echo "$GITHUB_TOKEN" |, R2 printenv GITHUB_TOKEN |, R3 -T "{.env,x.pub}", R4 cat ~/.netrc|curl, R5 wget --post-fi=.env and R6 -F "[email protected],x.pub" each gave action_kind destructive, credential_uploads 1, hold_for_review. The review's run on53ae15645c(review7236/runs) gave credential_uploads 0 and ask_user for each of R1-R6. Extra cases held (1, hold_for_review): <<< "$GITHUB_TOKEN" and <<<"$GITHUB_TOKEN", printf '%s' "$GITHUB_TOKEN" | curl -T -, wget --post-d="$GITHUB_TOKEN", -T ~/.ssh/id_rsa{,.pub}, CURL -d @.env, c'u'rl -d @.env, and command sh with stdin "curl -d @.env ...". Extra cases not held (0, ask_user): echo '{"a":1}' | curl -H "Authorization: Bearer $GITHUB_TOKEN" --data-binary @-, printf 'Authorization: Bearer %s' "$GITHUB_TOKEN" | curl -H @-, printenv HOME |, cat ~/.ssh/id_rsa.pub|curl --data-binary @-, -T ~/.ssh/id_ed25519.pub, wget --post=.env (ambiguous; wget itself refuses it), and the heredoc cat <<EOF | curl --data-binary @- with $GITHUB_TOKEN in the body (a stated limit). - Original acceptance probes (probe/run.py, 18 cases) re-run on this build. Results match53ae15645c: the U+200B, U+202E, ZWNJ and stdin-RLO cases are blocked with ASCII reasons, and Full Access runs them. The -F [email protected] and -d "$GITHUB_TOKEN" cases are held in Ask (denied) and Auto-Review, and still held under a curl allow rule. The Bearer header, plain curl, .pub upload and emoji cases are unlabelled. - TUI in tmux (Ask), debug build: - -F [email protected] card: "Can't be undone Upload credentials (`[email protected]`) with `curl ...`". - sh with stdin "curl -d @.env ...": "Can't be undone Upload credentials (`@.env`) with `curl -sS -d @.env ...`". - The marker cases (sh -c nested 9 deep, and sh with that stdin plus 70 KB of words) read "Can't be undone Run `sh -c ...`" and "Can't be undone Run `sh`". There is no <unparsed> on either card. Audit: destructive, credential_uploads 1, hold_for_review. Not verified / known limits - Residual cost below the cap: a text under 64 KiB that names curl or wget is still parsed by command_invocations, which is quadratic. Measured on this debug build with stdin "curl " + "word " * N under command wc -w: N=4000 3.1 s / 580 MB, N=8000 6.0 s / 1.30 GB, N=12000 10.6 s / 2.73 GB; N=14000 (over 64 KiB) 2.2 s / 576 MB and held. 0.10.2 already paid this cost for command text in shell_params_are_destructive_like. It is new only for stdin and interact payloads that name curl/wget. The real fix is to drop the per-suffix clone in codewhale_execpolicy::command_safety::command_invocations, which is a separate execpolicy slice. - The gate reason for a marker-only hold still reads "credential upload requires durable review: the request body carries a credential file or secret-named variable". The deterministic reasons are English literals, and none was added here. - A TUI card for a command the risk classifier rates benign (wc -w) whose stdin is held shows Routine stakes and offers "Always allow in this repo", because classify_stakes returns early for benign risk. The engine still forces the prompt, and no saved rule answers it. - Not detected: here-documents, $(printenv NAME) or $(env) inside a value, and the existing limits listed in53ae15645c. - No CI, no release build, no Windows run, no desktop or mobile render. Refs CW-7236 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01NBKbhx19BRbZtvWK8rVKjz
This commit is contained in:
1 parent
856eefaa53
commit
7af7549c1e
9 files changed
+127
-67
No files matched your search
+12
-8
@@ -26,16 +26,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- A `curl` or `wget` whose request body uploads a credential is now held by
|
||||
the built-in safety gate. This covers `-d`/`--data*`/`--json`/`-F`/
|
||||
`--url-query`/`-T`/`--upload-file`/`-H @file`/`--post-file`/`--post-data`
|
||||
carrying `.env`, `~/.ssh/id_*` (public `.pub` keys excepted),
|
||||
(and wget's abbreviations of them) carrying `.env`, `~/.ssh/id_*` (public
|
||||
`.pub` keys excepted, judged per file in `{a,b}` and comma lists),
|
||||
`~/.aws/credentials`, `.netrc`, a key file, a secret-named variable such as
|
||||
`$GITHUB_TOKEN` or `$OPENAI_API_KEY`, or a credential piped in on stdin or
|
||||
through command substitution. Ask shows a card headed "Upload credentials
|
||||
(…) with `…`" that a session grant or saved allow rule cannot answer;
|
||||
Auto-Review and Never deny the call. Runtime clients receive the same
|
||||
heading as the approval `summary`. A literal request header
|
||||
`$GITHUB_TOKEN` or `$OPENAI_API_KEY`, or stdin fed from one of those, from
|
||||
`env`/`printenv`, or from `echo`/`printf`/`<<<` of a secret-named variable.
|
||||
A `curl` or `wget` too large (over 64 KiB) or too deeply nested to read is
|
||||
held the same way under its ordinary heading. Ask shows a card headed
|
||||
"Upload credentials (…) with `…`" that a session grant or saved allow rule
|
||||
cannot answer; Auto-Review and Never deny the call. Runtime clients receive
|
||||
the same heading as the approval `summary`. A literal request header
|
||||
(`-H "Authorization: Bearer $TOKEN"`) is not affected, and other upload
|
||||
tools (scp, rsync, nc, httpie, `aws s3 cp`) and secrets inside an ordinary
|
||||
file are not detected. Full Access is unchanged (Refs CW-7236).
|
||||
tools (scp, rsync, nc, httpie, `aws s3 cp`), secrets inside an ordinary
|
||||
file, here-documents and `$(printenv NAME)` inside a value are not
|
||||
detected. Full Access is unchanged (Refs CW-7236).
|
||||
- Switching provider, model route, profile or workspace, or changing plugins,
|
||||
while a `/compact` is running or queued no longer leaves the session stuck.
|
||||
The pass on the replaced engine is stopped and the transcript says "Making
|
||||
|
||||
+12
-8
@@ -26,16 +26,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- A `curl` or `wget` whose request body uploads a credential is now held by
|
||||
the built-in safety gate. This covers `-d`/`--data*`/`--json`/`-F`/
|
||||
`--url-query`/`-T`/`--upload-file`/`-H @file`/`--post-file`/`--post-data`
|
||||
carrying `.env`, `~/.ssh/id_*` (public `.pub` keys excepted),
|
||||
(and wget's abbreviations of them) carrying `.env`, `~/.ssh/id_*` (public
|
||||
`.pub` keys excepted, judged per file in `{a,b}` and comma lists),
|
||||
`~/.aws/credentials`, `.netrc`, a key file, a secret-named variable such as
|
||||
`$GITHUB_TOKEN` or `$OPENAI_API_KEY`, or a credential piped in on stdin or
|
||||
through command substitution. Ask shows a card headed "Upload credentials
|
||||
(…) with `…`" that a session grant or saved allow rule cannot answer;
|
||||
Auto-Review and Never deny the call. Runtime clients receive the same
|
||||
heading as the approval `summary`. A literal request header
|
||||
`$GITHUB_TOKEN` or `$OPENAI_API_KEY`, or stdin fed from one of those, from
|
||||
`env`/`printenv`, or from `echo`/`printf`/`<<<` of a secret-named variable.
|
||||
A `curl` or `wget` too large (over 64 KiB) or too deeply nested to read is
|
||||
held the same way under its ordinary heading. Ask shows a card headed
|
||||
"Upload credentials (…) with `…`" that a session grant or saved allow rule
|
||||
cannot answer; Auto-Review and Never deny the call. Runtime clients receive
|
||||
the same heading as the approval `summary`. A literal request header
|
||||
(`-H "Authorization: Bearer $TOKEN"`) is not affected, and other upload
|
||||
tools (scp, rsync, nc, httpie, `aws s3 cp`) and secrets inside an ordinary
|
||||
file are not detected. Full Access is unchanged (Refs CW-7236).
|
||||
tools (scp, rsync, nc, httpie, `aws s3 cp`), secrets inside an ordinary
|
||||
file, here-documents and `$(printenv NAME)` inside a value are not
|
||||
detected. Full Access is unchanged (Refs CW-7236).
|
||||
- Switching provider, model route, profile or workspace, or changing plugins,
|
||||
while a `/compact` is running or queued no longer leaves the session stuck.
|
||||
The pass on the replaced engine is stopped and the transcript says "Making
|
||||
|
||||
@@ -1234,20 +1234,49 @@ fn hidden_unicode_reason(input: ExecutionInput, position: usize, ch: char, count
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) const UNPARSED_CREDENTIAL_UPLOAD: &str = "<unparsed>";
|
||||
|
||||
const CREDENTIAL_SCAN_MAX_BYTES: usize = 64 * 1024;
|
||||
|
||||
fn names_upload_program(text: &str) -> bool {
|
||||
let mut window = [0u8; 4];
|
||||
text.bytes()
|
||||
.filter(|byte| !matches!(byte, b'"' | b'\'' | b'\\'))
|
||||
.any(|byte| {
|
||||
window = [window[1], window[2], window[3], byte.to_ascii_lowercase()];
|
||||
matches!(&window, b"curl" | b"wget")
|
||||
})
|
||||
}
|
||||
|
||||
fn shell_command_credential_uploads(command: &str) -> Vec<String> {
|
||||
let Some(argvs) = codewhale_execpolicy::command_safety::command_invocations(command) else {
|
||||
return if command.contains("curl") || command.contains("wget") {
|
||||
vec!["<unparsed>".to_string()]
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
if !names_upload_program(command) {
|
||||
return Vec::new();
|
||||
}
|
||||
let argvs = (command.len() <= CREDENTIAL_SCAN_MAX_BYTES)
|
||||
.then(|| codewhale_execpolicy::command_safety::command_invocations(command))
|
||||
.flatten();
|
||||
let Some(argvs) = argvs else {
|
||||
return vec![UNPARSED_CREDENTIAL_UPLOAD.to_string()];
|
||||
};
|
||||
let fed_from_credential = || {
|
||||
let fed_from_credential_file = || {
|
||||
command.split_whitespace().any(names_credential_file)
|
||||
|| argvs.iter().any(
|
||||
|argv| matches!(argv.as_slice(), [word] if word == "env" || word == "printenv"),
|
||||
)
|
||||
};
|
||||
let fed_from_secret_variable = || {
|
||||
argvs.iter().any(|argv| match argv.as_slice() {
|
||||
[program, names @ ..] if program == "printenv" => names
|
||||
.iter()
|
||||
.any(|name| codewhale_sanitize::sanitize::is_sensitive_key_name(name)),
|
||||
[program, ..]
|
||||
if matches!(program.as_str(), "echo" | "printf") || program.starts_with("<<<") =>
|
||||
{
|
||||
argv.iter().any(|word| names_secret_variable(word))
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
};
|
||||
let mut uploads: Vec<String> = Vec::new();
|
||||
for argv in &argvs {
|
||||
let Some((program, args)) = argv.split_first() else {
|
||||
@@ -1273,7 +1302,9 @@ fn shell_command_credential_uploads(command: &str) -> Vec<String> {
|
||||
|| candidates
|
||||
.iter()
|
||||
.any(|candidate| names_credential_file(candidate))
|
||||
|| ((reads_stdin || substitutes) && fed_from_credential());
|
||||
|| ((reads_stdin || substitutes)
|
||||
&& (fed_from_credential_file()
|
||||
|| (kind != UploadValue::Header && fed_from_secret_variable())));
|
||||
if credential && !uploads.iter().any(|upload| upload == value) {
|
||||
uploads.push(value.to_string());
|
||||
}
|
||||
@@ -1291,18 +1322,21 @@ enum UploadValue {
|
||||
}
|
||||
|
||||
fn upload_values<'a>(program: &str, args: &'a [String]) -> Vec<(UploadValue, &'a str)> {
|
||||
let long_kind = |name: &str| match (program, name) {
|
||||
(
|
||||
"curl",
|
||||
"data" | "data-ascii" | "data-binary" | "data-urlencode" | "json" | "form"
|
||||
| "url-query",
|
||||
) => Some(UploadValue::Data),
|
||||
("curl", "data-raw" | "form-string") | ("wget", "post-data" | "body-data") => {
|
||||
Some(UploadValue::Literal)
|
||||
let long_kind = |name: &str| {
|
||||
let wget = |option: &str| program == "wget" && name.len() >= 6 && option.starts_with(name);
|
||||
match (program, name) {
|
||||
(
|
||||
"curl",
|
||||
"data" | "data-ascii" | "data-binary" | "data-urlencode" | "json" | "form"
|
||||
| "url-query",
|
||||
) => Some(UploadValue::Data),
|
||||
("curl", "data-raw" | "form-string") => Some(UploadValue::Literal),
|
||||
("curl", "upload-file") => Some(UploadValue::File),
|
||||
("curl", "header") => Some(UploadValue::Header),
|
||||
_ if wget("post-data") || wget("body-data") => Some(UploadValue::Literal),
|
||||
_ if wget("post-file") || wget("body-file") => Some(UploadValue::File),
|
||||
_ => None,
|
||||
}
|
||||
("curl", "upload-file") | ("wget", "post-file" | "body-file") => Some(UploadValue::File),
|
||||
("curl", "header") => Some(UploadValue::Header),
|
||||
_ => None,
|
||||
};
|
||||
if !matches!(program, "curl" | "wget") {
|
||||
return Vec::new();
|
||||
@@ -1369,15 +1403,17 @@ fn names_secret_variable(value: &str) -> bool {
|
||||
}
|
||||
|
||||
fn names_credential_file(text: &str) -> bool {
|
||||
let components: Vec<String> = text
|
||||
.split(|ch: char| ch.is_whitespace() || "@<=/\\:;,\"'()`{}[]".contains(ch))
|
||||
.filter(|component| !component.is_empty())
|
||||
.map(str::to_ascii_lowercase)
|
||||
.collect();
|
||||
!components.last().is_some_and(|last| last.ends_with(".pub"))
|
||||
&& components
|
||||
.iter()
|
||||
.any(|component| crate::core::authority::is_credential_file_name(component))
|
||||
text.split(|ch: char| ",{}|&>".contains(ch)).any(|path| {
|
||||
let components: Vec<String> = path
|
||||
.split(|ch: char| ch.is_whitespace() || "@<=/\\:;\"'()`[]".contains(ch))
|
||||
.filter(|component| !component.is_empty())
|
||||
.map(str::to_ascii_lowercase)
|
||||
.collect();
|
||||
!components.last().is_some_and(|last| last.ends_with(".pub"))
|
||||
&& components
|
||||
.iter()
|
||||
.any(|component| crate::core::authority::is_credential_file_name(component))
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn credential_upload_texts<'a>(
|
||||
|
||||
@@ -47,8 +47,19 @@ pub fn approval_summary_in(
|
||||
tr(locale, id).replace(&format!("{{{slot}}}"), value)
|
||||
};
|
||||
|
||||
let credential_uploads =
|
||||
crate::core::authority::auto_review::credential_upload_texts(tool_name, input);
|
||||
let credential_uploads: Vec<_> =
|
||||
crate::core::authority::auto_review::credential_upload_texts(tool_name, input)
|
||||
.into_iter()
|
||||
.filter_map(|(command, uploads)| {
|
||||
let uploads: Vec<String> = uploads
|
||||
.into_iter()
|
||||
.filter(|upload| {
|
||||
upload != crate::core::authority::auto_review::UNPARSED_CREDENTIAL_UPLOAD
|
||||
})
|
||||
.collect();
|
||||
(!uploads.is_empty()).then_some((command, uploads))
|
||||
})
|
||||
.collect();
|
||||
if let Some((command, _)) = credential_uploads.first() {
|
||||
let uploads: Vec<&str> = credential_uploads
|
||||
.iter()
|
||||
|
||||
@@ -2368,8 +2368,10 @@ reasoning contract, and all four membership ids omit generic sampling fields.
|
||||
fails closed as a hard block. Full Access skips the built-in floor. The
|
||||
safety floor covers publish-like actions, destructive background/headless
|
||||
actions, and `curl`/`wget` uploads whose request body carries a credential
|
||||
file, a secret-named variable or a credential fed through stdin, even if an
|
||||
allow rule matches. Outside Full Access it also refuses, in every posture, a
|
||||
file or a secret-named variable, or reads stdin fed from one of those or
|
||||
from `env`/`printenv`, even if an allow rule matches; a `curl`/`wget` too
|
||||
large (over 64 KiB) or too deeply nested to read is held too. Outside Full
|
||||
Access it also refuses, in every posture, a
|
||||
shell command, shell input or verifier containing a hidden Unicode character
|
||||
(bidirectional controls, zero-width and other invisible characters, tag
|
||||
characters, stray variation selectors, and terminal control characters
|
||||
|
||||
+5
-3
@@ -1388,9 +1388,11 @@ Clients show it first and keep the raw arguments behind it. For task and
|
||||
automation create/update, `summary` also names the requested trust mode,
|
||||
shell, auto-approve, mode and workspace. For a shell command, task gate,
|
||||
shell input or verifier whose `curl`/`wget` request body carries a credential
|
||||
file, a secret-named variable or a credential fed through stdin, `summary`
|
||||
reads ``Upload credentials (`…`) with `…` ``; the built-in safety gate holds
|
||||
that call, so a session grant or saved allow rule cannot answer it. A shell
|
||||
file or a secret-named variable, or reads stdin fed from one of those or from
|
||||
`env`/`printenv`, `summary` reads ``Upload credentials (`…`) with `…` ``; the
|
||||
built-in safety gate holds that call, so a session grant or saved allow rule
|
||||
cannot answer it. A `curl`/`wget` too large (over 64 KiB) or too deeply nested
|
||||
to read is held the same way under its ordinary `summary`. A shell
|
||||
command containing a hidden Unicode character is refused before any
|
||||
approval is created.
|
||||
|
||||
|
||||
@@ -1266,7 +1266,7 @@ DeepSeek V4 前缀缓存让 token 标签变得重要。这些数量保持分离
|
||||
action = "session.compact"
|
||||
```
|
||||
|
||||
- `[auto_review]`(表,可选):工具调用审查策略——确定性底线加模型守卫层。这一层位于现有权限档位之上;它可以拦住或阻断工具调用,但不是自动推送、自动合并或托管审查服务。先检查阻断规则,然后是内置安全底线,再是允许规则。在 Ask 中,安全拦阻打开审批,会话授权或 allow 规则都无法应答它;在 Auto-Review 或非交互 `never` 档位中,它作为硬阻断失败关闭。Full Access 跳过内置底线。即使 allow 规则匹配,安全底线仍覆盖类似发布的动作、破坏性的后台/无头动作,以及请求体携带凭据文件、名称表明是机密的变量或经 stdin 送入凭据的 `curl`/`wget` 上传。在 Full Access 之外,它还会在每个档位拒绝含有隐藏 Unicode 字符(双向控制符、零宽及其他不可见字符、标签字符、孤立的变体选择符,以及 shell 输入中 ASCII 控制键之外的终端控制字符)的 shell 命令、shell 输入或校验器,并写出该码位及其位置。
|
||||
- `[auto_review]`(表,可选):工具调用审查策略——确定性底线加模型守卫层。这一层位于现有权限档位之上;它可以拦住或阻断工具调用,但不是自动推送、自动合并或托管审查服务。先检查阻断规则,然后是内置安全底线,再是允许规则。在 Ask 中,安全拦阻打开审批,会话授权或 allow 规则都无法应答它;在 Auto-Review 或非交互 `never` 档位中,它作为硬阻断失败关闭。Full Access 跳过内置底线。即使 allow 规则匹配,安全底线仍覆盖类似发布的动作、破坏性的后台/无头动作,以及请求体携带凭据文件或名称表明是机密的变量、或读取由这两者或 `env`/`printenv` 送入的 stdin 的 `curl`/`wget` 上传;过大(超过 64 KiB)或嵌套过深而无法读取的 `curl`/`wget` 同样会被拦住。在 Full Access 之外,它还会在每个档位拒绝含有隐藏 Unicode 字符(双向控制符、零宽及其他不可见字符、标签字符、孤立的变体选择符,以及 shell 输入中 ASCII 控制键之外的终端控制字符)的 shell 命令、shell 输入或校验器,并写出该码位及其位置。
|
||||
|
||||
```toml
|
||||
[[auto_review.allow]]
|
||||
|
||||
@@ -1192,10 +1192,11 @@ Engine 的工具执行 ID 另行以 `tool_call_id` 出现在
|
||||
“Write notes/espresso.md”);工作区内的路径为工作区相对路径。
|
||||
客户端应先展示它,并把原始参数留在其后。对任务与自动化的创建/更新,
|
||||
`summary` 还会写出所请求的信任模式、shell、自动批准、模式和工作区。
|
||||
对 shell 命令、任务门禁、shell 输入或校验器,若其 `curl`/`wget` 请求体携带凭据文件、
|
||||
名称表明是机密的变量,或经 stdin 送入的凭据,`summary` 显示为
|
||||
对 shell 命令、任务门禁、shell 输入或校验器,若其 `curl`/`wget` 请求体携带凭据文件
|
||||
或名称表明是机密的变量,或读取由这两者或 `env`/`printenv` 送入的 stdin,`summary` 显示为
|
||||
``Upload credentials (`…`) with `…` ``;内置安全闸会拦住该调用,
|
||||
会话授权或已保存的 allow 规则都无法应答它。含有隐藏 Unicode 字符的 shell 命令
|
||||
会话授权或已保存的 allow 规则都无法应答它。过大(超过 64 KiB)或嵌套过深而无法读取的
|
||||
`curl`/`wget` 同样会被拦住,`summary` 保持普通内容。含有隐藏 Unicode 字符的 shell 命令
|
||||
会在创建任何审批之前被拒绝。
|
||||
|
||||
在 `allow` 上带上 `"remember": true` 会为该工具及其参数类别记录一份**会话授权**
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
"sources": [
|
||||
{
|
||||
"path": "docs/CONFIGURATION.md",
|
||||
"sha256": "b4a1df17d67bba39c20523f8fb61f16da57cd7c499d61dd239b17c19e85f0896",
|
||||
"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\n scaffold one. `CLAUDE.md` and `.claude/instructions.md` are read as\n compatibility fallbacks.\n- **Memory and handoffs** — recalled state. Useful, but lower authority than\n constitutions and project instructions.\n\n### Managing the user-global constitution (`/setup` and `/constitution`)\n\nThe bundled **working agreement** is the safe default and no longer adds a\nrequired first-run screen. Customize it later through `/constitution` or the\nprogressive `/setup` guide. Provider/model readiness, workspace trust, and\nruntime posture stay separate from this guidance.\n\nOn the **Working agreement** (constitution) step:\n\n- **`1`–`6`** tune the guided draft. **`G`** previews it, and **`G`** again\n ratifies and saves a fresh structured `constitution.json`.\n- **`A`** (shown only when a provider is configured) asks your first configured\n model to draft the constitution. Drafting is **not** saving: the draft is\n rendered through the same preview and you still press **`G`** to ratify\n before anything persists.\n- **`K`** keeps your existing loaded constitution unchanged (shown only when a\n valid file is already present).\n- **`U`** (or `/coLine truncated
|
||||
"sha256": "37556e4b839550250162a2cc7ae91bb8f6db20d4e61f550f2b46c82e0a873760",
|
||||
"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\n scaffold one. `CLAUDE.md` and `.claude/instructions.md` are read as\n compatibility fallbacks.\n- **Memory and handoffs** — recalled state. Useful, but lower authority than\n constitutions and project instructions.\n\n### Managing the user-global constitution (`/setup` and `/constitution`)\n\nThe bundled **working agreement** is the safe default and no longer adds a\nrequired first-run screen. Customize it later through `/constitution` or the\nprogressive `/setup` guide. Provider/model readiness, workspace trust, and\nruntime posture stay separate from this guidance.\n\nOn the **Working agreement** (constitution) step:\n\n- **`1`–`6`** tune the guided draft. **`G`** previews it, and **`G`** again\n ratifies and saves a fresh structured `constitution.json`.\n- **`A`** (shown only when a provider is configured) asks your first configured\n model to draft the constitution. Drafting is **not** saving: the draft is\n rendered through the same preview and you still press **`G`** to ratify\n before anything persists.\n- **`K`** keeps your existing loaded constitution unchanged (shown only when a\n valid file is already present).\n- **`U`** (or `/coLine truncated
|
||||
},
|
||||
{
|
||||
"path": "docs/CODEWHALE_AGENT.md",
|
||||
@@ -64,8 +64,8 @@
|
||||
"sources": [
|
||||
{
|
||||
"path": "docs/CONFIGURATION.md",
|
||||
"sha256": "b4a1df17d67bba39c20523f8fb61f16da57cd7c499d61dd239b17c19e85f0896",
|
||||
"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\n scaffold one. `CLAUDE.md` and `.claude/instructions.md` are read as\n compatibility fallbacks.\n- **Memory and handoffs** — recalled state. Useful, but lower authority than\n constitutions and project instructions.\n\n### Managing the user-global constitution (`/setup` and `/constitution`)\n\nThe bundled **working agreement** is the safe default and no longer adds a\nrequired first-run screen. Customize it later through `/constitution` or the\nprogressive `/setup` guide. Provider/model readiness, workspace trust, and\nruntime posture stay separate from this guidance.\n\nOn the **Working agreement** (constitution) step:\n\n- **`1`–`6`** tune the guided draft. **`G`** previews it, and **`G`** again\n ratifies and saves a fresh structured `constitution.json`.\n- **`A`** (shown only when a provider is configured) asks your first configured\n model to draft the constitution. Drafting is **not** saving: the draft is\n rendered through the same preview and you still press **`G`** to ratify\n before anything persists.\n- **`K`** keeps your existing loaded constitution unchanged (shown only when a\n valid file is already present).\n- **`U`** (or `/coLine truncated
|
||||
"sha256": "37556e4b839550250162a2cc7ae91bb8f6db20d4e61f550f2b46c82e0a873760",
|
||||
"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\n scaffold one. `CLAUDE.md` and `.claude/instructions.md` are read as\n compatibility fallbacks.\n- **Memory and handoffs** — recalled state. Useful, but lower authority than\n constitutions and project instructions.\n\n### Managing the user-global constitution (`/setup` and `/constitution`)\n\nThe bundled **working agreement** is the safe default and no longer adds a\nrequired first-run screen. Customize it later through `/constitution` or the\nprogressive `/setup` guide. Provider/model readiness, workspace trust, and\nruntime posture stay separate from this guidance.\n\nOn the **Working agreement** (constitution) step:\n\n- **`1`–`6`** tune the guided draft. **`G`** previews it, and **`G`** again\n ratifies and saves a fresh structured `constitution.json`.\n- **`A`** (shown only when a provider is configured) asks your first configured\n model to draft the constitution. Drafting is **not** saving: the draft is\n rendered through the same preview and you still press **`G`** to ratify\n before anything persists.\n- **`K`** keeps your existing loaded constitution unchanged (shown only when a\n valid file is already present).\n- **`U`** (or `/coLine truncated
|
||||
},
|
||||
{
|
||||
"path": "docs/LEGACY_PATHS.md",
|
||||
@@ -96,8 +96,8 @@
|
||||
},
|
||||
{
|
||||
"path": "docs/CONFIGURATION.md",
|
||||
"sha256": "b4a1df17d67bba39c20523f8fb61f16da57cd7c499d61dd239b17c19e85f0896",
|
||||
"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\n scaffold one. `CLAUDE.md` and `.claude/instructions.md` are read as\n compatibility fallbacks.\n- **Memory and handoffs** — recalled state. Useful, but lower authority than\n constitutions and project instructions.\n\n### Managing the user-global constitution (`/setup` and `/constitution`)\n\nThe bundled **working agreement** is the safe default and no longer adds a\nrequired first-run screen. Customize it later through `/constitution` or the\nprogressive `/setup` guide. Provider/model readiness, workspace trust, and\nruntime posture stay separate from this guidance.\n\nOn the **Working agreement** (constitution) step:\n\n- **`1`–`6`** tune the guided draft. **`G`** previews it, and **`G`** again\n ratifies and saves a fresh structured `constitution.json`.\n- **`A`** (shown only when a provider is configured) asks your first configured\n model to draft the constitution. Drafting is **not** saving: the draft is\n rendered through the same preview and you still press **`G`** to ratify\n before anything persists.\n- **`K`** keeps your existing loaded constitution unchanged (shown only when a\n valid file is already present).\n- **`U`** (or `/coLine truncated
|
||||
"sha256": "37556e4b839550250162a2cc7ae91bb8f6db20d4e61f550f2b46c82e0a873760",
|
||||
"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\n scaffold one. `CLAUDE.md` and `.claude/instructions.md` are read as\n compatibility fallbacks.\n- **Memory and handoffs** — recalled state. Useful, but lower authority than\n constitutions and project instructions.\n\n### Managing the user-global constitution (`/setup` and `/constitution`)\n\nThe bundled **working agreement** is the safe default and no longer adds a\nrequired first-run screen. Customize it later through `/constitution` or the\nprogressive `/setup` guide. Provider/model readiness, workspace trust, and\nruntime posture stay separate from this guidance.\n\nOn the **Working agreement** (constitution) step:\n\n- **`1`–`6`** tune the guided draft. **`G`** previews it, and **`G`** again\n ratifies and saves a fresh structured `constitution.json`.\n- **`A`** (shown only when a provider is configured) asks your first configured\n model to draft the constitution. Drafting is **not** saving: the draft is\n rendered through the same preview and you still press **`G`** to ratify\n before anything persists.\n- **`K`** keeps your existing loaded constitution unchanged (shown only when a\n valid file is already present).\n- **`U`** (or `/coLine truncated
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -224,8 +224,8 @@
|
||||
},
|
||||
{
|
||||
"path": "docs/CONFIGURATION.md",
|
||||
"sha256": "b4a1df17d67bba39c20523f8fb61f16da57cd7c499d61dd239b17c19e85f0896",
|
||||
"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\n scaffold one. `CLAUDE.md` and `.claude/instructions.md` are read as\n compatibility fallbacks.\n- **Memory and handoffs** — recalled state. Useful, but lower authority than\n constitutions and project instructions.\n\n### Managing the user-global constitution (`/setup` and `/constitution`)\n\nThe bundled **working agreement** is the safe default and no longer adds a\nrequired first-run screen. Customize it later through `/constitution` or the\nprogressive `/setup` guide. Provider/model readiness, workspace trust, and\nruntime posture stay separate from this guidance.\n\nOn the **Working agreement** (constitution) step:\n\n- **`1`–`6`** tune the guided draft. **`G`** previews it, and **`G`** again\n ratifies and saves a fresh structured `constitution.json`.\n- **`A`** (shown only when a provider is configured) asks your first configured\n model to draft the constitution. Drafting is **not** saving: the draft is\n rendered through the same preview and you still press **`G`** to ratify\n before anything persists.\n- **`K`** keeps your existing loaded constitution unchanged (shown only when a\n valid file is already present).\n- **`U`** (or `/coLine truncated
|
||||
"sha256": "37556e4b839550250162a2cc7ae91bb8f6db20d4e61f550f2b46c82e0a873760",
|
||||
"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\n scaffold one. `CLAUDE.md` and `.claude/instructions.md` are read as\n compatibility fallbacks.\n- **Memory and handoffs** — recalled state. Useful, but lower authority than\n constitutions and project instructions.\n\n### Managing the user-global constitution (`/setup` and `/constitution`)\n\nThe bundled **working agreement** is the safe default and no longer adds a\nrequired first-run screen. Customize it later through `/constitution` or the\nprogressive `/setup` guide. Provider/model readiness, workspace trust, and\nruntime posture stay separate from this guidance.\n\nOn the **Working agreement** (constitution) step:\n\n- **`1`–`6`** tune the guided draft. **`G`** previews it, and **`G`** again\n ratifies and saves a fresh structured `constitution.json`.\n- **`A`** (shown only when a provider is configured) asks your first configured\n model to draft the constitution. Drafting is **not** saving: the draft is\n rendered through the same preview and you still press **`G`** to ratify\n before anything persists.\n- **`K`** keeps your existing loaded constitution unchanged (shown only when a\n valid file is already present).\n- **`U`** (or `/coLine truncated
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -256,8 +256,8 @@
|
||||
},
|
||||
{
|
||||
"path": "docs/CONFIGURATION.md",
|
||||
"sha256": "b4a1df17d67bba39c20523f8fb61f16da57cd7c499d61dd239b17c19e85f0896",
|
||||
"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\n scaffold one. `CLAUDE.md` and `.claude/instructions.md` are read as\n compatibility fallbacks.\n- **Memory and handoffs** — recalled state. Useful, but lower authority than\n constitutions and project instructions.\n\n### Managing the user-global constitution (`/setup` and `/constitution`)\n\nThe bundled **working agreement** is the safe default and no longer adds a\nrequired first-run screen. Customize it later through `/constitution` or the\nprogressive `/setup` guide. Provider/model readiness, workspace trust, and\nruntime posture stay separate from this guidance.\n\nOn the **Working agreement** (constitution) step:\n\n- **`1`–`6`** tune the guided draft. **`G`** previews it, and **`G`** again\n ratifies and saves a fresh structured `constitution.json`.\n- **`A`** (shown only when a provider is configured) asks your first configured\n model to draft the constitution. Drafting is **not** saving: the draft is\n rendered through the same preview and you still press **`G`** to ratify\n before anything persists.\n- **`K`** keeps your existing loaded constitution unchanged (shown only when a\n valid file is already present).\n- **`U`** (or `/coLine truncated
|
||||
"sha256": "37556e4b839550250162a2cc7ae91bb8f6db20d4e61f550f2b46c82e0a873760",
|
||||
"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\n scaffold one. `CLAUDE.md` and `.claude/instructions.md` are read as\n compatibility fallbacks.\n- **Memory and handoffs** — recalled state. Useful, but lower authority than\n constitutions and project instructions.\n\n### Managing the user-global constitution (`/setup` and `/constitution`)\n\nThe bundled **working agreement** is the safe default and no longer adds a\nrequired first-run screen. Customize it later through `/constitution` or the\nprogressive `/setup` guide. Provider/model readiness, workspace trust, and\nruntime posture stay separate from this guidance.\n\nOn the **Working agreement** (constitution) step:\n\n- **`1`–`6`** tune the guided draft. **`G`** previews it, and **`G`** again\n ratifies and saves a fresh structured `constitution.json`.\n- **`A`** (shown only when a provider is configured) asks your first configured\n model to draft the constitution. Drafting is **not** saving: the draft is\n rendered through the same preview and you still press **`G`** to ratify\n before anything persists.\n- **`K`** keeps your existing loaded constitution unchanged (shown only when a\n valid file is already present).\n- **`U`** (or `/coLine truncated
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -288,8 +288,8 @@
|
||||
"sources": [
|
||||
{
|
||||
"path": "docs/RUNTIME_API.md",
|
||||
"sha256": "2d87c4e47dfdba7f5a7d6b90e480ef0f24d0b2934cf48a316e7aac5abcbf06ea",
|
||||
"content": "# Codewhale Engine Runtime API & Integration Contract\n\n> 阅读简体中文版:[zh_hans/RUNTIME_API.md](zh_hans/RUNTIME_API.md)。\n\n`codewhale app-server` exposes the [Codewhale Engine](ARCHITECTURE.md) through\nits canonical local Runtime API and control plane.\nLocal SDKs, mobile/remote-control clients, and editor integrations talk to it\ninstead of screen-scraping terminal output. It serves the full HTTP/SSE runtime\nAPI (`/v1/*`), a JSON-RPC control transport over stdio, and the phone-friendly\nmobile page. `codewhale doctor --json` provides machine-readable health, and\n`codewhale serve --acp` speaks the Agent Client Protocol over stdio for editors\nsuch as Zed.\n\n`codewhale serve --http` / `serve --mobile` remain as **compatibility aliases**\nfor `codewhale app-server --http` / `--mobile`; both launch the identical\nserver. New integrations should target `app-server`.\n\n`codewhale exec` is the separate one-shot headless worker path (stream-json,\nfleet worker subprocess, CI primitive). It is not part of this API, but it\nshares the same runtime, provider/model resolution, permission profiles, and\nevent vocabulary.\n\nThis document is the stable integration contract for native workbench\napplications (and other local supervisors) that embed the Codewhale Engine.\n\n## Architecture\n\n```\nlocal supervisor / SDK / automation harness\n │\n ├─ codewhale app-server --http → HTTP/SSE runtime API (/v1/*) [canonical]\n ├─ codewhale app-server --mobile → runtime API + mobile control page\n ├─ codewhale app-server --stdio → JSON-RPC control transport over stdio\n ├─ codewhale app-server --socket → same JSON-RPC over a unix domain socket (desktop daemon)\n ├─ codewhale doctor --json → machine-readable health & capability\n ├─ codewhale serve --acp → ACP stdio agent for editors such as Zed\n ├─ codewhale serve --mcp → MCP stdio server\n ├─ codewhale serve --http/--mobile → legacy aliases for `app-server --http/--mobile`\n └─ codewhale exec [args] → one-shot headless worker (stream-json)\n```\n\nThe engine runs as a local-only process. All APIs bind to `localhost` by\ndefault. No hosted relay, no provider-token custody, no secret leakage.\n\nFor the read-only record of what a thread or turn did, see\n[`docs/RECEIPTS.md`](RECEIPTS.md): `codewhale receipts` on the CLI and the\n`/receipt` routes under **Threads** below.\n\n## Runtime API entrypoints\n\n| Entry | Transport | Use |\n|---|---|---|\n| `codewhale web [--port 7878]` | HTTP/SSE on `127.0.0.1:7878` + embedded client | First-class loopback-only browser client; opens the default browser |\n| `codewhale app-server --http` | HTTP/SSE on `127.0.0.1:7878` | Full `/v1/*` runtime API (canonical) |\n| `codewhale app-server --mobile` | HTTP/SSE on loopback + `/mobile` | Runtime API + local mobile control page |\n| `codewhale app-server --stdio` | JSON-RPC 2.0 over stdio | Local SDK / control probe (no listener) |\n| `codewhale app-server --socket [--socket-path P]` | JSON-RPC 2.0 over a `0600` Unix domain socket (macOS/Linux) or an owner-only named pipe (Windows) | Desktop daemon: multi-client, kernel peer identity checked, `daemon/attach` claim handshake. Windows native-app qualification remains open. |\n| `codewhale app-server` | HTTP on `127.0.0.1:8787` | Legacy in-process app-server (`/healthz`, `/thread`, `/app`, `/prompt`); background jobs are `GET /v1/jobs` on the Runtime API; `/prompt` and `/thread` messages execute real turns via the runtime bridge. There is no direct `/tool` route: tools run only inside Engine turns, under the Engine's tool catalog and approval posture. This legacy server does not surface approvals: its bridge forwards only text deltas and the turn's completion, and it has no decision route, so an approval-gated call waits unanswered. Drive approval-gated work through the Runtime API (`/v1/threads/*` events and `POST /v1/approvals/{approval_id}`) |\n| `codewhale serve --http` / `--mobile` | same server as `app-server --http`/`--mobile` | Compatibility aliases |\n\n`app-server --http` and `--mobile` launch the same mature runtime API server\nhistorically reached through `serve --http` — no routes or behavior changed, so\nevery endpoint documented below is identical across both entrypoints. The\nruntime API token is read from `--auth-token`, then `CODEWHALE_RUNTIME_TOKEN`,\nthen `DEEPSEEK_RUNTIME_TOKEN`; use `--insecure-no-auth` only with a loopback\nbind. The `serve` compatibility aliases keep their `--insecure` flag.\nThe legacy in-process `codewhale app-server` also requires an explicit\n`--auth-token` or `CODEWHALE_APP_SERVER_TOKEN` before binding a non-loopback\nhost; its generated one-time `cwapp_*` token is loopback-only.\n\nDevice tokens minted by the master through `POST /v1/auth/client-tokens`\nhave an immutable `intent`: `Line truncated
|
||||
"sha256": "35648e87626c3c29a98603e7ede4e308c3190221d6d3a147d960ce2b3175cd41",
|
||||
"content": "# Codewhale Engine Runtime API & Integration Contract\n\n> 阅读简体中文版:[zh_hans/RUNTIME_API.md](zh_hans/RUNTIME_API.md)。\n\n`codewhale app-server` exposes the [Codewhale Engine](ARCHITECTURE.md) through\nits canonical local Runtime API and control plane.\nLocal SDKs, mobile/remote-control clients, and editor integrations talk to it\ninstead of screen-scraping terminal output. It serves the full HTTP/SSE runtime\nAPI (`/v1/*`), a JSON-RPC control transport over stdio, and the phone-friendly\nmobile page. `codewhale doctor --json` provides machine-readable health, and\n`codewhale serve --acp` speaks the Agent Client Protocol over stdio for editors\nsuch as Zed.\n\n`codewhale serve --http` / `serve --mobile` remain as **compatibility aliases**\nfor `codewhale app-server --http` / `--mobile`; both launch the identical\nserver. New integrations should target `app-server`.\n\n`codewhale exec` is the separate one-shot headless worker path (stream-json,\nfleet worker subprocess, CI primitive). It is not part of this API, but it\nshares the same runtime, provider/model resolution, permission profiles, and\nevent vocabulary.\n\nThis document is the stable integration contract for native workbench\napplications (and other local supervisors) that embed the Codewhale Engine.\n\n## Architecture\n\n```\nlocal supervisor / SDK / automation harness\n │\n ├─ codewhale app-server --http → HTTP/SSE runtime API (/v1/*) [canonical]\n ├─ codewhale app-server --mobile → runtime API + mobile control page\n ├─ codewhale app-server --stdio → JSON-RPC control transport over stdio\n ├─ codewhale app-server --socket → same JSON-RPC over a unix domain socket (desktop daemon)\n ├─ codewhale doctor --json → machine-readable health & capability\n ├─ codewhale serve --acp → ACP stdio agent for editors such as Zed\n ├─ codewhale serve --mcp → MCP stdio server\n ├─ codewhale serve --http/--mobile → legacy aliases for `app-server --http/--mobile`\n └─ codewhale exec [args] → one-shot headless worker (stream-json)\n```\n\nThe engine runs as a local-only process. All APIs bind to `localhost` by\ndefault. No hosted relay, no provider-token custody, no secret leakage.\n\nFor the read-only record of what a thread or turn did, see\n[`docs/RECEIPTS.md`](RECEIPTS.md): `codewhale receipts` on the CLI and the\n`/receipt` routes under **Threads** below.\n\n## Runtime API entrypoints\n\n| Entry | Transport | Use |\n|---|---|---|\n| `codewhale web [--port 7878]` | HTTP/SSE on `127.0.0.1:7878` + embedded client | First-class loopback-only browser client; opens the default browser |\n| `codewhale app-server --http` | HTTP/SSE on `127.0.0.1:7878` | Full `/v1/*` runtime API (canonical) |\n| `codewhale app-server --mobile` | HTTP/SSE on loopback + `/mobile` | Runtime API + local mobile control page |\n| `codewhale app-server --stdio` | JSON-RPC 2.0 over stdio | Local SDK / control probe (no listener) |\n| `codewhale app-server --socket [--socket-path P]` | JSON-RPC 2.0 over a `0600` Unix domain socket (macOS/Linux) or an owner-only named pipe (Windows) | Desktop daemon: multi-client, kernel peer identity checked, `daemon/attach` claim handshake. Windows native-app qualification remains open. |\n| `codewhale app-server` | HTTP on `127.0.0.1:8787` | Legacy in-process app-server (`/healthz`, `/thread`, `/app`, `/prompt`); background jobs are `GET /v1/jobs` on the Runtime API; `/prompt` and `/thread` messages execute real turns via the runtime bridge. There is no direct `/tool` route: tools run only inside Engine turns, under the Engine's tool catalog and approval posture. This legacy server does not surface approvals: its bridge forwards only text deltas and the turn's completion, and it has no decision route, so an approval-gated call waits unanswered. Drive approval-gated work through the Runtime API (`/v1/threads/*` events and `POST /v1/approvals/{approval_id}`) |\n| `codewhale serve --http` / `--mobile` | same server as `app-server --http`/`--mobile` | Compatibility aliases |\n\n`app-server --http` and `--mobile` launch the same mature runtime API server\nhistorically reached through `serve --http` — no routes or behavior changed, so\nevery endpoint documented below is identical across both entrypoints. The\nruntime API token is read from `--auth-token`, then `CODEWHALE_RUNTIME_TOKEN`,\nthen `DEEPSEEK_RUNTIME_TOKEN`; use `--insecure-no-auth` only with a loopback\nbind. The `serve` compatibility aliases keep their `--insecure` flag.\nThe legacy in-process `codewhale app-server` also requires an explicit\n`--auth-token` or `CODEWHALE_APP_SERVER_TOKEN` before binding a non-loopback\nhost; its generated one-time `cwapp_*` token is loopback-only.\n\nDevice tokens minted by the master through `POST /v1/auth/client-tokens`\nhave an immutable `intent`: `Line truncated
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user