Migrating a Claude Code skill from WebFetch to the new CircleCI CLI: lessons learned about tool and API design
genAI development generative AI harness engineering idea to code context engineering developer experience deployment pipeline devops automation testingContact me for information about consulting and training at your company.
The MEAP for Microservices Patterns 2nd edition is now available
One of the Claude Code skills in my idea-to-code plugin is debugging-ci-failures.
It tells Claude Code how to watch and diagnose a failing CI build.
Specifically, it instructs Claude Code to do the following five steps:
- Watch the build to completion
- Identify the failing job
- Fetch the failing step’s output
- Download the test artifacts
- Read the JUnit
TEST-*.xmlfiles to find the root cause
The skill supports two CI systems: GitHub Actions (via the gh CLI) and CircleCI.
Until today, the CircleCI support used WebFetch — Claude Code’s built-in HTTP fetch tool — to access CircleCI’s REST API directly.
That worked, but it was clumsy.

This post is about how I used Claude Code to migrate the skill from WebFetch to the new CircleCI CLI. The migration itself took a single one-line prompt — but that’s the least interesting part. Along the way, Claude Code discovered CLI features I didn’t know existed and found a shortcut I hadn’t thought to ask for. And by the end, a small skill update had turned into something more general: a lesson about how we should be designing tools for AI agents at all. I’ll come back to that. First, the hack the new CLI let me delete.
The WebFetch approach and its ugly workaround
Compared to the GitHub gh CLI, the existing CircleCI CLI was rather limited.
As a result, the skill had to use WebFetch to access CircleCI’s REST API directly, which was rather inconvenient.
Not only did Claude Code need to know the details of the REST API, but analyzing builds for private repositories required an API token, which was not something I wanted to expose to Claude Code.
Also, the Claude Code WebFetch tool caches responses for about 15 minutes, which is a problem when you are invoking an API. As a workaround, the skill had to append a cache-busting query parameter to every request:
WebFetch: https://circleci.com/api/v1.1/project/github/<org>/<repo>?limit=1&branch=<branch>&_ts=1
Note the &_ts=1 at the end.
That’s not a CircleCI parameter — it’s a hack that forces WebFetch to treat each request as unique.
The new CircleCI CLI
I was excited to read Rob Zuber’s LinkedIn post announcing the new CircleCI CLI.
A quick glance showed that it was roughly comparable to the gh CLI for GitHub Actions — it handled authentication, and hid the details of the REST API.
What’s more, I discovered that changing the skill to use it was remarkably straightforward.
The prompt that started the migration
After I reorganized the skill so that GitHub Actions and CircleCI each had their own section, my next prompt was a single line:
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.
Claude Code walked the CLI’s help tree (circleci --help, circleci run --help, circleci job --help, etc.), then ran commands against eventuate-foundation/eventuate-common to see the actual JSON shapes and behaviors before rewriting the skill.
Take a look at the Claude Code session and the resulting commit.
What the CLI replaces
The mapping turned out to be direct — the CLI has a purpose-built command for every step of the workflow:
| Skill step | Old (WebFetch + _ts hack) |
New (circleci CLI) |
|---|---|---|
| Watch a build | Poll /build/<n>?_ts=N in a loop |
circleci run watch — blocks, exit code = outcome |
| Find the latest run | WebFetch project endpoint | circleci run list --branch <branch> |
| Get run + workflow + job status | WebFetch, parse JSON | circleci run get <run-id> --json |
| Find the failed step | WebFetch ?include=steps, scan |
circleci job output list <job-id> --json --jq '.steps[] \| select(.exit_code != 0)' |
| Fetch the failed step’s output | WebFetch /output/<idx>/0 |
circleci job output get <job-id> --step-num N |
| List artifacts | WebFetch /artifacts |
circleci artifact <job-id> --json |
| Download artifacts | WebFetch each URL individually | circleci artifact <job-id> --output test-reports |
Two of these are worth highlighting.
circleci run watch
circleci run watch replaces an entire polling loop with a blocking call whose exit code encodes the outcome:
0— all workflows succeeded1— one or more workflows failed6— cancelled8— timed out
That’s a much better contract for an agent than “keep polling until status is no longer running, then check outcome.”
circleci job output get --condensed
Claude discovered that the circleci job output get command has a rather useful flag: --condensed:
Use –condensed to fetch a filtered version of stdout only, with noisy or repetitive lines removed server-side. This produces a much smaller payload suitable for feeding to an AI tool. When –condensed is set, output is always rendered through the plain-text renderer regardless of the terminal or –strip-ansi.
CircleCI has apparently added a first-class “give me the interesting lines, meant to be pasted into an LLM” mode to their CLI.
An unexpected shortcut
While Claude Code studied the CLI’s commands, it found another one that isn’t strictly a WebFetch replacement — it’s an entirely new step Claude can try before downloading anything:
circleci testresult list <job-id>
By default, this command shows a job’s failed tests.
It enables Claude Code to quickly identify the failing test without downloading any artifacts.
The skill now tries testresult list first and falls back to downloading TEST-*.xml files only if that isn’t enough.
Why this matters beyond one skill
The bigger point isn’t about CircleCI or Claude Code specifically. There are a few broad lessons here:
- Prefer tools to raw APIs
- Design CLI tools to be discoverable
- Design CLI tools for token-efficient output
Let’s look at each one.
Prefer tools to raw APIs
If your agent has to reach an external system through a general-purpose HTTP tool, it’s writing REST calls by hand, dealing with caching, composing URLs, and parsing JSON shapes. Every one of those steps is a place the agent can go wrong.
If instead the agent can reach the same system through a well-designed CLI, the CLI hides all of that.
circleci run watch doesn’t need cache-busting.
circleci artifact --output doesn’t need URL composition.
circleci job output get --condensed doesn’t need the agent to figure out how to trim noise for an LLM — the vendor already did.
A CLI aimed at agents is a shorter path than the raw API, and shorter paths are more reliable. When you’re writing skills, prefer the CLI when one exists — and let the absence of one push you to open an issue with the vendor rather than to hand-craft another URL.
Design CLI tools to be discoverable in the era of shallow understanding
It’s also worth pointing out that Claude Code figured out how to use the CircleCI CLI without me telling it anything about the commands.
It simply ran circleci --help, then circleci run --help, then circleci job --help, and so on, until it had a mental model of the CLI’s command tree.
That was enough for it to determine the right commands and update the skill.
If you are developing CLI tools, make sure they are discoverable in this way — the --help output is a first-class part of the interface, not just a convenience for humans.
Design CLI tools for token-efficient output
Finally, the --condensed flag is a great example of a CLI designed for an agent’s needs.
Filtering noise server-side lowers token cost and keeps the agent’s context window focused on what matters — and the vendor knows which lines are noise better than any skill author does.
Worth considering whenever you design an API or CLI tool.
About this article
Claude Code wrote the first draft of this post during the same session that made the change. The skill migration and the article came out of one conversation. First, I asked Claude to migrate the skill to the CircleCI CLI tool. After that, I told it to draft this post.
Need help with modernizing your architecture?
I help organizations modernize their architecture to enable fast flow and GenAI-powered software delivery. If you’re planning or struggling with a modernization effort, I can help.
Learn more about my modernization and architecture advisory work →
Premium content now available for paid subscribers at
