kew canary¶
Attest that kew still reads fresh vendor CLI output correctly — the runtime
twin of kew health. A vendor CLI update can rename a JSON key and
silently break kew's capture of tokens/session/cost; kew canary runs the real
runner against a trivial prompt and checks the governance fields the meter
depends on.
kew canary # human table; exit 0/1/2
kew canary --runner claude-code,opencode # subset (default: both)
kew canary --json # machine-readable JSON (stdout only)
kew canary --record DIR # write each runner's raw stream to DIR/<runner>.jsonl
Checks¶
| Check | Verifies |
|---|---|
tokens_present |
input and output tokens were captured (> 0). |
session_captured |
a session id was captured (runners that emit one). |
cost_captured |
opencode's native cost > 0; claude's derived cost (compute_cost_from_tokens) > 0. Free models skip. |
result_classified |
the run classified success with a terminal result event. |
Exit codes¶
| Code | Meaning |
|---|---|
0 |
every requested runner ran and all checks passed (full attestation). |
1 |
a runner ran and a check failed — drift (the nightly files a canary issue and goes red). |
2 |
a runner couldn't run (binary missing / unauthenticated / vendor blip) and no drift — incomplete, not an alarm. |
Nightly workflow¶
.github/workflows/canary.yml runs kew canary nightly.
- Self-hosted (
RUNNER_TARGET=self-hosted, recommended): claude and opencode are already installed + authenticated — the only configuration that attests both runners. No secret needed; ~<1¢/night. - GitHub-hosted (default): installs claude via npm and authenticates it with
the optional
ANTHROPIC_API_KEYsecret — claude-code only. opencode needs provider auth that a clean box lacks, so it reportsskip(exit 2), not a false alarm.
Refresh the golden fixtures after a deliberate CLI upgrade with
kew canary --record tests/fixtures/canary and review the .jsonl diff.