Compare commits

...

48 Commits

Author SHA1 Message Date
Yeachan-Heo
5a4a8ebfb2 docs(roadmap): add gh read-only bypass 2026-05-20 13:31:00 +00:00
Yeachan-Heo
214176d6dc docs(roadmap): add interpreter read-only bypass 2026-05-20 13:01:39 +00:00
Yeachan-Heo
8382e1ec51 docs(roadmap): add tee read-only bypass 2026-05-20 12:31:57 +00:00
Yeachan-Heo
916bf5f24d docs(roadmap): add git availability hang 2026-05-20 12:01:19 +00:00
Yeachan-Heo
4d185f0dee docs(roadmap): add tmux availability hang 2026-05-20 11:31:07 +00:00
Yeachan-Heo
2bf6924e01 docs(roadmap): add gitcontext system prompt hang 2026-05-20 11:01:37 +00:00
Yeachan-Heo
56555a3ad6 docs(roadmap): add dirty diff git hang 2026-05-20 10:31:18 +00:00
Yeachan-Heo
d5aa815b39 docs(roadmap): add status doctor git metadata hang 2026-05-20 10:01:41 +00:00
Yeachan-Heo
edcf5bf33a docs(roadmap): add stale branch freshness ref gap 2026-05-20 09:30:51 +00:00
Yeachan-Heo
d541130121 docs(roadmap): add status dirty path inventory gap 2026-05-20 09:01:30 +00:00
Yeachan-Heo
92e97e0b63 docs(roadmap): add prompt post-flag hang 2026-05-20 08:31:34 +00:00
Yeachan-Heo
32961cfc5b docs(roadmap): add prompt clean-home hang 2026-05-20 08:01:25 +00:00
Yeachan-Heo
8a2e133f66 docs(roadmap): add planning alias argument hang 2026-05-20 07:31:23 +00:00
Yeachan-Heo
51a450e473 docs(roadmap): add debug alias argument hang 2026-05-20 07:01:25 +00:00
Yeachan-Heo
dbd04ad334 docs(roadmap): add interactive alias help hang 2026-05-20 06:31:24 +00:00
Yeachan-Heo
625b8b06d8 docs(roadmap): add telemetry alias help hang 2026-05-20 06:01:16 +00:00
Yeachan-Heo
111e7e853c docs(roadmap): add slash alias help hang 2026-05-20 05:31:22 +00:00
Yeachan-Heo
51e6040b23 docs(roadmap): add session direct command hang 2026-05-20 05:01:09 +00:00
Yeachan-Heo
93f20dfd25 docs(roadmap): add unknown skill invocation hang 2026-05-20 04:32:31 +00:00
Yeachan-Heo
4d52703ca9 docs(roadmap): add export option hang 2026-05-20 03:31:35 +00:00
Yeachan-Heo
90a0d38d52 docs(roadmap): add system-prompt modifier hang 2026-05-20 03:01:45 +00:00
Yeachan-Heo
8afdb9448a docs(roadmap): add inventory json parity gap 2026-05-20 02:31:20 +00:00
Yeachan-Heo
bb2cf3f448 docs(roadmap): add local diagnostics json gap 2026-05-20 02:01:25 +00:00
Yeachan-Heo
9495dbee30 docs(roadmap): add local verb help arity hangs 2026-05-20 01:31:56 +00:00
Yeachan-Heo
1208b9a034 docs(roadmap): add compact slash-only help hang 2026-05-20 01:01:25 +00:00
Yeachan-Heo
e9db12d98b docs(roadmap): add silent malformed config gap 2026-05-20 00:30:56 +00:00
Yeachan-Heo
a666fa6f10 docs(roadmap): add version json alias gap 2026-05-20 00:01:10 +00:00
Yeachan-Heo
ac3665fe2f docs(roadmap): add help alias arity hang 2026-05-19 23:31:17 +00:00
Yeachan-Heo
7cbb6e7fa5 docs(roadmap): add unexpected positional hang 2026-05-19 22:32:00 +00:00
Yeachan-Heo
674cec191f docs(roadmap): add lifecycle explicit action hangs 2026-05-19 22:01:43 +00:00
Yeachan-Heo
59df684a17 docs(roadmap): add explicit plugin list hang 2026-05-19 21:31:23 +00:00
Yeachan-Heo
31d5db7453 docs(roadmap): add mixed PATH mcp reachability proof 2026-05-19 21:00:48 +00:00
Yeachan-Heo
164589b8e6 docs(roadmap): add mcp executable reachability gap 2026-05-19 20:30:59 +00:00
Yeachan-Heo
b4a732f33d docs(roadmap): add compact skills output gap 2026-05-19 20:01:01 +00:00
Yeachan-Heo
2980f6de6e docs(roadmap): add output-format flag placement gap 2026-05-19 19:31:20 +00:00
Yeachan-Heo
2cca298f7a docs(roadmap): add direct slash invocation contract 2026-05-19 18:31:28 +00:00
Yeachan-Heo
6b90f83b9d docs(roadmap): add text command help hang 2026-05-19 18:02:27 +00:00
Yeachan-Heo
8303af0898 docs(roadmap): add command-specific json help hang 2026-05-19 17:32:04 +00:00
Yeachan-Heo
3e2d902271 docs(roadmap): add structured root help schema 2026-05-19 17:01:00 +00:00
Yeachan-Heo
78d334c4e2 docs(roadmap): add dogfood timeout retry evidence 2026-05-19 16:31:00 +00:00
Yeachan-Heo
0063c0d698 docs(roadmap): add global flag order and clean version hang 2026-05-19 16:01:15 +00:00
Yeachan-Heo
429671ec12 docs(roadmap): add root help json hang 2026-05-19 15:31:27 +00:00
Yeachan-Heo
ed9d387e9a docs(roadmap): add shared lifecycle help hang 2026-05-19 15:01:46 +00:00
Yeachan-Heo
8d02077cfd docs(roadmap): add plugin help hang contract 2026-05-19 14:32:04 +00:00
Yeachan-Heo
44bd2b54f5 docs(roadmap): add plugin lifecycle help contract 2026-05-19 14:01:01 +00:00
Yeachan-Heo
e2c310dc04 docs(roadmap): add stale bundled plugin source provenance 2026-05-19 13:32:37 +00:00
Yeachan-Heo
25d663d140 docs(roadmap): add missing dogfood binary preflight 2026-05-19 13:00:59 +00:00
Yeachan-Heo
6183d958ba docs(roadmap): add dogfood workdir provenance guard 2026-05-19 12:31:56 +00:00

View File

