| 1 | # Opt-in live smoke runs |
| 2 | |
| 3 | This page is **manual, opt-in, and never automated.** Nothing in CI, no test, |
| 4 | no build script, and no skill runs these commands. The repository's automated |
| 5 | suite is provider-free by design; see |
| 6 | [`crates/tui/assets/skills-catalog-matrix.json`](../crates/tui/assets/skills-catalog-matrix.json) |
| 7 | and the catalog-matrix tests for what is actually asserted without a provider. |
| 8 | |
| 9 | Run this only when you want to answer one narrow question: *does a real route |
| 10 | to a real model return a well-formed receipt on this machine?* |
| 11 | |
| 12 | ## What a live smoke run does and does not prove |
| 13 | |
| 14 | | Question | Answered here? | |
| 15 | | --- | --- | |
| 16 | | Does the receipt record the provider/model I asked for? | Yes. This does not by itself prove which network endpoint handled the request. | |
| 17 | | Does the run emit an inspectable route/usage receipt? | Yes, when the harness reaches that stage. | |
| 18 | | Does one response prove my account's entitlement state? | **No.** Provider configuration, authentication/entitlement, and harness behavior remain candidate causes until corroborated. | |
| 19 | | Does the model semantically pick the right skill? | **No.** Not measured. | |
| 20 | | Is skill registry/catalog/alias behavior correct? | **No** — that is the provider-free suite's job. | |
| 21 | |
| 22 | Treat these as investigation starting points, not proven failure classes: |
| 23 | |
| 24 | - **Provider error response** — HTTP 401/403, unknown-model, quota, or region |
| 25 | errors can reflect the configured provider/endpoint, credential |
| 26 | authentication or entitlement, provider availability, or a harness |
| 27 | routing/request defect. The response alone does not distinguish them. |
| 28 | - **Receipt or process anomaly** — wrong `provider`/`model` in the receipt, |
| 29 | missing receipt fields, a crash, or failure to use the isolated state |
| 30 | directory is evidence to investigate the harness, but still needs a minimal |
| 31 | reproduction or other corroboration before assigning the cause. |
| 32 | |
| 33 | ## Isolation rules these snippets follow |
| 34 | |
| 35 | 1. `env -i` clears the inherited environment, so your ambient `HOME`, |
| 36 | `CODEWHALE_HOME`, and `*_API_KEY` values are not forwarded. Only variables |
| 37 | listed explicitly on the `env` line survive. |
| 38 | 2. Only `CODEWHALE_HOME` points at the task-specific throwaway directory, so |
| 39 | Codewhale config, sessions, and the bundled skill install land in scratch |
| 40 | state. `HOME` is intentionally left unset; the smoke run never repurposes it. |
| 41 | 3. You name the credential variable yourself (`CW_SMOKE_CRED_VAR`). Nothing is |
| 42 | guessed from the provider. |
| 43 | 4. The isolated child reads the secret with echo disabled, restores the prior |
| 44 | terminal state on `EXIT`, `INT`, `HUP`, or `TERM`, and exports it only in |
| 45 | that child. The value is not persisted to disk or placed in a command |
| 46 | argument or shell history. |
| 47 | 5. `PATH` is forwarded explicitly, and is the only host variable carried over. |
| 48 | |
| 49 | Portable `sh` is used throughout; `stty` and `mktemp -d` are the only non-POSIX |
| 50 | niceties and both exist on macOS and mainstream Linux. |
| 51 | |
| 52 | ## Step 1 — create the throwaway state (both runs) |
| 53 | |
| 54 | ```sh |
| 55 | CW_SMOKE_CODEWHALE_HOME="$(mktemp -d)" || exit 1 |
| 56 | mkdir -p "$CW_SMOKE_CODEWHALE_HOME/tmp" |
| 57 | echo "scratch Codewhale state: $CW_SMOKE_CODEWHALE_HOME" |
| 58 | ``` |
| 59 | |
| 60 | ## Step 2 — name the credential variable |
| 61 | |
| 62 | `CW_SMOKE_CRED_VAR` must be the variable name the provider expects. Codewhale |
| 63 | reads `MOONSHOT_API_KEY` (or `KIMI_API_KEY`) for the Moonshot/Kimi route and |
| 64 | `DEEPSEEK_API_KEY` for the DeepSeek route. |
| 65 | |
| 66 | ```sh |
| 67 | CW_SMOKE_CRED_VAR="MOONSHOT_API_KEY" # you choose this; nothing is inferred |
| 68 | ``` |
| 69 | |
| 70 | The run command prompts for the value inside its isolated child process. It |
| 71 | does not create a credential file. |
| 72 | |
| 73 | ## Step 3a — run A: Kimi K3 |
| 74 | |
| 75 | `kimi-k3` is a model id this build knows about. The configured provider and its |
| 76 | resolved endpoint determine the route: `--provider moonshot` selects the |
| 77 | configured Moonshot route; selecting `opencode_go` would select that separately |
| 78 | configured route. The account does not choose between them, and the harness |
| 79 | does not switch between them based on a response. Set |
| 80 | `CW_SMOKE_PROVIDER` / `CW_SMOKE_MODEL` for the route you intend to exercise. A |
| 81 | model-not-found response is an unclassified result until the provider/endpoint |
| 82 | configuration, credential access, and harness request are corroborated. |
| 83 | |
| 84 | ```sh |
| 85 | CW_SMOKE_PROVIDER="moonshot" |
| 86 | CW_SMOKE_MODEL="kimi-k3" |
| 87 | CW_SMOKE_EFFORT="medium" |
| 88 | CW_SMOKE_PROMPT="Reply with exactly: SMOKE OK" |
| 89 | |
| 90 | env -i \ |
| 91 | PATH="$PATH" \ |
| 92 | TMPDIR="$CW_SMOKE_CODEWHALE_HOME/tmp" \ |
| 93 | CODEWHALE_HOME="$CW_SMOKE_CODEWHALE_HOME" \ |
| 94 | CW_SMOKE_CRED_VAR="$CW_SMOKE_CRED_VAR" \ |
| 95 | sh -c ' |
| 96 | CW_SMOKE_STTY_STATE="$(stty -g)" || exit 1 |
| 97 | restore_terminal() { |
| 98 | stty "$CW_SMOKE_STTY_STATE" 2>/dev/null || : |
| 99 | } |
| 100 | trap "restore_terminal" EXIT |
| 101 | trap "restore_terminal; exit 129" HUP |
| 102 | trap "restore_terminal; exit 130" INT |
| 103 | trap "restore_terminal; exit 143" TERM |
| 104 | |
| 105 | printf "Paste value for %s (input hidden): " "$CW_SMOKE_CRED_VAR" >&2 |
| 106 | stty -echo || exit 1 |
| 107 | if ! IFS= read -r CW_SMOKE_CRED; then |
| 108 | printf "\nCredential input failed.\n" >&2 |
| 109 | exit 1 |
| 110 | fi |
| 111 | restore_terminal |
| 112 | trap - EXIT HUP INT TERM |
| 113 | unset CW_SMOKE_STTY_STATE |
| 114 | printf "\n" >&2 |
| 115 | |
| 116 | export "$CW_SMOKE_CRED_VAR=$CW_SMOKE_CRED" |
| 117 | unset CW_SMOKE_CRED |
| 118 | exec codewhale-tui exec \ |
| 119 | --provider "$1" --model "$2" --reasoning-effort "$3" --json "$4" |
| 120 | ' sh "$CW_SMOKE_PROVIDER" "$CW_SMOKE_MODEL" "$CW_SMOKE_EFFORT" "$CW_SMOKE_PROMPT" |
| 121 | ``` |
| 122 | |
| 123 | ## Step 3b — run B: a second provider/model (DeepSeek) |
| 124 | |
| 125 | Set `CW_SMOKE_CRED_VAR="DEEPSEEK_API_KEY"`, then: |
| 126 | |
| 127 | ```sh |
| 128 | CW_SMOKE_PROVIDER="deepseek" |
| 129 | CW_SMOKE_MODEL="deepseek-v4-pro" |
| 130 | ``` |
| 131 | |
| 132 | …and re-run the identical `env -i …` block from step 3a; it prompts for a fresh |
| 133 | credential value. Running the *same* command shape against two providers is the |
| 134 | point: a difference in outcome is an observation to investigate, not proof of |
| 135 | route, entitlement, or harness correctness. Provider/endpoint configuration, |
| 136 | credentials, provider health, and the generated request all remain possible |
| 137 | explanations. |
| 138 | |
| 139 | ## Step 4 — optional: tool-and-reasoning receipt |
| 140 | |
| 141 | The `--json` one-shot above records the resolved route claimed by the harness; |
| 142 | it does not independently prove which endpoint handled the request. To also see |
| 143 | tool-catalog and reasoning receipts, use the streaming form (still inside the |
| 144 | same `env -i` wrapper, substituting the `exec` line): |
| 145 | |
| 146 | ```sh |
| 147 | exec codewhale-tui exec --auto --max-turns 3 \ |
| 148 | --output-format stream-json \ |
| 149 | --provider "$1" --model "$2" --reasoning-effort "$3" "$4" |
| 150 | ``` |
| 151 | |
| 152 | ## Step 5 — what to record |
| 153 | |
| 154 | From the `--json` one-shot receipt: |
| 155 | |
| 156 | | Field | Expectation | |
| 157 | | --- | --- | |
| 158 | | `mode` | `one-shot` | |
| 159 | | `provider` | exactly the `--provider` you passed | |
| 160 | | `model` | exactly the `--model` you passed | |
| 161 | | `success` | `true` | |
| 162 | | `output` | the model's text; content is *not* a pass/fail criterion | |
| 163 | |
| 164 | From the `stream-json` metadata receipt: |
| 165 | |
| 166 | | Field | Expectation | |
| 167 | | --- | --- | |
| 168 | | `provider`, `model` | match the flags you passed | |
| 169 | | `route_source` | records *why* that route was chosen | |
| 170 | | `reasoning_tokens` | present when the receipt reports reasoning; absence can reflect model/provider behavior, configuration, or a harness omission and needs corroboration | |
| 171 | | `tool_catalog_sha256` | present when a tool surface was offered | |
| 172 | | `approval_posture`, `sandbox_posture` | match the flags you passed | |
| 173 | | `duration_ms`, `input_tokens`, `output_tokens` | present for a completed run | |
| 174 | |
| 175 | Report the receipt fields. Do **not** paste the credential, the key file, or |
| 176 | raw provider error bodies (they can echo request headers). |
| 177 | |
| 178 | ## Step 6 — clean up |
| 179 | |
| 180 | ```sh |
| 181 | rm -rf "$CW_SMOKE_CODEWHALE_HOME" |
| 182 | unset CW_SMOKE_CODEWHALE_HOME CW_SMOKE_CRED_VAR \ |
| 183 | CW_SMOKE_PROVIDER CW_SMOKE_MODEL CW_SMOKE_EFFORT CW_SMOKE_PROMPT |
| 184 | ``` |
| 185 | |
| 186 | ## Scope note |
| 187 | |
| 188 | A green live smoke run is evidence that the configured live attempt completed |
| 189 | today. By itself it does not prove endpoint identity, durable account |
| 190 | entitlement, or the absence of a harness defect; corroborate those claims |
| 191 | separately. It says nothing about skill selection, alias resolution, locale |
| 192 | routing, or prompt budget — all of which are covered deterministically and |
| 193 | provider-free in `crates/tui/src/skills/catalog_matrix.rs`. |
| 194 |