Compare commits

..

1 Commits

Author SHA1 Message Date
Yeachan-Heo
e63b0458ed docs(roadmap): add #687 — status help json lacks output schema 2026-05-24 23:01:02 +00:00

View File

@@ -6429,46 +6429,38 @@ 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.
686. **`doctor --help --output-format json` now returns parseable JSON on current main, but it is still message-only (`{kind, command, topic, message}`) and does not expose the diagnostic check schema, local-only/no-provider contract, or expected output fields (`checks[]`, check names, levels/statuses), so wrappers cannot discover how to consume the primary preflight surface without scraping prose or running the command first** — dogfooded 2026-05-24 for the 22:30 Clawhip nudge at message `1508235675546419210`, reproduced on a freshly rebuilt current `origin/main` binary (`git_sha f8e1bb726`) from `/tmp/cc-probe-main-2130`. Active claw-code sessions: none. 687. **`status --help --output-format json` is JSON-valid on current main but message-only (`{kind, command, topic, message}`), while actual `status --output-format json` exposes a large preflight schema (`workspace`, `sandbox`, `allowed_tools`, `lane_board`, `model_source`, `usage`, etc.) that help does not describe; wrappers cannot discover status output fields or local/auth semantics without invoking status and reverse-engineering the payload** — dogfooded 2026-05-24 for the 23:00 Clawhip nudge at message `1508243229626204292`, reproduced on a freshly rebuilt current `origin/main` binary (`git_sha f8e1bb726`) from `/tmp/cc-probe-main-2130`. Active claw-code sessions: none.
Reproduction: Reproduction:
```bash ```bash
$ env -i HOME=/tmp/iso41/home PATH=/usr/bin:/bin TERM=dumb \ $ env -i HOME=/tmp/iso42/home PATH=/usr/bin:/bin TERM=dumb \
claw doctor --help --output-format json claw status --help --output-format json
{ {
"command": "doctor", "command": "status",
"kind": "help", "kind": "help",
"message": "Doctor\n Usage claw doctor [--output-format <format>]\n Purpose diagnose local auth, config, workspace, sandbox, and build metadata\n Output local-only health report; no provider request or session resume required\n Formats text (default), json\n Related /doctor · claw --resume latest /doctor", "message": "Status\n Usage claw status [--output-format <format>]\n Purpose show the local workspace snapshot without entering the REPL\n Output model, permissions, git state, config files, and sandbox status\n Formats text (default), json\n Related /status · claw --resume latest /status",
"topic": "doctor" "topic": "status"
} }
``` ```
The help object is valid JSON, but all actionable metadata is trapped in `message`. There are no structured `usage`, `purpose`, `formats`, `related`, `local_only`, `requires_credentials:false`, `requires_provider_request:false`, `output_fields`, `check_names`, `status_values`, or `failure_contract` fields. Actual status JSON on the same binary exposes many structured fields:
Contrast with the actual doctor JSON surface (same command family):
```bash ```bash
$ claw doctor --output-format json $ claw status --output-format json | jq 'keys'
{ ["allowed_tools", "config_load_error", "kind", "lane_board", "model", "model_raw", "model_source", "permission_mode", "sandbox", "status", "usage", "workspace"]
"kind": "doctor",
"status": "...", $ claw status --output-format json | jq '.workspace | keys'
"checks": [ ["boot_preflight", "branch_freshness", "changed_files", "cwd", "discovered_config_files", "git_branch", "git_state", "loaded_config_files", "memory_file_count", "project_root", "session", "session_id", "session_lifecycle", "staged_files", "unstaged_files", "untracked_files"]
{"name":"auth", ...},
{"name":"config", ...}, $ claw status --output-format json | jq '.sandbox | keys'
{"name":"install_source", ...}, ["active", "active_namespace", "active_network", "allowed_mounts", "enabled", "fallback_reason", "filesystem_active", "filesystem_mode", "in_container", "markers", "requested_namespace", "requested_network", "supported"]
{"name":"workspace", ...},
{"name":"sandbox", ...},
{"name":"system", ...}
],
...
}
``` ```
And contrast with `export --help --output-format json` on the same rebuilt binary, which already exposes structured `usage`, `purpose`, `formats`, `related`, `defaults`, and `options[]`. The doctor help surface therefore satisfies JSON validity but not schema discoverability for the most important local preflight command. None of this is described as structured help metadata. There is no `output_fields`, `workspace_fields`, `sandbox_fields`, `status_values`, `local_only`, `requires_credentials:false`, `requires_provider_request:false`, `mutates_workspace:false`, or `related` array.
**Why distinct from existing items:** #357 originally covered `doctor --help --output-format json` returning plain text. Current main no longer reproduces that exact failure: it returns JSON. #686 covers the next-layer contract gap: JSON is message-only and does not describe the doctor schema. #325 is the broad top-level help prose-wrapper problem; #684 and #685 are command-specific schema-depth gaps for `init` and `version`. This entry is doctor-specific because `doctor` is the primary automation preflight and its check schema is what claws branch on before running work. It also complements #100/#102/#107 style doctor-coverage gaps: before adding checks, help should expose which checks and status vocabulary are available. **Why distinct from existing items:** #356 covered `status --help --output-format json` returning plain text; current main no longer reproduces that exact issue because it returns valid JSON. #687 covers the next-layer schema-depth gap: status help is message-only and does not describe the actual status output schema. #325 is broad top-level help prose-wrapper. #686 is doctor-specific check-schema help. #326/#448 cover specific status/sandbox payload correctness problems; #687 is the discoverability contract for status as a whole.
**Why this matters:** `doctor` is the command operators and claws run when setup is broken. A wrapper should be able to learn from help, without running health checks yet, that `doctor` is local-only, credential-free, produces `checks[]`, and uses check/status levels suitable for gating. Today it must scrape prose or run `doctor` and reverse-engineer the response. That makes preflight adapters brittle and hides schema changes from automation. **Why this matters:** `status` is the lightweight lane truth surface. Claws use it to decide model/provenance, permission mode, workspace git state, sandbox state, active session lifecycle, and lane board state before choosing work. A wrapper should not need to run status and reverse-engineer keys before it knows whether `workspace.branch_freshness`, `sandbox.filesystem_active`, or `allowed_tools.restricted` exist. Help JSON should declare the output schema and local/auth semantics.
**Required fix shape:** (a) Extend `doctor --help --output-format json` with structured fields such as `usage:"claw doctor [--output-format <format>]"`, `purpose`, `formats:["text","json"]`, `related:["/doctor","claw --resume latest /doctor"]`, `local_only:true`, `requires_credentials:false`, `requires_provider_request:false`, `mutates_workspace:false`, `output_fields:["kind","status","checks","message"]`, `check_names:["auth","config","install_source","workspace","sandbox","system"]` (or a versioned stable/default list), `status_values:["ok","warn","fail"]`, and optional `schema_version`. (b) Keep `message` as human summary only. (c) Add regression coverage proving `claw doctor --help --output-format json | jq '.output_fields'` includes `checks`, and that `.requires_credentials == false`. (d) When new doctor checks land, update the help schema from the same registry/source used to build the report so help/check output cannot drift. **Acceptance check:** `claw doctor --help --output-format json | jq -e '.command=="doctor" and .local_only==true and .requires_credentials==false and ([.output_fields[]] | index("checks")) and ([.status_values[]] | index("warn"))'` should pass; currently those structured fields are absent. Source: gaebal-gajae dogfood for the 2026-05-24 22:30 Clawhip nudge. **Required fix shape:** (a) Extend `status --help --output-format json` with structured fields: `usage:"claw status [--output-format <format>]"`, `formats:["text","json"]`, `related:["/status","claw --resume latest /status"]`, `local_only:true`, `requires_credentials:false`, `requires_provider_request:false`, `mutates_workspace:false`, `output_fields:["kind","status","model","model_raw","model_source","permission_mode","allowed_tools","workspace","sandbox","usage","lane_board","config_load_error"]`, `workspace_fields:[...]`, `sandbox_fields:[...]`, `status_values:["ok","degraded",...]` or equivalent documented vocabulary, and `schema_version`. (b) Keep `message` as human summary only. (c) Derive help schema from the same status renderer structs/registry so newly added status fields do not drift from help. (d) Add regression coverage proving `claw status --help --output-format json | jq '.output_fields'` contains `workspace`, `sandbox`, `allowed_tools`, and that `workspace_fields` contains `branch_freshness` / `session_lifecycle`. **Acceptance check:** `claw status --help --output-format json | jq -e '.command=="status" and .local_only==true and .requires_credentials==false and ([.output_fields[]] | index("workspace") and index("sandbox") and index("allowed_tools")) and ([.workspace_fields[]] | index("branch_freshness"))'` should pass; currently those fields are absent. Source: gaebal-gajae dogfood for the 2026-05-24 23:00 Clawhip nudge.