@@ -6428,3 +6428,124 @@ Original filing (2026-04-18): the session emitted `SessionStart hook (completed)
450. **`prompt` emits `kind:"missing_credentials"` JSON on STDERR (not stdout), leaving stdout at 0 bytes — automation pattern `output=$(claw prompt hello --output-format json)` captures nothing on auth-absent failure; `doctor` correctly surfaces `auth.status:"warn"` with `api_key_present:false` but exposes no `prompt_ready:false` field that automation can check before invoking `prompt`** — dogfooded 2026-05-16 by Jobdori on `a35ee9a0` in response to Clawhip pinpoint nudge at `1505208225321062521`. Exact reproduction (isolated env, no creds, fresh git repo, HEAD `a35ee9a0`): `timeout 5 env -i HOME=$ISOLATED_HOME PATH=$PATH CLAW_CONFIG_HOME=$PROBE/.claw-cfg claw prompt hello --output-format json > stdout.txt 2> stderr.txt` → stdout = **0 bytes**, stderr = 195 bytes containing `{"error":"missing Anthropic credentials…","exit_code":1,"hint":null,"kind":"missing_credentials","type":"error"}`, exit code 1. Confirms Gaebal's `1505208553793781792` pinpoint that `prompt` timeout + zero bytes was the prior state — HEAD `a35ee9a0` now correctly exits 1 with `kind:"missing_credentials"` **but the envelope is still routed to stderr** (issue #447 class, same class as prior entries #422, #435). **Contrast with `doctor`:** `claw doctor --output-format json 2>/dev/null` succeeds to stdout with `checks[auth].status:"warn"`, `api_key_present:false`, `auth_token_present:false` — but the auth check has no `prompt_ready:false` field. Automation that gates on `doctor` before invoking `prompt` must re-derive readiness from `api_key_present && auth_token_present` — there is no single canonical boolean. **Three compound problems:** (a) **stdout-empty on `--output-format json` failure**: same class as #447; `prompt`'s error envelope goes to stderr, not stdout. The canonical automation idiom `if ! result=$(claw prompt "q" --output-format json); then echo "$result" | jq .kind; fi` sees `$result=""` on failure — the jq call gets nothing. All `--output-format json` error paths must route JSON to stdout per #447 contract; (b) **`doctor` missing `prompt_ready` field**: `doctor --output-format json` already knows auth is absent (`api_key_present:false`) but surfaces no derived `prompt_ready:bool` or `prompt_blocked_reason:string` field. Automation must infer readiness from `api_key_present || auth_token_present || legacy_*_present` — a 5-field OR across legacy fields that is fragile as auth mechanisms evolve. A single `prompt_ready:false` (with `prompt_blocked_reason:"auth_missing"`) inside the `auth` check would give downstream a stable contract; (c) **`claw prompt` with no auth does no preflight and fires straight at the API**: the preflight check that `doctor` runs (auth discovery) is not reused by `prompt` to emit a fast typed error before attempting the network call. Both Gaebal's pinpoint (prompt hanging silently on older HEAD) and the current behavior (prompt hitting auth gate after a brief API attempt) stem from the same root: prompt does not short-circuit at the point where `doctor` already knows auth is absent. If `doctor` can emit `kind:"doctor"` with `auth.status:"warn"` in ~20ms without a network call, `prompt` should emit `kind:"missing_credentials"` in the same window and output it to stdout. **Required fix shape:** (a) `prompt --output-format json` must write the `kind:"missing_credentials"` JSON envelope to **stdout**, not stderr — same fix as #447 for all error envelopes; (b) add `prompt_ready:bool` and `prompt_blocked_reason:string|null` to the `auth` check in `doctor --output-format json`; derive it as `api_key_present || auth_token_present || legacy_saved_oauth_present`; (c) `prompt` must run the credential preflight check (same codepath as doctor's auth check) before attempting any API call and emit `{"kind":"missing_credentials","prompt_blocked_reason":"auth_missing"}` on **stdout** with exit 1 if the check fails; (d) `--output-format json` stdout routing fix must cover: `prompt`, `session list` (cross-ref #449), `skills uninstall` (cross-ref #431), `resume` (cross-ref #435), `acp serve` (cross-ref #443) — the full `kind:"missing_credentials"` class; (e) regression test: `claw prompt hello --output-format json` with no creds writes JSON to stdout (0 bytes stderr), exits 1, `kind:"missing_credentials"`, in under 200ms (no network attempt). **Why this matters:** `prompt` is the primary consumer entry point. Auth-absent failure routing to stderr breaks every automation wrapper that captures `$(claw prompt ... --output-format json)`. The `doctor` preflight metadata gap means auth-readiness checks require parsing 5 legacy fields instead of reading one boolean. Cross-references #447 (all JSON error envelopes on stderr), #449 (session list hits auth gate), #431 (skills uninstall hits auth gate), #357 (auth gate on local ops cluster), #422 (exit-code parity). Source: Jobdori live dogfood, `a35ee9a0`, 2026-05-16. 450. **`prompt` emits `kind:"missing_credentials"` JSON on STDERR (not stdout), leaving stdout at 0 bytes — automation pattern `output=$(claw prompt hello --output-format json)` captures nothing on auth-absent failure; `doctor` correctly surfaces `auth.status:"warn"` with `api_key_present:false` but exposes no `prompt_ready:false` field that automation can check before invoking `prompt`** — dogfooded 2026-05-16 by Jobdori on `a35ee9a0` in response to Clawhip pinpoint nudge at `1505208225321062521`. Exact reproduction (isolated env, no creds, fresh git repo, HEAD `a35ee9a0`): `timeout 5 env -i HOME=$ISOLATED_HOME PATH=$PATH CLAW_CONFIG_HOME=$PROBE/.claw-cfg claw prompt hello --output-format json > stdout.txt 2> stderr.txt` → stdout = **0 bytes**, stderr = 195 bytes containing `{"error":"missing Anthropic credentials…","exit_code":1,"hint":null,"kind":"missing_credentials","type":"error"}`, exit code 1. Confirms Gaebal's `1505208553793781792` pinpoint that `prompt` timeout + zero bytes was the prior state — HEAD `a35ee9a0` now correctly exits 1 with `kind:"missing_credentials"` **but the envelope is still routed to stderr** (issue #447 class, same class as prior entries #422, #435). **Contrast with `doctor`:** `claw doctor --output-format json 2>/dev/null` succeeds to stdout with `checks[auth].status:"warn"`, `api_key_present:false`, `auth_token_present:false` — but the auth check has no `prompt_ready:false` field. Automation that gates on `doctor` before invoking `prompt` must re-derive readiness from `api_key_present && auth_token_present` — there is no single canonical boolean. **Three compound problems:** (a) **stdout-empty on `--output-format json` failure**: same class as #447; `prompt`'s error envelope goes to stderr, not stdout. The canonical automation idiom `if ! result=$(claw prompt "q" --output-format json); then echo "$result" | jq .kind; fi` sees `$result=""` on failure — the jq call gets nothing. All `--output-format json` error paths must route JSON to stdout per #447 contract; (b) **`doctor` missing `prompt_ready` field**: `doctor --output-format json` already knows auth is absent (`api_key_present:false`) but surfaces no derived `prompt_ready:bool` or `prompt_blocked_reason:string` field. Automation must infer readiness from `api_key_present || auth_token_present || legacy_*_present` — a 5-field OR across legacy fields that is fragile as auth mechanisms evolve. A single `prompt_ready:false` (with `prompt_blocked_reason:"auth_missing"`) inside the `auth` check would give downstream a stable contract; (c) **`claw prompt` with no auth does no preflight and fires straight at the API**: the preflight check that `doctor` runs (auth discovery) is not reused by `prompt` to emit a fast typed error before attempting the network call. Both Gaebal's pinpoint (prompt hanging silently on older HEAD) and the current behavior (prompt hitting auth gate after a brief API attempt) stem from the same root: prompt does not short-circuit at the point where `doctor` already knows auth is absent. If `doctor` can emit `kind:"doctor"` with `auth.status:"warn"` in ~20ms without a network call, `prompt` should emit `kind:"missing_credentials"` in the same window and output it to stdout. **Required fix shape:** (a) `prompt --output-format json` must write the `kind:"missing_credentials"` JSON envelope to **stdout**, not stderr — same fix as #447 for all error envelopes; (b) add `prompt_ready:bool` and `prompt_blocked_reason:string|null` to the `auth` check in `doctor --output-format json`; derive it as `api_key_present || auth_token_present || legacy_saved_oauth_present`; (c) `prompt` must run the credential preflight check (same codepath as doctor's auth check) before attempting any API call and emit `{"kind":"missing_credentials","prompt_blocked_reason":"auth_missing"}` on **stdout** with exit 1 if the check fails; (d) `--output-format json` stdout routing fix must cover: `prompt`, `session list` (cross-ref #449), `skills uninstall` (cross-ref #431), `resume` (cross-ref #435), `acp serve` (cross-ref #443) — the full `kind:"missing_credentials"` class; (e) regression test: `claw prompt hello --output-format json` with no creds writes JSON to stdout (0 bytes stderr), exits 1, `kind:"missing_credentials"`, in under 200ms (no network attempt). **Why this matters:** `prompt` is the primary consumer entry point. Auth-absent failure routing to stderr breaks every automation wrapper that captures `$(claw prompt ... --output-format json)`. The `doctor` preflight metadata gap means auth-readiness checks require parsing 5 legacy fields instead of reading one boolean. Cross-references #447 (all JSON error envelopes on stderr), #449 (session list hits auth gate), #431 (skills uninstall hits auth gate), #357 (auth gate on local ops cluster), #422 (exit-code parity). Source: Jobdori live dogfood, `a35ee9a0`, 2026-05-16.
451. **Dogfood automation can silently run probes in the wrong repository/worktree when adjacent checkouts share similarly named binaries and stale build artifacts, so reports may mix evidence from Clawdbot/OMX with claw-code** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 12:00/12:30 UTC nudge cycle. While following a tmux-hook JSON lifecycle probe, the shell reported `/home/bellman/clawd` as the top-level worktree and executed `node dist/cli/omx.js ...` from Clawdbot/OMX artifacts instead of a claw-code checkout; a later correction found the actual claw-code repos under `/home/bellman/Workspace/claw-code-*`, including one `main` checkout hundreds of commits behind `origin/main`. The transcript therefore briefly contained plausible-looking CLI evidence from the wrong product tree before git provenance checks caught it. **Required fix shape:** (a) before dogfood probes, emit a mandatory machine-readable provenance preflight with repo root, remote URL, branch, HEAD, upstream HEAD, ahead/behind counts, binary path, and embedded build SHA when available; (b) make report templates include this provenance block before any command evidence; (c) warn or block when the requested product name does not match the remote/package/binary identity, or when the checkout is behind the target upstream by a configured threshold; (d) add regression coverage around multi-worktree/multi-product environments proving dogfood harnesses cannot silently attribute evidence from a neighboring repo or stale artifact. **Why this matters:** stale-branch confusion is not just a git annoyance; it corrupts the evidence chain. Claws can land or report fixes against the wrong codebase if the harness does not prove repo and binary identity before probing. Source: gaebal-gajae dogfood response to Clawhip messages `1506265193863446711` and `1506272743895728249` on 2026-05-19.
452. **Validated claw-code checkouts can have no runnable local debug binary, and the failure is a raw shell `No such file or directory` instead of a typed build/provenance preflight result** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 13:00 UTC nudge after applying the provenance guard from #451. The corrected claw-code checkout was `/home/bellman/Workspace/claw-code-pr2967` with remote `https://github.com/ultraworkers/claw-code.git`, branch `docs/roadmap-workdir-provenance`, HEAD `6183d95`, upstream `origin/main` at `f8e1bb7`, and ahead/behind `1/0`. The first real probe then failed before reaching claw-code logic: `timeout --kill-after=1s 8s ./rust/target/debug/claw plugins list --output-format json` exited `127` with stderr `timeout: failed to run command './rust/target/debug/claw': No such file or directory` and empty stdout. This is distinct from stale-binary mismatch: here the selected checkout is identifiable, but there is no built binary and no canonical instruction/result telling automation whether to build, locate an installed `claw`, or stop. **Required fix shape:** (a) provide a canonical `claw dogfood preflight --output-format json` or equivalent script that checks expected binary paths, installed binary fallback, embedded build SHA, workspace HEAD, and build freshness before any product probe; (b) when the expected local binary is absent, return a typed result such as `kind:"dogfood_preflight"`, `binary_status:"missing"`, `expected_path`, `recommended_build_command`, and `can_use_installed_binary:false|true`; (c) integrate the preflight into dogfood report templates so a missing build artifact is reported as startup friction, not a raw shell 127; (d) add regression/fixture coverage for missing binary, stale binary, matching debug binary, and installed-binary fallback cases. **Why this matters:** after #451 proves the repo is right, claws still need to prove the executable exists and corresponds to that repo. A raw shell missing-file error wastes a nudge cycle and tempts operators to run whatever stale binary happens to be nearby. Source: gaebal-gajae dogfood response to Clawhip message `1506280293831544997` on 2026-05-19.
453. **Plugin list JSON can report bundled plugin `source` paths from a stale user registry in a different checkout, with no stale-source warning or current-bundled-root distinction** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 13:30 UTC nudge after a successful local build in `/home/bellman/Workspace/claw-code-pr2967` (branch `docs/roadmap-workdir-provenance`, HEAD `25d663d`, binary `./rust/target/debug/claw` reporting `git_sha:"25d663d"`). Running `./rust/target/debug/claw plugins list --output-format json` returned structured `plugins[]`, but both bundled plugin entries reported `source` under `/home/bellman/Workspace/claw-code-parity-worktrees/clawcode-ux-enhance/...` instead of the current checkout. Cleaning and rebuilding the `plugins` crate did not change the output; the stale paths came from `~/.claw/plugins/installed.json`, where bundled plugin records persisted old `source.path` values. The JSON payload gave no `source_stale`, `source_exists`, `current_bundled_root`, `registry_path`, or `source_origin:"registry"` cue, so automation would treat another worktree's bundled plugin path as current truth. **Required fix shape:** (a) for bundled plugins, derive/display source from the current binary/workspace bundled root rather than a persistent user registry path when possible; (b) if registry source is retained, expose `registry_path`, `source_origin`, `source_exists`, `source_matches_current_bundle_root`, and `current_bundled_root` fields; (c) warn in text mode and JSON diagnostics when bundled plugin registry records point outside the current binary/workspace provenance; (d) add regression coverage where `installed.json` contains stale bundled paths from another checkout and `plugins list --output-format json` either self-heals or marks the source stale. **Why this matters:** plugin lifecycle actions rely on source provenance. If a fresh build from checkout A reports bundled plugin sources from checkout B, claws can inspect, enable, update, or debug the wrong plugin tree and misattribute lifecycle failures to current code. Source: gaebal-gajae dogfood response to Clawhip message `1506287843021160500` on 2026-05-19.
454. **`plugins help --output-format json` returns a success-shaped plugin inventory plus `Unknown /plugins action 'help'` prose instead of structured plugin command help or supported lifecycle actions** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 14:00 UTC nudge on a freshly built binary from `/home/bellman/Workspace/claw-code-pr2967` (`./rust/target/debug/claw version --output-format json` reported `git_sha:"25d663d"`; the worktree had roadmap-only commits ahead of that source build). Running `./rust/target/debug/claw plugins help --output-format json` exited `0` and returned JSON with `kind:"plugin"`, `action:"help"`, `status:"ok"`, a full `plugins[]` inventory, and message `Unknown /plugins action 'help'. Use list, install, enable, disable, uninstall, or update.` It did not return `supported_actions[]`, usage, action metadata, destructive-action markers, target requirements, or a typed `unsupported_action` / `help_unavailable` status. The same probe also confirmed `plugins show example-bundled --output-format json` still returns `status:"ok"` plus an unknown-action message and no selected `plugin` object, matching the existing unsupported-show class, but the new pinpoint is the absence of a plugin lifecycle discovery/help contract. **Required fix shape:** (a) implement `plugins help --output-format json` as a real help/discovery payload with `supported_actions[]`, per-action `requires_target`, `destructive`, `resume_safe`/automation notes, usage, and examples; (b) if `help` is intentionally unsupported, return a non-ok typed JSON envelope with `code:"unsupported_plugin_action"` and structured `supported_actions[]`, not `status:"ok"`; (c) avoid attaching full plugin inventory to unsupported/help responses unless requested, or mark it as incidental; (d) add regression coverage proving plugin lifecycle help is machine-readable and does not require scraping `message` for available actions. **Why this matters:** plugin lifecycle commands include install/enable/disable/update/uninstall; claws need a safe discovery surface before attempting mutations. A success-shaped unknown-help response with only prose action names keeps lifecycle automation brittle and encourages trial-and-error against mutating commands. Source: gaebal-gajae dogfood response to Clawhip message `1506295397285494905` on 2026-05-19.
455. **Plugin help entrypoints hang before producing any help bytes, and with normal user config they emit only a deprecation warning before timeout** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 14:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. Bounded probes of `plugins --help --output-format json`, `plugins help --output-format json`, and `plugins list --help --output-format json` each timed out after 8s with `stdout=0`; under the normal user config each had `stderr=121` containing only the repeated config deprecation warning, and under an isolated clean `HOME`/`CLAW_CONFIG_HOME` even `plugins --help` and JSON help forms timed out with both stdout and stderr empty. This is distinct from #454's success-shaped unknown-help JSON observed on the action-dispatch path: the flag-style/local help path can hang before returning any help or typed JSON at all. **Required fix shape:** (a) route `plugins --help`, `plugins help`, and subcommand help forms through static help rendering before config/plugin registry loading; (b) make JSON help return bounded stdout JSON with `kind:"plugin"`, `action:"help"`, `supported_actions[]`, and usage metadata; (c) if dynamic plugin state is intentionally consulted, enforce a short internal timeout and return a typed `plugin_help_unavailable` JSON error instead of zero-byte hangs; (d) add regression coverage with clean home and deprecated-config home proving plugin help emits bytes promptly and does not initialize slow lifecycle/registry paths. **Why this matters:** help must be the safe escape hatch when plugin lifecycle is broken. If every plugin help spelling can hang before bytes, claws cannot discover valid plugin actions, recover from registry issues, or explain how to fix lifecycle state without external docs. Source: gaebal-gajae dogfood response to Clawhip message `1506302942754639892` on 2026-05-19.
456. **Static `--help --output-format json` hangs across multiple local lifecycle namespaces under a clean home, so help discovery is not a reliable no-side-effect escape hatch** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 15:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. After pushing the accumulated roadmap branch, clean-environment probes using isolated `HOME` and `CLAW_CONFIG_HOME` showed that `mcp --help --output-format json`, `agents --help --output-format json`, `skills --help --output-format json`, `memory --help --output-format json`, and `session --help --output-format json` each timed out after 8s with `stdout=0` and `stderr=0`. This extends the plugin-specific #455 into a shared parser/help-layer gap: even command namespaces whose help should be static and local can enter a zero-byte hang before any JSON or text help is emitted. **Required fix shape:** (a) centralize `--help`/`help` handling before config, auth, registry, session, MCP, memory, or plugin initialization for all local lifecycle namespaces; (b) make `--output-format json` help return a bounded stdout payload with `kind:"help"`, namespace, usage, supported actions/sections, output formats, and side-effect/auth requirements; (c) add a global deterministic help timeout guard that returns typed JSON such as `kind:"help_unavailable"` instead of allowing zero-byte hangs; (d) add clean-home regression coverage for `mcp`, `agents`, `skills`, `memory`, `session`, and `plugins` help forms proving they emit bytes promptly and do not touch slow lifecycle providers. **Why this matters:** help is the only safe discovery path when lifecycle state is broken. If help itself can hang with no bytes, claws cannot learn how to inspect or recover MCP, agents, skills, memory, sessions, or plugins without external docs or guesswork. Source: gaebal-gajae dogfood response to Clawhip message `1506310493080518767` on 2026-05-19.
457. **Root help is bounded in text mode, but `help --output-format json` and command `--help --output-format json` convert help into a zero-byte hang** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 15:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. In an isolated clean `HOME`/`CLAW_CONFIG_HOME`, `./rust/target/debug/claw --help` and `./rust/target/debug/claw help` both exited 0 and printed 7403 bytes of root text help. But `help --output-format json`, `version --help --output-format json`, `doctor --help --output-format json`, and `status --help --output-format json` each timed out after 8s with `stdout=0` and `stderr=0`. This narrows #456: the help renderer itself is capable of returning promptly, but the parser/order path that combines help with JSON output appears to route into a different slow/non-returning path. **Required fix shape:** (a) parse `--help`/`help` before selecting command execution paths, auth, provider, session, or lifecycle initialization, while still preserving requested output format; (b) make root and command help JSON static/bounded with `kind:"help"`, `scope`, `command`, `usage`, `options`, `examples`, and `supported_output_formats`; (c) add regression coverage proving `claw --help`, `claw help`, `claw help --output-format json`, and representative command help forms all return within a small deterministic budget under clean home; (d) ensure JSON help does not silently fall back to text or zero-byte timeout. **Why this matters:** this is a parser-order failure in the safest command surface. Operators can get text help, but the moment automation asks for JSON discovery, help becomes a hang, forcing claws back to prose scraping or external docs. Source: gaebal-gajae dogfood response to Clawhip message `1506318038167847045` on 2026-05-19.
458. **Global output-format flag ordering is parser-hostile, and even `version --output-format json` can hang under clean env despite normal-env success** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 16:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with normal-env `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. Clean-environment flag-order probes showed `--output-format json --help`, `--output-format json help`, `--output-format json version`, `--version --output-format json`, and `--output-format json --version` each failed immediately with text-mode stderr only, e.g. `[error-kind: cli_parse] error: unknown option: --output-format json --help`, and `stdout=0`. The parser appears to treat the whole trailing string as one unknown option rather than recognizing a global output-format flag before the command. Separately, in the same clean `HOME`/`CLAW_CONFIG_HOME`, canonical `version --output-format json` timed out after 8s with `stdout=0`/`stderr=0`, even though the same command succeeds in the normal environment. **Required fix shape:** (a) make global flags such as `--output-format json` accepted before or after the subcommand, or return structured JSON `cli_parse` errors on stdout when JSON format is requested anywhere in argv; (b) parse flag values as separate tokens in error reporting instead of echoing combined strings like `--output-format json --help` as one option; (c) ensure `version` is fully local/static and cannot hang under clean env or missing config/auth; (d) add clean-env regression coverage for `version --output-format json`, `--output-format json version`, `--version --output-format json`, and JSON parse errors with stdout envelopes. **Why this matters:** claws often put global flags first for CLI uniformity and run in sanitized envs. If global JSON selection is order-sensitive and local version can hang only under clean env, startup probes become unreliable exactly in CI/sandbox contexts. Source: gaebal-gajae dogfood response to Clawhip message `1506325598245748828` on 2026-05-19.
459. **Dogfood timeout claims lack a required retry/evidence contract, so transient hangs can be recorded as durable product gaps without immediate reproducibility metadata** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 16:30 UTC nudge while narrowing #458 on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. The previous 16:00 pass saw clean-env `version --output-format json` time out with zero bytes, but a focused 16:30 retry matrix using isolated `HOME`/`CLAW_CONFIG_HOME` plus minimal env variants (`TERM`, `USER`/`LOGNAME`, `SHELL`, `LANG`/`LC_ALL`, and all combined) returned valid version JSON every time. That means the earlier timeout may have been transient harness load, process scheduling, or invocation interference, while the report format had no mandatory retry count, timing, command log artifact, or “reproduced N/M” field to distinguish flaky evidence from stable behavior. **Required fix shape:** (a) dogfood timeout reports must include retry count, per-attempt exit code/stdout/stderr byte counts, elapsed duration, env summary, binary provenance, and whether the failure reproduced after process isolation; (b) add a standard `timeout_evidence` block to report templates and ROADMAP entries before filing zero-byte hang claims; (c) classify un-reproduced hangs as `flaky_unconfirmed` with follow-up probes instead of stable product bugs; (d) provide a small harness command that runs bounded retries and emits machine-readable evidence JSON. **Why this matters:** zero-byte timeouts are high-severity but easy to misattribute. Without a retry/evidence contract, claws can pollute the backlog with transient scheduler artifacts or miss real nondeterministic hangs because the evidence shape is too thin. Source: gaebal-gajae dogfood response to Clawhip message `1506333141571211314` on 2026-05-19.
460. **Root `help --output-format json` is reproducibly bounded but only wraps 7.4KB of prose in `{kind,message}`, with no structured command or slash-command schema** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 17:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. Applying the retry/evidence discipline from #459, three clean-home attempts of `./rust/target/debug/claw help --output-format json` all exited 0 with `stdout=7563`, `stderr=0`, valid JSON keys exactly `kind,message`, `kind:"help"`, and a `message` string of length 7401. There were no `commands[]`, `options[]`, `slash_commands[]`, resume-safety flags, output-format support metadata, side-effect/auth requirements, or examples as structured fields. This supersedes the flaky zero-byte hang framing from #457 for root help: the stable reproducible gap is schema opacity, not timeout. **Required fix shape:** (a) keep `message` for human rendering but add a versioned structured help schema with `schema_version`, `commands[]`, `global_options[]`, `slash_commands[]`, `examples[]`, and `related_docs[]`; (b) include per-command fields such as `name`, `aliases`, `usage`, `description`, `supports_json`, `requires_auth`, `side_effects`, and `resume_safe` where applicable; (c) expose slash-command metadata without requiring prose scraping; (d) add regression coverage proving root help JSON has stable structured fields and that old `message` remains optional/backward-compatible. **Why this matters:** help JSON is the bootstrap discovery surface for claws. Valid JSON that contains only prose still forces automation to scrape text before choosing safe commands or resume paths. Source: gaebal-gajae dogfood response to Clawhip message `1506340691431657472` on 2026-05-19.
461. **Command-specific `--help --output-format json` reproducibly zero-byte hangs even though root JSON help returns bounded prose JSON** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 17:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. After #460 confirmed root `help --output-format json` is bounded but schema-opaque, two clean-home attempts each for `status --help --output-format json`, `doctor --help --output-format json`, `version --help --output-format json`, and `sandbox --help --output-format json` all timed out after 8s with `stdout=0` and `stderr=0`. This establishes a split contract: root JSON help reaches the help serializer, while command-specific JSON help falls into a non-returning command execution/parser path. **Required fix shape:** (a) add a command-help dispatch layer that catches `<command> --help` before entering the command's runtime handler; (b) share the same bounded JSON help schema from #460 for command-specific help, with fields `kind:"help"`, `command`, `usage`, `options`, `examples`, `supports_json`, `requires_auth`, and `side_effects`; (c) ensure local/static commands like `version`, `status`, `doctor`, and `sandbox` never initialize slow providers just to render help; (d) add clean-home regression coverage proving command-specific JSON help emits bytes promptly for representative static and lifecycle commands. **Why this matters:** claws often discover command contracts one command at a time. If root help is available but every command's JSON help hangs, automation still cannot inspect option-level semantics safely and must scrape root prose or guess. Source: gaebal-gajae dogfood response to Clawhip message `1506348241128788111` on 2026-05-19.
462. **Text-mode `<command> --help` also zero-byte hangs, proving the bug is command-help dispatch rather than JSON serialization** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 18:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. After #461 showed command-specific JSON help hangs, a text-mode retry matrix in isolated clean `HOME`/`CLAW_CONFIG_HOME` showed two attempts each for `status --help`, `doctor --help`, `version --help`, `sandbox --help`, `mcp --help`, `agents --help`, and `skills --help` all timed out after 6s with `stdout=0` and `stderr=0`. Root `--help` and `help` remain bounded, so the split is not help text rendering generally and not JSON formatting specifically; it is the command-specific help dispatch path failing to intercept `<command> --help` before some non-returning runtime path. **Required fix shape:** (a) implement a first-stage argv parser that recognizes `<command> --help` and `<command> help` for every registered command before command runtime initialization; (b) render static text help in text mode and structured JSON help in JSON mode from the same command metadata registry; (c) add regression coverage for both text and JSON help for representative static commands (`version`, `status`, `doctor`, `sandbox`) and lifecycle commands (`mcp`, `agents`, `skills`, `plugins`); (d) ensure every command-help path has a bounded no-provider/no-auth/no-config execution budget. **Why this matters:** users do not only run root `--help`; they naturally ask `claw status --help` or `claw mcp --help`. If that path hangs silently, the product loses the most basic local recovery surface before any real action starts. Source: gaebal-gajae dogfood response to Clawhip message `1506355792582938665` on 2026-05-19.
463. **Root help advertises direct slash examples like `claw /skills`, but direct slash behavior is inconsistent: `/skills` runs a huge local report, `/help` aliases root help, while `/status` is rejected as interactive-only despite being marked resume-safe** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 18:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. Root help examples include `claw /skills`, and clean-home probes showed direct `claw /skills` exits 0 and prints a 27KB skill inventory, while direct `claw /help` exits 0 and prints root help. But direct `claw /status` exits 1 with `slash command /status is interactive-only... use claw --resume SESSION.jsonl /status ... when the command is marked [resume] in /help`, even though `/status` is explicitly marked `[resume]` in root help and has a top-level sibling `claw status`. The same surface therefore mixes three semantics for direct slash invocation: accepted alias, accepted local slash report, and rejected interactive-only/resume-only command. **Required fix shape:** (a) define a single direct-slash CLI contract: either reject all slash commands outside REPL/resume with structured guidance, or allow resume-safe/local slash commands consistently; (b) if allowing direct slash commands, route `/status` to the same local/resume-safe status serializer as `claw status` or require `--resume` with a typed `resume_required` code; (c) make help examples distinguish top-level commands from slash commands and avoid advertising `claw /skills` unless direct slash invocation is intentional for the whole supported set; (d) add regression coverage for `/help`, `/skills`, `/status`, `/mcp`, `/agents`, and their top-level equivalents proving consistent direct/resume/text/json behavior. **Why this matters:** claws copy help examples literally. If `claw /skills` works but `claw /status` says interactive-only despite `[resume]`, automation cannot infer which slash commands are safe outside the REPL and will oscillate between direct, top-level, and resume forms. Source: gaebal-gajae dogfood response to Clawhip message `1506363340048564425` on 2026-05-19.
464. **Global `--output-format json` placement is broken for top-level subcommands: post-subcommand placement silently hangs, while pre-subcommand placement is rejected as `cli_parse` despite help documenting `--output-format` as a global flag** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 19:00/19:30 UTC nudges on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. Root help lists `--output-format FORMAT` in the global Flags section and examples like `claw [--model MODEL] [--output-format text|json] prompt TEXT`, while top-level commands (`claw status`, `claw doctor`, `claw mcp`, `claw skills`, `claw version`) advertise local diagnostic/report surfaces. Clean-home probes showed two distinct bad paths: `claw version --output-format json`, `claw status --output-format json`, and `claw skills --output-format json` timed out after 5s with `stdout=0`/`stderr=0`; the more canonical GNU-style global placement `claw --output-format json version`, `claw --output-format json status`, and `claw --output-format json skills` exited 1 with `[error-kind: cli_parse] error: unknown option: --output-format json <command>`. The only working form observed for `version` is the special local parser path used by `claw version --output-format json` in a non-clean environment/provenance preflight, which contradicts the clean-home bounded test and suggests the parser/runtime path is environment-sensitive as well as placement-sensitive. **Required fix shape:** (a) make `--output-format` a true global flag accepted before any subcommand and before slash commands; (b) make top-level local commands also accept trailing `--output-format` if the project wants common CLI ergonomics; (c) normalize both placements into one parsed `OutputFormat` before command dispatch; (d) ensure parse errors in JSON-requested mode emit structured JSON rather than prose-on-stderr; (e) add clean-home regression coverage for `claw --output-format json version|status|doctor|mcp|skills` and `claw version|status|doctor|mcp|skills --output-format json`, with bounded no-provider execution. **Why this matters:** claws and shell users routinely place global flags either before or after subcommands. A machine-readable output flag that sometimes hangs and sometimes parse-errors means automation cannot reliably request JSON for the exact local diagnostics it needs during recovery. Source: gaebal-gajae dogfood response to Clawhip messages `1506370889653027012` and `1506378443812765756` on 2026-05-19.
465. **`claw skills` is technically bounded but operationally noisy: the default text output dumps full descriptions for every discovered skill (~27KB / 65 skills in clean-home dogfood), unlike `status`, `doctor`, `mcp`, `sandbox`, and `agents` which stay compact enough for recovery logs** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 20:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. Clean-home text probes showed `version`, `status`, `doctor`, `mcp`, `sandbox`, and `agents` all exit promptly with compact diagnostic reports (`version` 136 bytes, `status` 1274 bytes, `doctor` 2519 bytes, `mcp` 117 bytes, `sandbox` 352 bytes, `agents` 17 bytes). `skills` also exits 0, but emits 27,573 bytes by default because it prints every skill name plus full description. This makes `claw skills` a poor first-response diagnostic in clawhip logs, tmux tails, CI failure artifacts, and copied support snippets: the useful inventory count and roots are buried under pages of prose. This is distinct from discovery-scope/security issues (#85/#95): even when the skill set is legitimate, the default report shape is too verbose for a recovery command. **Required fix shape:** (a) make default text `claw skills` compact: counts by source/root plus names only, truncated with an explicit `--verbose` hint; (b) add `claw skills --verbose` or `claw skills list --verbose` for full descriptions; (c) add `--format compact|verbose` or reuse `--compact` if the CLI standardizes it; (d) keep JSON mode complete but add `summary` and `entries[].description` fields so consumers can choose; (e) add regression coverage enforcing that default text output for 50+ skills stays under a small byte/line budget while verbose preserves current detail. **Why this matters:** local diagnostics should be safe to paste and scan during failures. A 27KB default skill dump hides the actual signal and makes every dogfood/support loop noisier than necessary. Source: gaebal-gajae dogfood response to Clawhip message `1506385992368652489` on 2026-05-19.
466. **Syntactically valid MCP config with a nonexistent command is reported as healthy/configured by `doctor`, `mcp`, and `status` instead of surfacing executable reachability as degraded** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 20:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. In a temp workspace containing only `.claw.json` with `mcpServers.broken.command:"/definitely/not/a/real/mcp-server"`, clean-home text probes showed `doctor` exits 0 with `Failures 0`, `Config Status ok`, and `Boot preflight ... mcp=true · servers 1`; `mcp` exits 0 and lists `broken stdio project /definitely/not/a/real/mcp-server --serve`; `status` exits 0 and reports `Boot preflight ... mcp=true plugins=true last_failed=none`. None of the three surfaces attempts even a cheap executable existence/PATH reachability check, so a server that cannot possibly launch is indistinguishable from a configured usable MCP server until the first runtime tool call fails. This is distinct from malformed-config degraded-mode items (#143/#144/#440): here the JSON shape is valid and the parser succeeds, but lifecycle readiness is false. **Required fix shape:** (a) add an MCP executable preflight pass that classifies each stdio server as `reachable:true|false|unknown` using absolute-path existence/executable-bit checks and PATH lookup for bare commands, without launching untrusted code; (b) expose per-server fields in `claw mcp` / JSON (`launch_status`, `command_exists`, `command_executable`, `path_resolution`, `error_kind:"mcp_command_not_found"`); (c) make `doctor` add an `mcp_reachability` check with `status:"warn"` or `"fail"` when any configured server command is missing; (d) make `status` distinguish `mcp_configured:true` from `mcp_reachable:false` instead of the current single `mcp=true`; (e) regression test with one valid `/bin/echo` server and one nonexistent absolute path proving partial status is reported. **Fresh mixed-PATH proof (21:00 UTC):** a temp config containing one PATH-resolvable server (`pathEcho.command:"echo"`) and one missing bare command (`missingBare.command:"definitely-not-a-real-mcp-bare-command-xyz"`) still made `mcp` list both as configured, `doctor` report `Failures 0` and `mcp=true · servers 2`, and `status` report `mcp=true` with no degraded marker. So the fix must handle both absolute paths and PATH lookup for bare commands, and it must preserve partial success (`echo` reachable, missingBare not found) instead of collapsing both into `configured`. **Why this matters:** MCP failures are often setup/path mistakes. If doctor says failures 0 and mcp=true while the command path does not exist, claws and users waste turns discovering the break only after a blocked tool call. Source: gaebal-gajae dogfood response to Clawhip messages `1506393539385491598` and `1506401088801083495` on 2026-05-19.
467. **Bare `claw plugins` / `claw plugin` returns the plugin inventory, but the natural explicit action `claw plugins list` / `claw plugin list` zero-byte hangs; singular/plural aliases are wired for the default action but not for the `list` subaction** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 21:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. In isolated clean `HOME`/`CLAW_CONFIG_HOME`, `plugins` and `plugin` each exited 0 and printed the two bundled plugins (`example-bundled`, `sample-hooks`) in text mode. But `plugins list` and `plugin list` each timed out after 8s with `stdout=0` and `stderr=0`. `plugins help` and `plugin help` also timed out, while direct `/plugins` and `/plugin` were rejected as interactive-only, showing that there are at least three parser paths for the same lifecycle namespace. This is a narrower current-main follow-up to the historical plugin route/help items (#78/#145/#348/#420/#454/#455): the route now exists for the default inventory, but adding the explicit canonical `list` action drops into a different non-returning path. **Required fix shape:** (a) normalize `plugin` and `plugins` aliases plus omitted action into one parser action before dispatch (`None` and `Some("list")` must be equivalent); (b) route `help` to static plugin help before plugin registry/lifecycle initialization; (c) add a deterministic timeout guard or typed `plugin_action_unavailable` envelope around plugin action dispatch so unsupported/misparsed actions cannot hang silently; (d) add clean-home regression coverage for `plugins`, `plugins list`, `plugin`, `plugin list`, `plugins help`, and `plugin help` in text and JSON modes, proving the first four produce the same inventory and help emits bounded usage. **Why this matters:** `list` is the most obvious plugin lifecycle action and is already the documented/discovery word from other lifecycle namespaces (`mcp list`, `agents list`, `skills list`). If bare inventory works but explicit list hangs, claws cannot safely choose between terse default and explicit action forms, and plugin support remains trial-and-error. Source: gaebal-gajae dogfood response to Clawhip message `1506408638883954768` on 2026-05-19.
468. **Explicit subactions hang across local lifecycle namespaces: bare `agents`, `mcp`, `skills`, `sandbox`, and `doctor` return bounded diagnostics, but natural explicit forms (`agents list`, `mcp list`, `skills list`, `sandbox status`, `doctor check`) zero-byte hang** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 22:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. Clean-home text probes showed the bare commands are usable: `agents` exits 0 (`No agents found.`), `mcp` exits 0 with `Configured servers 0`, `skills` exits 0 with inventory, `sandbox` exits 0 with sandbox state, and `doctor` exits 0 with the full health report. But adding the most natural explicit action caused zero-byte timeouts after 8s: `agents list`, `mcp list`, `skills list`, `sandbox status`, and `doctor check` all produced `stdout=0` and `stderr=0`. This broadens #467's plugin-specific `plugins list` hang into a shared parser/action-normalization bug: omitted default action works, but spelling the default action explicitly routes to a non-returning path. **Required fix shape:** (a) define a per-namespace action table where omitted action normalizes to the documented default (`list` for inventory namespaces, `status` for status namespaces, `check`/`run` only if supported); (b) reject unsupported explicit actions with typed bounded errors (`unknown_action`, `supported_actions[]`) instead of falling through to prompt/runtime dispatch; (c) make `agents list`, `mcp list`, and `skills list` equivalent to their bare forms; decide/document whether `sandbox status` and `doctor check` are aliases or unsupported; (d) add clean-home regression coverage for bare/default/unsupported explicit actions in text and JSON across agents, mcp, skills, plugins, sandbox, and doctor. **Why this matters:** users and claws naturally prefer explicit commands in automation (`mcp list`, `agents list`) because they are self-documenting. If explicit defaults hang while bare commands work, every script has to learn undocumented terse forms and cannot safely derive commands from help/usage text. Source: gaebal-gajae dogfood response to Clawhip message `1506416189616947210` on 2026-05-19.
469. **Unexpected positional arguments after local verbs zero-byte hang instead of returning bounded parse errors; even `version extra` hangs, proving the parser does not fail closed once a local subcommand has extra tokens** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 22:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. In isolated clean `HOME`/`CLAW_CONFIG_HOME`, bounded 8s probes of `version extra`, `status extra`, `doctor extra`, `sandbox extra`, `agents extra`, `mcp extra`, `skills extra`, and `plugins extra` all timed out with `stdout=0` and `stderr=0`. This is broader than #468's explicit-default-action hang: the extra token does not need to be a plausible action like `list` or `status`; any unexpected positional can route a local, no-auth diagnostic command into a non-returning path. It also refreshes the older extra-arg/fallthrough findings (#127/#147) with current-binary evidence where the failure mode is now a silent hang rather than a visible missing-credentials prompt. **Required fix shape:** (a) every local subcommand parser must declare accepted positional arity and reject extra args before prompt/runtime dispatch; (b) emit a typed bounded error such as `kind:"unexpected_argument"`, `command`, `argument`, `supported_usage`, and `supported_actions[]` where relevant; (c) in JSON-requested mode, route that envelope to the documented JSON stream with nonzero exit; (d) add regression coverage for `version extra`, `status extra`, `doctor extra`, `sandbox extra`, `agents extra`, `mcp extra`, `skills extra`, and `plugins extra` proving they return promptly and do not enter provider/prompt/plugin/session runtime. **Why this matters:** typos and stale wrapper scripts commonly append leftover tokens. A local health command must fail closed with usage guidance, not hang with no bytes; otherwise orchestrators cannot distinguish typo, parser deadlock, provider stall, or lifecycle startup block. Source: gaebal-gajae dogfood response to Clawhip message `1506423740597141665` on 2026-05-19.
470. **Root flag aliases fail closed on extra tokens, but the word alias `help` zero-byte hangs with any trailing token (`help extra`, `help --help`, `help --version`) instead of returning root help or a bounded arity error** — dogfooded 2026-05-19 from the `#clawcode-building-in-public` 23:00/23:30 UTC nudges on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. Clean-home probes showed the flag aliases are healthy/bounded: `--version` and `-V` exit 0 with version text; `--version extra`, `-V extra`, and `--help extra` exit 1 with `[error-kind: cli_parse]`. But the word help alias is fragile: `help extra`, `help --help`, and `help --version` each timed out after 6s with `stdout=0` and `stderr=0`. This narrows #469: not all root alias extra-token paths hang; the flag parser has a fail-closed path, while the `help` word alias enters the same non-returning command/prompt dispatch when trailing tokens are present. **Required fix shape:** (a) treat `help` as a first-class root command with strict arity: bare `help` renders root help; `help <topic>` either renders a static topic if supported or returns typed `unknown_help_topic`; extra flags like `help --help` and `help --version` must be handled locally; (b) never route `help ...` into provider/prompt/runtime dispatch; (c) make JSON mode preserve the same bounded behavior with `kind:"help"` or `kind:"unknown_help_topic"`; (d) add clean-home regression coverage for `help`, `help extra`, `help --help`, `help --version`, `--help extra`, `--version extra`, and `-V extra`. **Why this matters:** `help` is the recovery primitive users type when every other command is broken. If `--help extra` reports a parse error but `help extra` hangs silently, claws cannot rely on the documented `claw help` alias as a safe discovery surface. Source: gaebal-gajae dogfood response to Clawhip messages `1506431285977940009` and `1506438835775737939` on 2026-05-19.
471. **Root version aliases (`--version`, `-V`) have no JSON form and reject `--output-format json`, while the `version --output-format json` subcommand hangs under clean home — version provenance is not reliably machine-readable from the safest startup path** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 00:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with provenance preflight `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"` in the normal environment. In isolated clean `HOME`/`CLAW_CONFIG_HOME`, `version --output-format json` timed out after 6s with `stdout=0` and `stderr=0`, while `--version --output-format json`, `--output-format json --version`, `-V --output-format json`, and `--output-format json -V` all exited 1 with `[error-kind: cli_parse] unknown option: ...`. Plain `--version`/`-V` work in text mode, but there is no bounded JSON equivalent through the root flag aliases, and the subcommand JSON path is environment/placement-sensitive. This is a focused provenance/startup slice of #464: the one command claws use to prove binary identity has split semantics across root flags and subcommand forms. **Required fix shape:** (a) make `--version --output-format json` and `--output-format json --version` valid aliases for `version --output-format json`; (b) make `-V` support the same formatting contract; (c) ensure `version --output-format json` is config-free/help-free/provider-free and bounded under clean home; (d) emit a typed JSON parse error on stdout/stderr according to the project-wide JSON error-stream contract if an unsupported combination remains; (e) add clean-home regression coverage for all five forms above. **Why this matters:** binary provenance is the first fact every dogfood report and orchestrator needs. If root version flags only produce text and the JSON subcommand can hang, claws cannot safely establish which executable they are testing without relying on a special normal-environment preflight. Source: gaebal-gajae dogfood response to Clawhip message `1506446390212169839` on 2026-05-20.
472. **Malformed project `.claw.json` is silently treated as `loaded 0/N` while `doctor` still says `Config Status ok` and `runtime config loaded successfully`; `status` reports no config error at all** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 00:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. In a temp workspace with an invalid `.claw.json` containing truncated JSON (`{"mcpServers":{"bad":{}`), root recovery surfaces correctly stayed config-free: `--help`, `help`, `--version`, `-V`, and `version` all exited 0. But config-aware diagnostics silently downplayed the broken file: `status` exited 0 and reported `Config files loaded 0/5` with no parse error or degraded marker; `doctor` exited 0 with `Failures 0`, `Config Status ok`, `Summary runtime config loaded successfully`, and details `Config files loaded 0/1` plus the discovered malformed file path. This is not the older #143 fatal-status path; it is the opposite failure mode: broken config is detected enough to count as present/discovered, but the parse error is dropped and the health summary remains OK. **Required fix shape:** (a) preserve config parse/load errors per discovered file even when continuing with defaults; (b) make `doctor` config check `status:"fail"` or `"warn"` when any discovered config file fails to parse, never `ok`; (c) make `status` expose `config_load_error` / `config_files[].error` and a degraded marker while still reporting independent workspace fields; (d) distinguish `present_count`, `loaded_count`, and `failed_count`; (e) add regression coverage with malformed/truncated `.claw.json` proving root help/version remain config-free while status/doctor surface the parse error. **Why this matters:** a user with a broken config needs diagnostics to point at the exact file and parse problem. Saying `runtime config loaded successfully` while also saying `loaded 0/1` is contradictory and makes the tool look healthy while silently ignoring the user's intended MCP/plugins/permissions/model settings. Source: gaebal-gajae dogfood response to Clawhip message `1506453939443204247` on 2026-05-20.
473. **Slash-only command guidance is inconsistent: bare `claw compact` fails fast with useful guidance, but `claw compact --help` and `claw compact extra` zero-byte hang instead of returning the same guidance/help or a bounded arity error** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 01:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`. After confirming the remote `docs/roadmap-workdir-provenance` branch still had HEAD `e9db12d` (Jobdori's claimed `f997a1a8` was not present on origin at probe time), compact-surface probes showed `claw compact` exits 1 with a clear local message: `` `claw compact` is a slash command. Use `claw --resume SESSION.jsonl /compact` or start `claw` and run `/compact`.`` Direct `/compact` also exits 1 with interactive/resume guidance, and `/compact --confirm` returns a bounded unexpected-argument help block. But `compact --help` and `compact extra` each timed out after 6s with `stdout=0` and `stderr=0`. This is a parser/help arity bug distinct from the compaction-internals sentinel issue Jobdori described: the CLI already knows how to explain that `compact` is slash-only, but adding `--help` or any extra token bypasses that safe guidance path. **Required fix shape:** (a) route `compact --help` to static compact help/guidance before prompt/runtime dispatch; (b) route `compact <unexpected>` to a typed bounded `unexpected_argument` or `slash_only_command` error with resume usage; (c) make slash-only top-level shims share one helper so bare/--help/extra forms cannot drift; (d) add clean-home regressions for `compact`, `compact --help`, `compact extra`, `/compact`, `/compact --confirm`, and JSON-mode equivalents. **Why this matters:** users who follow the bare-command guidance and ask for help on the same word hit a silent hang. Recovery commands must converge toward usage, not fall off a different parser cliff as soon as a user adds `--help`. Source: gaebal-gajae dogfood response to Clawhip message `1506461484950093967` on 2026-05-20.
474. **Local diagnostic verbs and slash-only shims hang on `--help`/extra-token forms even when their bare or slash forms already have bounded guidance (`status --help`, `status extra`, `doctor --help`, `doctor extra`, `clear --help`, `clear --confirm`, `clear extra`)** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 01:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`; branch and origin were both `docs/roadmap-workdir-provenance@1208b9a` before editing. Bounded clean-home probes showed `claw clear` exits 1 with useful slash-only guidance, `/clear` and `/clear --confirm` return bounded interactive/resume guidance, and `/clear extra` returns a bounded usage block. But `clear --help`, `clear --confirm`, and `clear extra` each timed out after 6s with `stdout=0`/`stderr=0`. The same arity/help drift affects bare local diagnostics: `status --help`, `status extra`, `doctor --help`, and `doctor extra` also timed out after 6s with no bytes, despite bare `status`/`doctor` being local, bounded diagnostic commands in other probes. This generalizes #473 from `compact` to the parser layer: after a recognized local verb, trailing tokens are not routed through a command-specific help/arity table and can enter the non-returning prompt/runtime path. **Required fix shape:** (a) define per-command arity/help metadata for every local verb before prompt fallback; (b) `status --help` and `doctor --help` render static help; `status extra` and `doctor extra` return typed `unexpected_argument`; (c) `clear --help` renders slash/resume guidance, while `clear --confirm` either maps to `/clear --confirm` guidance or returns typed `slash_only_command` without dispatch; (d) centralize slash-only top-level shim handling for `compact`, `clear`, and future resume-capable slash commands; (e) add clean-home timeout-guarded regression coverage for all forms above. **Why this matters:** `status` and `doctor` are the commands operators reach for during startup/config breakage. If adding `--help` or a stale wrapper token makes them silently hang, the recovery surface is unreliable and automation cannot distinguish operator typo from runtime deadlock. Source: gaebal-gajae dogfood response to Clawhip message `1506469039562555573` on 2026-05-20.
475. **Local diagnostic commands (`status`, `doctor`, `sandbox`) have no bounded JSON output-form contract: bare text works, suffix `--output-format json` hangs, and prefix `--output-format json <command>` is rejected as a parse error** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 02:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`; branch and origin were both `docs/roadmap-workdir-provenance@9495dbe` before editing. Clean-home probes showed `status`, `doctor`, and `sandbox` exit 0 with useful human-readable text. But `status --output-format json`, `doctor --output-format json`, and `sandbox --output-format json` each timed out after 6s with `stdout=0` and `stderr=0`. The prefix spelling `--output-format json status|doctor|sandbox` exits 1 with `[error-kind: cli_parse] unknown option`, also with no JSON envelope. This is distinct from #474's help/arity hang: here the option is a documented global formatting concept already used by `version` and prompt mode, but local diagnostics neither honor it nor fail closed consistently. **Required fix shape:** (a) define a project-wide rule for `--output-format` placement and apply it to local diagnostics; (b) support `status --output-format json`, `doctor --output-format json`, and `sandbox --output-format json` with stable `kind:"status"|"doctor"|"sandbox"` envelopes; (c) either support prefix global placement or reject it with a typed JSON-capable parse envelope; (d) ensure these paths are config/provider/prompt-free and bounded under clean home; (e) add timeout-guarded clean-home regressions for bare text, suffix JSON, and prefix JSON forms. **Why this matters:** operators and orchestrators need machine-readable health snapshots during startup failures. If the only working forms are text and JSON requests hang, automation has to scrape prose or misclassify a formatting request as runtime deadlock. Source: gaebal-gajae dogfood response to Clawhip message `1506476585543532596` on 2026-05-20.
476. **Read-only inventory commands (`agents`, `mcp`, `skills`, `plugins`) have no bounded JSON/list contract: bare text works, suffix `--output-format json` hangs, prefix global JSON is rejected, and `skills` dumps a huge prose list with no machine-readable counts/paths** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 02:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`; branch and origin were both `docs/roadmap-workdir-provenance@bb2cf3f` before editing. Clean-home probes showed bare inventory commands are local and bounded: `agents` prints `No agents found.`, `mcp` prints a short `Configured servers 0` report, `plugins` prints two disabled bundled plugins, and `skills` prints `65 available skills` plus ~27KB of prose descriptions. But `agents --output-format json`, `mcp --output-format json`, `skills --output-format json`, and `plugins --output-format json` each timed out after 6s with `stdout=0`/`stderr=0`. Prefix forms `--output-format json agents|mcp|skills|plugins` exit 1 with `[error-kind: cli_parse] unknown option` and no JSON envelope. This is adjacent to #475 but distinct: these are inventory surfaces that orchestrators need for routing, MCP/plugin lifecycle checks, and skill selection, not just health diagnostics. **Required fix shape:** (a) provide stable JSON envelopes for each command (`kind:"agents"|"mcp"|"skills"|"plugins"`) with counts, source paths, enabled/disabled state, and parse/load errors where relevant; (b) make `--output-format json` suffix bounded and optionally support/predictably reject prefix placement via the global formatting contract; (c) add compact text/list modes for `skills` so default output is not an unbounded prose wall; (d) ensure inventory JSON does not initialize providers or interactive prompt runtime; (e) add clean-home timeout-guarded regressions for bare text, suffix JSON, and prefix JSON forms. **Why this matters:** claws need structured inventories to decide which skills/plugins/MCP servers are available. Scraping 27KB of human prose or hitting a silent hang on JSON makes routing brittle and masks lifecycle breakage. Source: gaebal-gajae dogfood response to Clawhip message `1506484138927067286` on 2026-05-20.
477. **`system-prompt` only works as a bare command; every documented modifier (`--date`, `--cwd`, `--help`, `--output-format json`) and even invalid modifier cases zero-byte hang, making prompt provenance/reproducibility unusable outside the current cwd/date defaults** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 03:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`; branch and origin were both `docs/roadmap-workdir-provenance@8afdb94` before editing. Bare `system-prompt` exits 0 and prints the expected prompt with dynamic context, including working directory, date, git status, recent commits, and `CLAUDE.md` content. But `system-prompt --date 2026-05-20`, `system-prompt --cwd /tmp --date 2026-05-20`, `system-prompt --help`, `system-prompt extra`, `system-prompt --date nope`, `system-prompt --cwd /definitely/not/here`, and `system-prompt --output-format json` each timed out after 6s with `stdout=0` and `stderr=0`. Prefix global JSON (`--output-format json system-prompt`) exits 1 with `[error-kind: cli_parse] unknown option`. This is worse than a missing JSON parity issue: the help text advertises `claw system-prompt [--cwd PATH] [--date YYYY-MM-DD]`, but the advertised valid modifiers enter the non-returning path. **Required fix shape:** (a) parse `system-prompt` options before prompt/runtime fallback and make `--cwd`/`--date` valid, bounded, and deterministic; (b) validate `--date` format and nonexistent `--cwd` with typed errors; (c) implement `system-prompt --help`; (d) support or typed-reject `--output-format json` with a stable prompt-provenance envelope (`kind:"system_prompt"`, `cwd`, `date`, `project_context_sources`, `git_snapshot`, `text`); (e) add clean-home regression tests for bare, valid modifier, invalid modifier, help, extra arg, and JSON forms. **Why this matters:** `system-prompt` is the main way to debug prompt misdelivery and stale-context complaints. If users cannot pin cwd/date or get structured provenance, they cannot reproduce why a session received the wrong instructions. Source: gaebal-gajae dogfood response to Clawhip message `1506491684064723004` on 2026-05-20.
478. **`export` has a bounded bare no-session error, but every advertised flag/help form (`--help`, `--session`, `--output`, `--output-format json`) zero-byte hangs, so session artifact export cannot be scripted or debugged from the documented CLI surface** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 03:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with `./rust/target/debug/claw version --output-format json` reporting `git_sha:"25d663d"`; branch and origin were both `docs/roadmap-workdir-provenance@90a0d38` before editing. Clean-home probes showed bare `export` exits 1 with a good typed error: `[error-kind: no_managed_sessions]`, the partitioned `.claw/sessions/<fingerprint>/` path, and guidance to start `claw` or rerun with `--resume latest`. But `export --help`, `export extra`, `export --session latest`, `export --session definitely-missing`, `export --output /tmp/claw-export-test.md`, and `export --output-format json` each timed out after 6s with `stdout=0`/`stderr=0`. Prefix `--output-format json export` exits 1 with `[error-kind: cli_parse]` and no JSON envelope. The help text advertises `claw export [PATH] [--session SESSION] [--output PATH]`, but those flags are not safely parsed. **Required fix shape:** (a) parse `export` options before prompt/runtime fallback; (b) implement `export --help`; (c) make `--session latest`, missing session IDs, positional PATH, and `--output PATH` return bounded results/errors; (d) support or typed-reject `--output-format json` with an envelope including `kind:"export"`, session fingerprint/path, output path, and skipped/error reason; (e) add clean-home regressions for bare no-session, help, extra arg, missing/latest session, output path, positional path, and JSON forms. **Why this matters:** `export` is the evidence path for stale session, prompt misdelivery, and event/log opacity bugs. If bare no-session works but every real option hangs, operators cannot reliably produce or inspect artifacts when debugging clawability issues. Source: gaebal-gajae dogfood response to Clawhip message `1506499237972545576` on 2026-05-20.
479. **`skills` accepts listing/help surfaces, but unknown skill invocation names zero-byte hang instead of returning a typed `skill_not_found`/usage error, so typoed skill calls look like runtime stalls** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 04:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@4d52703` and binary `./rust/target/debug/claw` built from source SHA `25d663d`. Clean-home probes confirmed healthy bounded surfaces for `skills` (exit 0, `No skills found.`), `skills help`/`skills --help` (usage), and `skills --output-format json` (empty typed inventory). But the actual invocation/error path hangs silently: `skills garbage --output-format json`, `skills missing --output-format json`, `skills help missing --output-format json`, and `skills /nope --output-format json` each timed out after 6s with `stdout=0` and `stderr=0`. In contrast, sibling surfaces are bounded: `agents garbage --output-format json` exits 0 with a typed help envelope including `unexpected:"garbage"`, `mcp garbage --output-format json` does the same, and `skills install /nope --output-format json` exits 1 with a JSON error envelope. **Required fix shape:** (a) resolve the first post-`skills` token against installed skill names before falling into runtime prompt/tool execution; (b) for unknown names return a bounded JSON/text error with `kind:"skill_not_found"`, `name`, `available_count`, and a hint to run `claw skills list`; (c) reject extra args after `skills help` with typed usage instead of trying to invoke `help` as a skill; (d) preserve `skills list <extra>` behavior only if intentionally documented, otherwise reject the extra arg; (e) add clean-home regressions for list/help/json, unknown-name JSON/text, `help extra`, `/pathlike` unknown names, and install missing-path. **Why this matters:** skills are a plugin-like lifecycle surface. A typo or missing local skill should be diagnosable immediately; a zero-byte hang is indistinguishable from MCP startup deadlock or prompt misdelivery and makes automation wrappers unable to classify the failure. Source: gaebal-gajae dogfood response to Clawhip message `1506514333394403409` on 2026-05-20.
480. **`claw session` correctly says it is resume-only when bare, but `session --help` and `session list` zero-byte hang instead of returning bounded guidance, so users trying to discover session management from the advertised slash command get no usable recovery path** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 05:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@93f20df` and binary `./rust/target/debug/claw` built from source SHA `25d663d`. Clean-home probe: bare `claw session` exits 1 with a useful typed stderr error: `[error-kind: unknown] error: \`claw session\` is a slash command. Use \`claw --resume SESSION.jsonl /session\` or start \`claw\` and run \`/session\`.` But the natural discovery and list forms do not share that bounded path: `claw session --help` timed out after 6s with `stdout=0`/`stderr=0`, and `claw session list` timed out after 6s with `stdout=0`/`stderr=0`; a longer wrapper run had to be killed after the `session list` probe stopped producing output. **Required fix shape:** (a) treat `session` as an explicit top-level alias for resume-safe session inspection rather than falling into prompt/runtime dispatch; (b) implement `session --help` with the same usage as `/session [list|exists|switch|fork|delete]` plus the `--resume` requirement where applicable; (c) make `session list` return a bounded empty-list result or a typed `resume_required`/`no_managed_sessions` error rather than hanging; (d) support or typed-reject `--output-format json` for session discovery/list/exists forms; (e) add clean-home regressions for bare `session`, `session --help`, `session list`, `session exists missing`, and the documented `--resume latest /session list` no-session path. **Why this matters:** session management is the recovery surface for stale-session confusion and prompt misdelivery. A user who sees `/session` in help naturally tries `claw session --help` or `claw session list`; hanging there blocks the exact diagnostics needed to find or resume the broken session. Source: gaebal-gajae dogfood response to Clawhip message `1506521887231180986` on 2026-05-20.
481. **Slash-only top-level aliases (`files`, `hooks`, `memory`) emit a useful bare resume-only error, but `--help` hangs with zero output, so users cannot discover the documented resume-safe command shape from the command they just tried** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 05:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@51e6040` and binary `./rust/target/debug/claw` built from source SHA `25d663d`. Clean-home probes show the bare aliases are bounded: `claw files`, `claw hooks`, and `claw memory` each exit 1 with `[error-kind: unknown]` and a helpful message: `Use \`claw --resume SESSION.jsonl /<verb>\` or start \`claw\` and run \`/<verb>\`.` Their JSON forms are also bounded (`files --output-format json`, `hooks --output-format json`, `memory --output-format json`) with the same message in a JSON error envelope. But adding the most natural discovery flag hangs: `claw files --help`, `claw hooks --help`, and `claw memory --help` each timed out after 6s with `stdout=0`/`stderr=0`. In the same clean-home sweep, real top-level local verbs (`config`, `config --help`, `config env --output-format json`) returned immediately, proving this is specific to slash-only alias help fallback. **Required fix shape:** (a) centralize slash-only alias handling so `--help`/`help` never enter prompt/runtime dispatch; (b) return a bounded help page for every slash-only alias, including direct CLI usage (`claw --resume SESSION.jsonl /files`) and whether the command is resume-safe; (c) make JSON help/error envelopes include `kind:"slash_command_alias"`, `slash:"/files"`, `resume_required:true`, and supported resume forms; (d) add clean-home regressions for bare, `--help`, `help`, and JSON forms for `files`, `hooks`, `memory`, plus the already-found `session` sibling (#480). **Why this matters:** these are exactly the diagnostic surfaces users reach for during prompt misdelivery and stale-session debugging. A helpful bare error followed by a zero-byte hang on `--help` is a recovery dead-end. Source: gaebal-gajae dogfood response to Clawhip message `1506529436466675713` on 2026-05-20.
482. **Session-inspection slash aliases (`cost`, `stats`, `history`, `tokens`) have bounded bare/JSON resume-only errors, but `--help` hangs with zero output, extending the slash-alias help dead-end to the telemetry/recovery commands users need during stale-session debugging** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 06:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@111e7e8` and binary `./rust/target/debug/claw` built from source SHA `25d663d`. Clean-home sweep showed local direct verbs behave differently: `diff` returns bounded no-git text/JSON and rejects `diff --help` with a bounded `unexpected extra arguments`; interactive-only write verbs (`commit`, `pr`, `issue`) return bounded bare/JSON errors and `--help` prints the global help. The broken cluster is the resume-safe telemetry alias family: `claw cost`, `claw stats`, `claw history`, and `claw tokens` each exit 1 with a useful resume-only message (`Use \`claw --resume SESSION.jsonl /<verb>\` or start \`claw\` and run \`/<verb>\`.`), and their `--output-format json` forms return bounded JSON error envelopes, but `claw cost --help`, `claw stats --help`, `claw history --help`, and `claw tokens --help` time out after 6s with `stdout=0`/`stderr=0`; the sweep had to be killed while stuck at `tokens --help`. **Required fix shape:** (a) fold the resume-safe telemetry slash aliases into the centralized slash-only alias help handler proposed in #481; (b) for each alias, return bounded text/JSON help listing the `--resume SESSION.jsonl /<verb>` form, accepted optional args (`history [count]`), and JSON support status; (c) do not fall through to prompt/runtime dispatch when `--help` follows any known slash alias; (d) add clean-home regressions for bare, `--help`, `help`, and JSON forms for `cost`, `stats`, `history`, `tokens`, `cache`, and `providers`. **Why this matters:** these commands are the observability surface for event/log opacity and stale-session confusion. If the first attempt to ask for help on `/tokens` or `/history` silently hangs, operators cannot tell whether the session store, runtime, or help parser is broken. Source: gaebal-gajae dogfood response to Clawhip message `1506536984976425070` on 2026-05-20.
483. **Interactive-only slash aliases (`approve`, `deny`, `model`) hang on `--help`, while `permissions --help` already returns bounded inline usage, proving the alias-help behavior is inconsistent within the same command family** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 06:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@625b8b0` and binary `./rust/target/debug/claw` built from source SHA `25d663d`. Clean-home sweep: `claw approve`, `claw deny`, and `claw model` each exit 1 with a bounded interactive-only message (`Start \`claw\` and run \`/<verb>\` inside the REPL.`), and their `--output-format json` forms return bounded JSON error envelopes. But `claw approve --help`, `claw deny --help`, and `claw model --help` time out after 6s with `stdout=0`/`stderr=0`. Same sweep shows a nearby positive control: `claw permissions --help` exits 1 with the interactive-only message plus an inline usage block (`Usage /permissions [read-only|workspace-write|danger-full-access]`). Resume-safe siblings `cache`, `providers`, and `clear` also still hang on `--help`, matching #481/#482. **Required fix shape:** (a) extend the centralized slash-alias help handler to interactive-only aliases, not just resume-safe aliases; (b) model it after the existing bounded `permissions --help` behavior, returning the interactive-only reason plus per-command usage; (c) include aliases (`/approve` = `/yes`/`/y`, `/deny` = `/no`/`/n`) in help text/JSON; (d) add clean-home regressions for `approve --help`, `deny --help`, `model --help`, `debug-tool-call --help`, and assert `permissions --help` remains bounded. **Why this matters:** permission prompts and model switching are high-friction startup/operator surfaces. If users naturally type `claw approve --help` or `claw model --help`, the CLI must explain that these are REPL-only instead of silently hanging and looking like a dead runtime. Source: gaebal-gajae dogfood response to Clawhip message `1506544532026687562` on 2026-05-20.
484. **Interactive helper slash aliases (`debug-tool-call`, `bughunter`, `teleport`) hang on `--help`, and argument-bearing invocations like `bughunter src --output-format json` also hang instead of returning an interactive-only error, so high-value debug/navigation entrypoints are misclassified as dead runtime work** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 07:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@dbd04ad` and binary `./rust/target/debug/claw` built from source SHA `25d663d`. Clean-home sweep: `claw bughunter` and `claw teleport` exit 1 with bounded interactive-only messages (`Start \`claw\` and run \`/<verb>\` inside the REPL.`), but `claw debug-tool-call --help`, `claw bughunter --help`, and `claw teleport --help` each timed out after 6s with `stdout=0`/`stderr=0`. Worse, a realistic argument-bearing form, `claw bughunter src --output-format json`, also timed out after 6s with zero output instead of saying `/bughunter` is REPL-only; the sweep had to be killed after `teleport --help` hung. **Required fix shape:** (a) classify debug/navigation slash aliases before prompt/runtime fallback, including when they carry positional arguments; (b) return bounded interactive-only help for `debug-tool-call`, `bughunter [scope]`, and `teleport <symbol-or-path>`; (c) for JSON mode, return an error envelope with `kind:"slash_command_repl_only"`, `slash`, `args`, and `usage`; (d) add clean-home regressions for bare, `--help`, JSON, and argument-bearing forms (`bughunter src`, `teleport main`, `ultraplan task`, `release-notes`). **Why this matters:** these are the tools operators reach for to diagnose brittle tests, find files, or replay tool calls. Hanging before the REPL boundary makes a simple usage mistake indistinguishable from prompt misdelivery or a stuck MCP/plugin lifecycle. Source: gaebal-gajae dogfood response to Clawhip message `1506552081589342383` on 2026-05-20.
485. **Planning/output slash aliases (`ultraplan`, `release-notes`) still enter zero-byte hang paths on `--help`, and `ultraplan <task> --output-format json` hangs instead of returning a REPL-only error, while nearby `release-notes --output-format json` is bounded — proving slash-alias argument classification is incomplete, not uniformly broken** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 07:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@51a450e` and binary `./rust/target/debug/claw` built from source SHA `25d663d`. Clean-home probes: `claw ultraplan --help` timed out after 6s with `stdout=0`/`stderr=0`; `claw ultraplan task --output-format json` also timed out with zero output; `claw release-notes --help` timed out with zero output. But `claw release-notes --output-format json` exits 1 with a bounded JSON error (`Start \`claw\` and run \`/release-notes\` inside the REPL.`). Nearby non-slash/plugin-like controls are bounded: `agents missing --output-format json` returns typed help with `unexpected:"missing"`; `mcp show missing --output-format json` returns `found:false`; `mcp list extra --output-format json` returns `unsupported_action`. **Required fix shape:** (a) add `ultraplan` and `release-notes` to the centralized slash-alias help/REPL-only classifier; (b) classify slash aliases before attempting to treat positional args as prompt text or runtime work; (c) return bounded text/JSON help for `ultraplan [task]` and `release-notes`, including whether any direct non-REPL invocation is intentionally unsupported; (d) add clean-home regressions for `ultraplan --help`, `ultraplan task --output-format json`, `release-notes --help`, `release-notes --output-format json`, plus positive controls for `agents`/`mcp` bounded unknown handling. **Why this matters:** `/ultraplan` is a prompt-construction/planning surface and `/release-notes` is an artifact/reporting surface. If direct invocations silently hang, users cannot distinguish unsupported REPL-only usage from prompt misdelivery, model startup, or artifact-generation deadlock. Source: gaebal-gajae dogfood response to Clawhip message `1506559635996414132` on 2026-05-20.
486. **`prompt` has bounded help and missing-prompt errors, but real one-shot prompt invocations zero-byte hang under clean-home/no-credentials conditions instead of returning an auth/config error, so wrappers cannot distinguish model startup from CLI dispatch deadlock** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 08:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@8a2e133` and binary `./rust/target/debug/claw` built from source SHA `25d663d`. Clean-home probes: `claw prompt --help` exits 0 with the global help, and `claw prompt --output-format json` exits 1 with a bounded JSON error (`prompt subcommand requires a prompt string`). But actual prompt dispatch hangs silently: `claw prompt hello --output-format json` timed out after 6s with `stdout=0`/`stderr=0`; the prefix form `claw --output-format json prompt hello` also timed out with zero output; `claw prompt --compact hello` timed out with zero output, and the sweep had to be killed before the remaining modifier probes. In a clean-home environment with isolated `HOME`, `CLAW_CONFIG_HOME`, `XDG_CONFIG_HOME`, and `XDG_DATA_HOME`, a one-shot prompt without usable credentials should fail quickly with a typed auth/config error, not enter an opaque silent wait. **Required fix shape:** (a) add a preflight auth/provider/config check before one-shot prompt runtime startup; (b) if credentials/config are missing, return bounded text/JSON error (`kind:"missing_credentials"` or provider-specific typed error) before opening any long-running runtime path; (c) preserve bounded behavior for `prompt --help` and missing prompt string; (d) add clean-home regressions for `prompt hello --output-format json`, `--output-format json prompt hello`, `prompt --compact hello`, and `--compact prompt hello` verifying nonzero bounded error with stderr/stdout body; (e) include elapsed-time assertion so prompt startup failures cannot regress into hangs. **Why this matters:** `prompt` is the primary non-interactive automation surface. A zero-byte hang on a basic clean-home one-shot prompt turns missing setup into event/log opacity and makes CI/wrappers classify the CLI as dead rather than misconfigured. Source: gaebal-gajae dogfood response to Clawhip message `1506567181570277556` on 2026-05-20.
487. **`prompt` validates missing strings and bad model syntax before runtime, but unknown/permissive post-prompt flags are swallowed into the runtime path and hang, so typoed one-shot modifiers become silent prompt misdelivery instead of CLI parse errors** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 08:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@32961cf` and binary `./rust/target/debug/claw` built from source SHA `25d663d`. Clean-home probes: bare shorthand `claw hello` and `claw --output-format json hello` are bounded unknown-subcommand errors with a hint to use `claw prompt -- ...`; global unknown flags (`claw --definitely-unknown hello`) are bounded `cli_parse`; `claw prompt --output-format json` is a bounded missing-prompt error; `claw prompt hello --model bad` is a bounded invalid-model-syntax error. But `claw prompt hello --definitely-unknown`, `claw prompt hello --foo`, `claw prompt hello --allowedTools read`, and `claw prompt hello --permission-mode read-only` each entered runtime and timed out after 6s instead of validating or rejecting the modifier; the `--permission-mode` case even emitted only spinner control bytes (`⠋ 🦀 Thinking...`) before hanging. **Required fix shape:** (a) give `prompt` a strict subcommand-specific parser that separates prompt text from supported modifiers; (b) reject unknown post-prompt flags with `kind:"cli_parse"` and echo the offending flag; (c) support documented global modifiers consistently before or after `prompt` only if intentionally allowed, otherwise reject with a hint to put them before `prompt`; (d) in JSON mode, never emit spinner/control bytes and always return a bounded JSON error for preflight failures; (e) add clean-home regressions for `prompt hello --foo`, `prompt hello --allowedTools read`, `prompt hello --permission-mode read-only`, `prompt hello --model bad`, and global-vs-post-subcommand flag placement. **Why this matters:** one-shot `prompt` is the automation entrypoint. If a typoed or misplaced flag silently becomes part of the model runtime path, wrappers cannot tell whether the prompt was delivered, rejected, or is waiting on model startup. Source: gaebal-gajae dogfood response to Clawhip message `1506574734610137200` on 2026-05-20.
488. **`status --output-format json` reports only git dirty counts (`changed_files`, `untracked_files`) but omits the actual changed/untracked path list, so automation cannot identify the files that make a workspace dirty without shelling out to git** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 09:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@92e97e0` and binary `./rust/target/debug/claw` built from source SHA `25d663d`. Clean-home git fixture: initialized a repo with one committed tracked file, then added untracked `untracked.txt` plus untracked `.gitignore` (with ignored `ignored.log`). `claw status --output-format json` returned `workspace.git_state:"dirty · 2 files · 2 untracked"`, `changed_files:2`, `staged_files:0`, `unstaged_files:0`, and `untracked_files:2`, but the JSON contained neither `untracked.txt` nor `.gitignore` anywhere; `ignored.log` was correctly absent, but there is no positive path inventory for the two files counted as dirty. Text status similarly summarizes counts without paths. **Required fix shape:** (a) add `workspace.changed_file_paths` or structured `workspace.git_files:{staged:[], unstaged:[], untracked:[]}` to status JSON; (b) cap the list with `truncated:true` and `total` fields for large repos; (c) preserve ignore behavior (ignored files stay absent unless an explicit include-ignored option lands); (d) add fixture regressions proving untracked `.gitignore` and regular untracked files appear by path while ignored files do not. **Why this matters:** status is the main machine-readable workspace preflight. Counts alone are insufficient for stale-branch/dirty-worktree gating, cleanup decisions, or explaining why a launch is blocked; wrappers must currently run their own `git status --porcelain`, duplicating logic and losing parity with claw's own dirty classification. Source: gaebal-gajae dogfood response to Clawhip message `1506582285292535818` on 2026-05-20.
489. **`status --output-format json` branch freshness is computed from local remote-tracking refs only and does not fetch or report ref age, so a branch can be reported `fresh:true behind:0` while the remote already has new commits** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 09:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@d541130` and binary `./rust/target/debug/claw` built from source SHA `25d663d`. Fixture: created a repo with `origin/master`, pushed initial commit, made one local commit (ahead 1), then from a second clone pushed one remote commit without fetching in the first worktree. Before `git fetch`, `claw status --output-format json` reported `workspace.branch_freshness:{"ahead":1,"behind":0,"fresh":true,"upstream":"origin/master"}` and `git_state:"clean"`. After a manual `git fetch`, the same command reported `ahead:1, behind:1, fresh:false`. This means the preflight freshness field can be stale-but-green whenever the local remote-tracking ref is old. **Required fix shape:** (a) either fetch (bounded/optional) before computing freshness, or expose `remote_ref_observed_at` / `fetch_age_seconds` and `freshness_source:"local_ref"`; (b) if no recent fetch occurred, mark freshness as `unknown` or `stale_reference` rather than `fresh:true`; (c) add a `--refresh`/`--no-refresh` policy if network access is intentionally avoided; (d) add fixture regression with a bare remote + second clone proving status does not report `fresh:true` from stale local refs. **Why this matters:** stale-branch confusion is a core clawability gap. Orchestrators gating launches/merges on `branch_freshness.fresh` will make the wrong decision if `status` presents old local refs as authoritative remote freshness. Source: gaebal-gajae dogfood response to Clawhip message `1506589831097221120` on 2026-05-20.
490. **`status`/`doctor` still run boot-preflight git metadata probes with blocking `git` subprocesses and no deadline, so slow `rev-parse`/branch/root discovery can zero-byte hang local diagnostics before any JSON is emitted** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 10:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@edcf5bf` and binary `./rust/target/debug/claw` built from source SHA `25d663d`. Fixture: clean isolated repo plus a fake `git` shim that sleeps 20s only for metadata probes (`rev-parse --is-inside-work-tree`, `rev-parse --git-dir`, `branch --show-current`, `rev-parse --show-toplevel`) and delegates all other git commands to `/usr/bin/git`. `claw status --output-format json` timed out after 6s with `stdout=0`/`stderr=0`; `claw doctor --output-format json` did the same. A control shim that delayed only `fetch`/`ls-remote` did not affect status/doctor, confirming the hang is local metadata probing, not network refresh. Code path: `build_boot_preflight_snapshot` calls `run_git_bool` and `run_git_capture_in` with `.output()` and no timeout; `parse_git_status_metadata_for` calls `resolve_git_branch_for` (`branch --show-current`, fallback `rev-parse --abbrev-ref HEAD`) and `find_git_root_in` (`rev-parse --show-toplevel`) similarly. **Required fix shape:** (a) route all local diagnostic git subprocesses through a shared `git_with_timeout(cwd,args,deadline)` helper; (b) use `--no-optional-locks` for read-only git probes; (c) on timeout, return bounded JSON with `git_probe_timeout`/`unknown` fields instead of aborting the whole status/doctor response; (d) add regressions with a fake `git` shim proving status/doctor still return within deadline and mark git metadata degraded. **Why this matters:** status and doctor are supposed to be the escape hatches when startup is broken. If local git metadata can hang them before emitting JSON, stale-branch and boot-preflight diagnostics fail exactly when a repo or filesystem is slow/locked. Source: gaebal-gajae dogfood response to Clawhip message `1506597387534209085` on 2026-05-20.
491. **`status`, `doctor`, and direct `diff` all block on dirty-state/diff git probes with no timeout, so a slow `git status` or `git diff` makes every local diagnostic surface zero-byte hang** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 10:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@d5aa815` and binary `./rust/target/debug/claw` built from source SHA `25d663d`. Fixture: clean isolated git repo plus fake `git` shim that sleeps 20s only for dirty/diff probes (`status --short`, `diff --cached`, and `diff`) and delegates all other git commands to `/usr/bin/git`. Results: `claw status --output-format json` timed out after 6s with `stdout=0`/`stderr=0`; `claw doctor --output-format json` timed out with zero output; direct `claw diff --output-format json` also timed out with zero output. This is distinct from the metadata-probe hang in #490: even when branch/root metadata is fast, dirty-state and diff collection can deadlock the supposedly local escape-hatch commands before they emit any degraded JSON. **Required fix shape:** (a) route `read_git_status`, `read_git_diff`, and direct `diff` command helpers through shared timeout-aware git execution; (b) emit partial/degraded status JSON with `git_status_timeout:true` and omit/cap diff payload instead of blocking; (c) make direct `claw diff --output-format json` return `kind:"diff", result:"git_timeout"` with command/stage metadata; (d) add fake-git shim regressions for slow `git status`, `git diff --cached`, and `git diff` proving status/doctor/diff stay bounded. **Why this matters:** dirty-state and diff are central to stale-branch, cleanup, and prompt-context decisions. If they can hang the health commands, operators cannot tell whether the repo is dirty, the runtime is stuck, or git itself is wedged. Source: gaebal-gajae dogfood response to Clawhip message `1506604934555242546` on 2026-05-20.
492. **`system-prompt --output-format json` and `status --output-format json` can both zero-byte hang on `GitContext`'s unbounded branch/log/staged-file probes, so prompt provenance and local diagnostics share the same startup deadlock surface** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 11:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@56555a3` and binary `./rust/target/debug/claw` built from source SHA `25d663d`. Fixture: clean isolated git repo plus fake `git` shim that sleeps 20s only for `rev-parse --abbrev-ref HEAD`, `log --oneline`, and `diff --cached --name-only` (the `GitContext::detect` branch/recent-commits/staged-files probes) while delegating all other git commands to `/usr/bin/git`. Results: `claw system-prompt --output-format json` timed out after 6s with `stdout=0`/`stderr=0`; `claw status --output-format json` also timed out with zero output. Earlier controls showed shims delaying unrelated `fetch`/`ls-remote` do not affect these commands. **Required fix shape:** (a) route `GitContext::detect` probes through the same timeout-aware git helper as #490/#491; (b) make `system-prompt` emit a bounded degraded prompt-provenance envelope when git context times out (`git_context:{status:"timeout", branch:null, recent_commits_truncated:true}`) instead of hanging; (c) make `status` omit/degrade `GitContext` fields independently from boot-preflight metadata; (d) add fake-git shim regressions for each GitContext probe (`rev-parse --abbrev-ref`, `log --oneline`, `diff --cached --name-only`) across both `system-prompt` and `status`. **Why this matters:** `system-prompt` is the primary prompt-misdelivery/provenance debugger. If the prompt renderer itself blocks on git context before emitting JSON, users cannot inspect what prompt would have been delivered when startup is slow or git is locked. Source: gaebal-gajae dogfood response to Clawhip message `1506612484520542258` on 2026-05-20.
493. **`status` and `doctor` block on `tmux --version` availability checks with no timeout, so a wedged tmux binary/socket makes the local health surfaces zero-byte hang even though prompt rendering still works** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 11:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@2bf6924` and binary `./rust/target/debug/claw` built from source SHA `25d663d`. Fixture: clean isolated git repo plus fake `tmux` shim at the front of `PATH` that sleeps 20s for every invocation; `git` was normal. Results: `claw status --output-format json` timed out after 6s with `stdout=0`/`stderr=0`; `claw doctor --output-format json` also timed out with zero output; control `claw system-prompt --output-format json` exited 0 with prompt JSON under the same fake-tmux environment. Code path: `build_boot_preflight_snapshot` populates `required_binaries` via `command_available("tmux")`, which runs `tmux --version` through blocking `.output()` and no deadline. **Required fix shape:** (a) route `command_available` checks through a small timeout helper; (b) mark slow binary probes as `{name:"tmux", available:null, timeout:true}` instead of blocking the entire status/doctor response; (c) avoid invoking `tmux` at all when `$TMUX` is absent if the field is only informational, or cache the availability probe; (d) add fake-binary shim regressions for slow `tmux` and slow `git --version` proving status/doctor stay bounded. **Why this matters:** status/doctor are the recovery surfaces for tmux/session lifecycle breakage. If a broken `tmux` itself prevents the health command from returning JSON, orchestrators lose the exact diagnostic path needed to explain session/pane failures. Source: gaebal-gajae dogfood response to Clawhip message `1506620033886060665` on 2026-05-20.
494. **`status`/`doctor` also block on `git --version` binary-availability checks with no timeout, while `diff` and `system-prompt` still work, so an unhealthy git binary can kill the health surfaces before they report degraded tool availability** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 12:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@4d185f0` and binary `./rust/target/debug/claw` built from source SHA `25d663d`. Fixture: clean isolated git repo plus fake `git` shim at the front of `PATH` that sleeps 20s only for `git --version` and delegates all other git commands to `/usr/bin/git`. Results: `claw status --output-format json` timed out after 6s with `stdout=0`/`stderr=0`; `claw doctor --output-format json` timed out with zero output. Positive controls under the same environment: `claw diff --output-format json` returned `{"kind":"diff","result":"clean"...}` and `claw system-prompt --output-format json` returned prompt JSON, proving ordinary git operations were fine and the hang is specifically `command_available("git")` in boot preflight `required_binaries`. **Required fix shape:** (a) same timeout-aware binary probe as #493, but cover `git` and `claw` too; (b) represent slow probes as timeout/degraded availability instead of blocking status/doctor; (c) prefer `which`/PATH existence plus optional bounded version string over mandatory `--version`; (d) add fake-binary regressions for slow `git --version`, slow `tmux --version`, and slow current-exe/version probe. **Why this matters:** status/doctor should explain missing or broken binaries. If the binary availability probe itself hangs, health checks fail before they can say `git` is unhealthy, forcing operators back to shell debugging. Source: gaebal-gajae dogfood response to Clawhip message `1506627582756651018` on 2026-05-20.
495. **The actual `PermissionEnforcer::check_bash` read-only heuristic still whitelists `tee`, so `tee file.txt` can write in read-only mode despite the richer `bash_validation` module correctly classifying `tee` as a write command** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 12:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@916bf5f`. Code inspection shows two divergent validators: `rust/crates/runtime/src/bash_validation.rs` defines `WRITE_COMMANDS` including `tee` and would block it in read-only mode, but `PermissionEnforcer::check_bash` does not call that pipeline. It calls local `is_read_only_command` in `permission_enforcer.rs`, whose allowlist explicitly includes `tee` and only rejects commands containing `" > "`, `" >> "`, `"-i "`, or `"--in-place"`. Plain `tee out.txt` writes to `out.txt` without any redirection token, so `is_read_only_command("tee out.txt")` returns true and `check_bash` allows it under `PermissionMode::ReadOnly`. **Required fix shape:** (a) remove `tee` from `is_read_only_command` or, better, replace that local heuristic with the canonical `bash_validation::validate_command`/`classify_command` pipeline; (b) add regression tests proving `tee out.txt`, `tee -a out.txt`, `printf hi | tee out.txt`, and `cat a | tee b` are denied in read-only mode; (c) add a consistency test that every `WRITE_COMMANDS` entry in `bash_validation` is denied by `PermissionEnforcer::check_bash` in read-only mode. **Why this matters:** permission-mode enforcement is only as strong as the runtime path actually used. Having a stricter validator module sitting unused while `check_bash` allows a common write tool creates a real read-only bypass and contradicts the documented command semantics. Source: gaebal-gajae dogfood response to Clawhip message `1506635133468282950` on 2026-05-20.
496. **`PermissionEnforcer::check_bash` treats `python`/`python3`/`node`/`ruby` as read-only commands, so inline script execution (`python -c ...`, `node -e ...`, `ruby -e ...`) can write files in `read-only` mode** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 13:00 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@8382e1e`. Code inspection: `rust/crates/runtime/src/permission_enforcer.rs::is_read_only_command` allowlists `python3`, `python`, `node`, and `ruby`, and only rejects commands containing `-i `, `--in-place`, ` > `, or ` >> `. It does not inspect interpreter flags or inline code. Therefore `python -c 'open("pwned.txt","w").write("x")'`, `node -e 'require("fs").writeFileSync("pwned.txt","x")'`, and `ruby -e 'File.write("pwned.txt","x")'` are classified as read-only and allowed by `check_bash` under `PermissionMode::ReadOnly`, despite arbitrary filesystem writes. The richer `bash_validation` module's semantic list does not include these interpreters, but the runtime enforcer uses this separate local heuristic. **Required fix shape:** (a) remove general-purpose interpreters (`python`, `python3`, `node`, `ruby`) from the read-only allowlist or require explicit safe subcommands only (`python --version`, maybe `python -m pytest` under test gating is not read-only); (b) if kept, detect `-c`, `-e`, here-doc, stdin script, and file path script execution as non-read-only; (c) replace the local heuristic with the canonical `bash_validation` pipeline to avoid future divergence; (d) add regressions proving inline interpreter writes are denied in read-only mode while harmless version/help invocations remain bounded. **Why this matters:** read-only mode is supposed to prevent writes. Any general interpreter with inline code is equivalent to arbitrary shell execution; allowing it because the first token is `python` or `node` is a direct permission bypass and contradicts the safety story for exploratory sessions. Source: gaebal-gajae dogfood response to Clawhip message `1506642678996013207` on 2026-05-20.
497. **`PermissionEnforcer::check_bash` also allowlists `gh` as read-only, so GitHub-mutating commands (`gh pr merge`, `gh issue edit`, `gh repo delete`, etc.) can run in `read-only` mode** — dogfooded 2026-05-20 from the `#clawcode-building-in-public` 13:30 UTC nudge on `/home/bellman/Workspace/claw-code-pr2967` with branch/origin `docs/roadmap-workdir-provenance@214176d`. Code inspection: `rust/crates/runtime/src/permission_enforcer.rs::is_read_only_command` includes `gh` in the read-only allowlist and only rejects `-i`, `--in-place`, ` > `, or ` >> `. There is no `gh` subcommand classifier analogous to `bash_validation.rs::validate_git_read_only` for `git`. Therefore `gh pr merge 123 --merge`, `gh issue edit 5 --add-label done`, `gh repo delete owner/repo --yes`, and `gh api repos/:owner/:repo/actions/runs/1/approve -X POST` are all classified as read-only by the runtime enforcer, even though they mutate remote GitHub state. **Required fix shape:** (a) remove `gh` from the blanket read-only allowlist or implement a conservative `gh` subcommand classifier; (b) allow only clearly read-only forms (`gh pr view/list`, `gh issue view/list`, `gh run view/list`, `gh api` without mutating method) and require workspace-write/danger or prompt for merge/edit/create/delete/api `-X POST|PATCH|PUT|DELETE`; (c) add regressions proving mutating `gh` commands are denied in `PermissionMode::ReadOnly` while view/list commands remain allowed if desired; (d) preferably replace the local heuristic with the canonical bash-validation pipeline so shell permission logic has one source of truth. **Why this matters:** read-only mode is not just filesystem safety; it should prevent external state mutation. A `gh pr merge` or `gh issue edit` from a supposedly read-only lane is a serious control-plane bypass and can alter public repo state without the permission escalation the mode implies. Source: gaebal-gajae dogfood response to Clawhip message `1506650232937513140` on 2026-05-20.