$npx -y skills add anthropics/defending-code-reference-harness --skill verifyVerify harness changes end-to-end without docker — drive the real pinned CLI against a header-capturing stub server with the exact env resolve_auth_env() produces.
| 1 | # Verifying harness changes on a docker-less host |
| 2 | |
| 3 | The pipeline's real surface is the in-container `claude -p` process and its |
| 4 | outbound API requests. Without docker, drive the same pinned CLI binary |
| 5 | directly with the env dict the harness would inject via `docker -e`. |
| 6 | |
| 7 | ## Recipe |
| 8 | |
| 9 | 1. **Get the pinned CLI** (version from `harness/agent_image.py:CLAUDE_CODE_VERSION`): |
| 10 | `npm install --no-save @anthropic-ai/claude-code@<pin>` in a temp dir → |
| 11 | binary at `node_modules/@anthropic-ai/claude-code/bin/claude.exe` (the |
| 12 | `.exe` name is the real native-binary entry on Linux too, filled in by the |
| 13 | package's postinstall — not a Windows leftover). |
| 14 | 2. **Stub API server**: a tiny HTTP server that appends each request's |
| 15 | headers to a JSONL file and returns a 400 `invalid_request_error` |
| 16 | (non-retryable, so the CLI exits fast; exit=1 is expected). |
| 17 | 3. **Build the agent env exactly as the pipeline does**: |
| 18 | `python3 -c "from harness.auth import resolve_auth_env; ..."` and dump to |
| 19 | an `export`-lines file with `shlex.quote` (values contain newlines — |
| 20 | NEVER pass via `env $(...)`, word-splitting mangles them; `source` the file). |
| 21 | 4. **Emulate the container env**: `unset ANTHROPIC_CUSTOM_HEADERS` (and any |
| 22 | other ambient var not in the resolved dict) before sourcing — a Claude |
| 23 | Code session in this repo injects `.claude/settings.json` env into shells, |
| 24 | which containers never see. |
| 25 | 5. **Run**: `ANTHROPIC_BASE_URL=http://127.0.0.1:<port> CLAUDECODE= IS_SANDBOX=1 |
| 26 | timeout 30 <cli> -p hi --model claude-sonnet-4-5 --max-turns 1`, then read |
| 27 | the captured JSONL. |
| 28 | |
| 29 | ## Gotchas |
| 30 | |
| 31 | - Unit tests in `tests/test_patch.py` / `tests/test_patch_grade.py` need |
| 32 | docker and fail on docker-less hosts — pre-existing, not your change. |
| 33 | - The docker `-e` injection leg itself can't be exercised without docker; |
| 34 | it's the same mechanism that carries `ANTHROPIC_API_KEY` in production. |
| 35 | - For the interactive-skills surface, copy `.claude/settings.json` into a |
| 36 | fresh temp dir and run the host `claude` from there (with ambient |
| 37 | `ANTHROPIC_CUSTOM_HEADERS` unset so settings.json is the only source). |