Created
July 17, 2026 07:13
-
-
Save cer/ae9d749031a8445e0c014566bf5fb30b to your computer and use it in GitHub Desktop.
Migrating from WebFetch to CircleCI CLI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ❯ For circleci some or all of the webfetch can be replaced by the new circleci CLI. For example, `circleci run list` - you can try | |
| on eventuate-foundation/eventuate-common | |
| ⏺ Bash(which circleci && circleci version) | |
| ⎿ /opt/homebrew/bin/circleci | |
| circleci 1.0.45068-pre (b6835dba0a1d) | |
| ⏺ Bash(circleci --help) | |
| ⎿ # CircleCI CLI | |
| Work with CircleCI from the command line. | |
| … +34 lines (ctrl+o to expand) | |
| ⏺ Bash(circleci run --help) | |
| ⎿ # CircleCI CLI | |
| Work with CircleCI runs. | |
| … +39 lines (ctrl+o to expand) | |
| ⏺ Bash(circleci job --help) | |
| ⎿ # CircleCI CLI | |
| Work with CircleCI jobs. | |
| … +36 lines (ctrl+o to expand) | |
| ⏺ Bash(circleci artifact --help) | |
| ⎿ # CircleCI CLI | |
| List or download artifacts produced by a CircleCI job. | |
| … +35 lines (ctrl+o to expand) | |
| ⏺ Bash(circleci workflow --help) | |
| ⎿ # CircleCI CLI | |
| Work with CircleCI workflows. | |
| … +43 lines (ctrl+o to expand) | |
| ⏺ Bash(circleci run list --help) | |
| ⎿ # CircleCI CLI | |
| List recent runs for a CircleCI project. | |
| … +34 lines (ctrl+o to expand) | |
| ⏺ Bash(circleci run watch --help) | |
| ⎿ # CircleCI CLI | |
| Monitor a CircleCI run and block until it reaches a terminal state. | |
| … +33 lines (ctrl+o to expand) | |
| ⏺ Bash(circleci run get --help) | |
| ⎿ # CircleCI CLI | |
| Display the status of a CircleCI run and its workflows. | |
| … +32 lines (ctrl+o to expand) | |
| ⏺ Bash(circleci job output --help) | |
| ⎿ # CircleCI CLI | |
| Fetch the raw stdout and stderr produced by a job's steps. | |
| … +35 lines (ctrl+o to expand) | |
| ⏺ Now let me actually try these commands on the eventuate-common project. | |
| ⏺ Bash(circleci run list --project gh/eventuate-foundation/eventuate-common --limit 3) | |
| ⎿ # Runs | |
| | Ref | Revision | Subject | ID | Created | Status | | |
| | ------ | -------- | ----------------------- | -------------------------------------- | -------------------- | ---------- | | |
| | master | 6de8d54 | Bumped SNAPSHOT version | `45fc6cc0-f1f4-4240-b391-b3d6390cdd8f` | 2026-07-17 05:56 UTC | 🔵 running | | |
| ⏺ Bash(circleci run get --project gh/eventuate-foundation/eventuate-common --no-interactive --json | head -100) | |
| ⎿ { | |
| "error": true, | |
| "code": "api.error", | |
| … +3 lines (ctrl+o to expand) | |
| ⏺ Bash(circleci run get 45fc6cc0-f1f4-4240-b391-b3d6390cdd8f --json) | |
| ⎿ { | |
| "id": "45fc6cc0-f1f4-4240-b391-b3d6390cdd8f", | |
| "phase": "started", | |
| … +38 lines (ctrl+o to expand) | |
| ⏺ Bash(circleci run list --project gh/eventuate-foundation/eventuate-common --limit 5 --json --jq '.[] | {id, phase, outcome, | |
| revision}') | |
| ⎿ { | |
| "id": "45fc6cc0-f1f4-4240-b391-b3d6390cdd8f", | |
| "outcome": null, | |
| … +3 lines (ctrl+o to expand) | |
| ⏺ Bash(circleci run list --project gh/eventuate-foundation/eventuate-common --limit 10 --branch master --json --jq 'length') | |
| ⎿ 1 | |
| ⏺ Bash(circleci run list --project gh/eventuate-foundation/eventuate-common --limit 25 --json --jq 'length') | |
| ⎿ Error: Exit code 4 | |
| { | |
| "error": true, | |
| "code": "api.error", | |
| "message": "API returned 400: Invalid page size.\nerror id: 676d33362591531e5cc25ed725dfdec5", | |
| "exit_code": 4 | |
| } | |
| ⏺ Bash(circleci run list --project gh/eventuate-foundation/eventuate-common --limit 20 --json --jq '.[] | {id, phase, outcome, | |
| revision, branch}') | |
| ⎿ { | |
| "branch": "master", | |
| "id": "45fc6cc0-f1f4-4240-b391-b3d6390cdd8f", | |
| … +4 lines (ctrl+o to expand) | |
| ⏺ Bash(circleci job get 45fc6cc0-f1f4-4240-b391-b3d6390cdd8f --json) | |
| ⎿ { | |
| "id": "45fc6cc0-f1f4-4240-b391-b3d6390cdd8f", | |
| "name": "build-and-test-mysql8-arm", | |
| … +47 lines (ctrl+o to expand) | |
| ⏺ Bash(circleci job get --help) | |
| ⎿ # CircleCI CLI | |
| Display the status and steps of a CircleCI job. | |
| … +35 lines (ctrl+o to expand) | |
| ⏺ Bash(circleci artifact 45fc6cc0-f1f4-4240-b391-b3d6390cdd8f --json --jq '.[0:3]') | |
| ⎿ [ | |
| { | |
| "node_index": 0, | |
| … +14 lines (ctrl+o to expand) | |
| ⏺ Bash(circleci job output list --help) | |
| ⎿ # CircleCI CLI | |
| List every step in a job alongside its terminal-processed output. | |
| … +31 lines (ctrl+o to expand) | |
| ⏺ Bash(circleci job output get --help) | |
| ⎿ # CircleCI CLI | |
| Fetch the raw stdout and stderr of a single step within a job and | |
| … +37 lines (ctrl+o to expand) | |
| ⏺ Bash(circleci testresult --help) | |
| ⎿ # CircleCI CLI | |
| Work with the test metadata CircleCI collects for a job. | |
| … +41 lines (ctrl+o to expand) | |
| ⏺ Let me verify a couple more commands work end-to-end before I update the skill. | |
| ⏺ Bash(circleci job output list 45fc6cc0-f1f4-4240-b391-b3d6390cdd8f --json --jq '.steps | length') | |
| ⎿ 11 | |
| ⏺ Bash(circleci testresult list 45fc6cc0-f1f4-4240-b391-b3d6390cdd8f 2>&1 | head -20) | |
| ⎿ No matching test results found. | |
| ⏺ Both work. Now I'll update the CircleCI section to use the CLI instead of WebFetch. | |
| Update(claude-code-plugins/idea-to-code/skills/debugging-ci-failures/SKILL.md) | |
| ⎿ Added 44 lines, removed 23 lines | |
| 68 | |
| 69 ## CircleCI | |
| 70 | |
| 71 -**IMPORTANT:** The WebFetch tool has a 15-minute cache. To get fresh data on each poll, append a unique query paramet | |
| -er (e.g., `&_ts=1`, `&_ts=2`, incrementing each time). | |
| 71 +Use the `circleci` CLI. It has no caching issues (unlike WebFetch) and returns proper exit codes. | |
| 72 | |
| 73 +The project slug has the form `gh/<org>/<repo>` (e.g., `gh/eventuate-foundation/eventuate-common`). When run from ins | |
| +ide the project's git checkout, the CLI infers the slug from the git remote and `--project` can be omitted. | |
| 74 + | |
| 75 ### Phase 0: Watch a build | |
| 76 | |
| 75 -1. Find the latest build: | |
| 77 +`circleci run watch` blocks until the run reaches a terminal state and its exit code reflects the outcome: | |
| 78 +- `0` — all workflows succeeded | |
| 79 +- `1` — one or more workflows failed | |
| 80 +- `6` — cancelled | |
| 81 +- `8` — timed out | |
| 82 + | |
| 83 +```bash | |
| 84 +circleci run watch --project gh/<org>/<repo> --branch <branch> | |
| 85 ``` | |
| 77 -WebFetch: https://circleci.com/api/v1.1/project/github/<org>/<repo>?limit=1&branch=<branch>&_ts=1 | |
| 86 + | |
| 87 +Or, from inside the project after `git push`: | |
| 88 +```bash | |
| 89 +circleci run watch --sha $(git rev-parse HEAD) | |
| 90 ``` | |
| 79 -Extract the `build_num`. | |
| 91 | |
| 81 -2. Poll the build status, incrementing `_ts` each time: | |
| 92 +If you need to poll instead of block (e.g., interleaving other work), use `run list` + `run get`: | |
| 93 +```bash | |
| 94 +circleci run list --project gh/<org>/<repo> --branch <branch> --limit 1 --json --jq '.[0] | {id, phase, outcome}' | |
| 95 +circleci run get <run-id> --json --jq '{phase, workflows: [.workflows[] | {name, phase, jobs: [.jobs[] | {id, name, p | |
| +hase, outcome}]}]}' | |
| 96 ``` | |
| 83 -WebFetch: https://circleci.com/api/v1.1/project/github/<org>/<repo>/<build-num>?_ts=<N> | |
| 84 -``` | |
| 85 -Ask for the `status`, `outcome`, and `stop_time` fields. | |
| 97 | |
| 87 -3. Repeat every 10-15 seconds until `status` is no longer `running`. | |
| 88 - | |
| 89 -4. Report the final result: `success` or `failed`. | |
| 90 - | |
| 98 If the build failed, proceed to Phase 1. | |
| 99 | |
| 100 ### Phase 1: Gather evidence | |
| 101 | |
| 95 -**Step 1: Get the failed job summary** | |
| 102 +**Step 1: Identify the failing job(s)** | |
| 103 | |
| 97 -First get the build steps: | |
| 104 +```bash | |
| 105 +circleci run get <run-id> --json --jq '.workflows[].jobs[] | select(.outcome == "failed")' | |
| 106 ``` | |
| 99 -WebFetch: https://circleci.com/api/v1.1/project/github/<org>/<repo>/<build-num>?include=steps | |
| 107 + | |
| 108 +**Step 2: Get the failed step and its output** | |
| 109 + | |
| 110 +List the job's steps and find the one with a non-zero exit code: | |
| 111 +```bash | |
| 112 +circleci job output list <job-id> --json --jq '.steps[] | select(.exit_code != 0) | {num, name, exit_code}' | |
| 113 ``` | |
| 101 -Then fetch the output for the failed step index: | |
| 114 + | |
| 115 +Then fetch that step's output. Use `--condensed` for an AI-friendly filtered view: | |
| 116 +```bash | |
| 117 +circleci job output get <job-id> --step-num <N> --condensed | |
| 118 ``` | |
| 103 -WebFetch: https://circleci.com/api/v1.1/project/github/<org>/<repo>/<build-num>/output/<step-index>/0 | |
| 119 + | |
| 120 +**Step 3: Check parsed test results** | |
| 121 + | |
| 122 +If the job uses `store_test_results`, CircleCI has already parsed them — this may be enough to identify the failing t | |
| +est without downloading anything: | |
| 123 +```bash | |
| 124 +circleci testresult list <job-id> | |
| 125 ``` | |
| 126 | |
| 106 -**Step 2: Download test artifacts** | |
| 127 +**Step 4: Download test artifacts** | |
| 128 | |
| 108 -List artifacts: | |
| 129 +List artifacts, then download into a project-relative directory: | |
| 130 +```bash | |
| 131 +circleci artifact <job-id> --json | |
| 132 +circleci artifact <job-id> --output test-reports | |
| 133 ``` | |
| 110 -WebFetch: https://circleci.com/api/v1.1/project/github/<org>/<repo>/<build-num>/artifacts | |
| 111 -``` | |
| 112 -Then fetch specific artifact URLs from the response. | |
| 134 | |
| 114 -**Step 3: Read the TEST-*.xml files** — see "Reading TEST-*.xml files" below. | |
| 135 +**Step 5: Read the TEST-*.xml files** — see "Reading TEST-*.xml files" below. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment