Skip to content

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_KEY secret — claude-code only. opencode needs provider auth that a clean box lacks, so it reports skip (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.