Instruments a repository for CircleCI deploy markers, generates deploy and rollback pipelines, and wires up release validation webhooks. This is the editor-native equivalent of the guided deploy setup in the CircleCI web app.
Use the whole repository, not one job
The guided setup in the web app works from a single job's YAML, so it has to guess at values like the deployed version and the target namespace from that one block.
You are not limited that way. Read scripts/deploy.sh, Helm values, Dockerfiles, Makefile
targets, and existing CI config, and infer those values from what the project actually
does. Fall back to a generic placeholder only when the repository genuinely does not say.
Show the user what you inferred so they can correct it — see step 2.
Order of operations
flowchart TD
Audit[1. Audit what already exists] --> Ask[2. Report findings and agree the scope]
Ask --> Markers[3. Instrument deploy markers]
Markers --> Val{Validation in scope?}
Val -->|yes| RelJob["4. Add the type: release job<br>and the validation block"]
Val -->|no| Pipelines
RelJob --> Pipelines[5. Generate deploy.yml and rollback.yml]
Pipelines --> Verify[6. Validate config and check invariants]
Verify --> Review[7. Interactive diff review]
Review --> Commit["8. Commit on a branch and open a PR<br>(direct to main only if asked)"]
Commit --> Merged{Config on the default branch?}
Merged -->|"not yet, PR open"| Wait["Register now, but say it cannot<br>trigger until the PR merges"]
Merged -->|yes| Register[9. Register pipelines]
Wait --> Register
Register --> Val2{Validation in scope?}
Val2 -->|yes| Secret["10. User mints webhook secret"]
Secret --> Monitor["11. User configures monitoring, from your instructions"]
Monitor --> Smoke[12. Real deploy to confirm matching]
Val2 -->|no| Done[Done]
Steps 3 onward cover only what the user chose in step 2. Skip the rest without comment.
All config work happens before the commit. The validation block and its
type: release job are config changes, so they belong in step 4 — not alongside the
monitoring work in step 11. Committing first and discovering the release job is missing
means a second round trip through review and approval.
When validation is in scope, deploy markers must not include a deploy-job
--status=SUCCESS step for that plan — success is delegated to the release job. See
references/validation.md and references/markers.md.
The config must reach the branch before registration is useful. Registration references a config file path, not a blob, so a definition created against a file that is not on the branch resolves to nothing when triggered. Committing first is therefore necessary — and with a PR flow, "first" means the PR has to merge before the pipeline can actually run. You can still create the definition while the PR is open; just say it will not trigger until the merge. See step 8.
Step 12 is not optional if validation is in scope. See references/validation.md —
the webhook endpoint returns success even when nothing matches, so only a real deploy
proves the setup works. It is also the only step that catches a tag mismatch.
Topic files
Load these on demand; do not read them all upfront.
| File | Read it when |
|---|---|
references/markers.md |
Instrumenting jobs with deploy markers (step 3) |
references/orbs.md |
The repo uses an AWS deploy orb |
references/pipelines.md |
Generating deploy.yml / rollback.yml (step 5) |
references/verification.md |
Before every diff review — the six invariants (step 6) |
references/validation.md |
The user wants release validation or auto-rollback (step 4, and diagnosis at step 12) |
references/api.md |
Registering pipeline definitions via CLI (step 9) |
references/ui-steps.md |
User-handoff steps: designate pipelines, mint webhook secret (steps 9–10) |
references/monitoring.md |
Instructing the user to wire up webhooks and monitors (step 11), or the user named a monitoring tool with no built-in defaults |
Step 1: audit what already exists
Never start setting things up on arrival. Onboarding is partial far more often than it is absent, and the user may want to redo a piece that already exists. Build the inventory below first, reading only — no edits, no API writes.
Check the CLI first, because it determines how you do the rest of the audit — the registration check below is a CLI command.
| Component | How to check |
|---|---|
circleci CLI |
circleci version, then circleci auth me. Not required, but recommended — raise it in step 2 if absent. Registering pipelines needs a write-scoped token, which you cannot check for; say so in step 2 rather than discovering it at step 9 |
| VCS and slug | git remote get-url origin |
| VCS integration | circleci pipeline list --json --jq '.[].config_source.provider'. This bounds the achievable scope — deploy and rollback pipelines do not exist on GitLab, Bitbucket, or Cursor Origin. Raise it in step 2, see references/api.md |
| GitHub App connection | Only if the above says github_oauth. A github_oauth project can still take App definitions if the org has the App connected, and the provider alone cannot tell you — run the provider/repositories probe in references/api.md. Checking here avoids discovering it as a failed write at step 9 |
| Deploy jobs | Read .circleci/config.yml in full. Watch for setup-workflows or dynamic config, where the deploy job lives in a continuation config |
| Deploy markers | Per job: absent, log-only, partial, or complete. Check for circleci run release steps and for deploys/plan / deploys/log from the circleci/deploys orb, which is instrumentation with no circleci run release text in it. See the detection rules in references/markers.md |
| Kubernetes deploys | If a job runs kubectl or helm, ask whether they use the CircleCI release agent — it changes which markers are correct, and the repo cannot tell you. See references/markers.md |
| Deploy pipeline | Does .circleci/deploy.yml exist, and is it registered? |
| Rollback pipeline | Does .circleci/rollback.yml exist, and is it registered? |
| Registration | circleci pipeline list --json and circleci deploy settings --json. Both default to the git remote, so no IDs needed. See references/api.md |
| Release job | Is there a type: release job, and does its plan_name match a plan name used by a marker? Required for validation, see references/validation.md |
| Validation config | A validation: block on that type: release job |
| Monitoring | Ask. There is no reliable way to detect monitor tags from the repo |
A file existing and a pipeline being registered are different facts, and either can be true without the other. Check both rather than inferring one from the other.
The trap worth naming: a repo touched by circleci deploy init has a single
circleci run release log step and looks instrumented. It is not — that is a deploy
record with no release lifecycle. Report it as "log-only, needs upgrading", never as
"markers present".
Step 2: report findings and agree the scope
Show the inventory, then ask what to set up. One consolidated question, not a sequence of them.
Offer the fullest setup as the recommended default: deploy markers, deploy pipeline,
rollback pipeline, validation with auto-rollback, and monitoring. It is the configuration
the rest of the product assumes, and the partial ones mostly exist for people with a
specific constraint. Mark it (Recommended) and let the user narrow from there rather
than assembling upward from nothing.
State prerequisites honestly when they affect the choice:
- auto-rollback needs a registered rollback pipeline, not merely a
rollback.ymlfile - validation needs a monitoring tool the user can actually configure
- validation without markers is meaningless: there is no planned release to attach to
- the VCS integration may put part of the scope out of reach. Deploy and rollback
pipelines are unavailable on GitLab, Bitbucket, and Cursor Origin, and need a connected
GitHub App on a GitHub OAuth org — and auto-rollback needs a rollback pipeline, so it
goes with them. Say this before offering the full setup, so you are not recommending
something the integration cannot do. Markers and validation still work on all of them,
and that is most of the value. For a GitHub OAuth org, mention that adding the App is a
one-off that unlocks the rest and coexists with their existing integration — and that it
must be started from Org → VCS Connections in CircleCI, not from GitHub, or it will
not connect. See
references/api.md
Ask which monitoring tool they use, and say that any tool works. Datadog, Grafana,
Prometheus and Alertmanager have built-in defaults, but provider: custom handles anything
that can POST to a URL with a custom header — New Relic, Honeycomb, Sentry, CloudWatch,
in-house alerting. Users assume an unlisted tool means "unsupported" and quietly drop
validation from the scope, so name the possibility rather than listing four providers and
waiting. If they name something you do not know, read its docs and map it —
references/monitoring.md has the procedure.
Fold the delivery question into this same message: branch and PR (the default), or commit directly to the default branch. Asking here costs one line and saves discovering at step 8 that they wanted a PR after you already pushed. See step 8.
Recommend the CLI up front, if they do not have it
When step 1 found no circleci CLI, say so in the same message as the inventory —
before any work starts, not when you first trip over a missing command. Recommend
installing it, and be specific about what it buys them:
- compilation checking. Without it you cannot run
circleci config validate, so a syntax error reaches CI instead of being caught locally - pipeline registration.
circleci pipeline createreplaces hand-assembled API calls, and resolves the project from the git remote - no tokens in commands. The CLI reads its own stored credential, so nothing you run carries a secret
Install with the local CLI instructions, then
circleci auth login — an OAuth browser flow that needs no token from them. If it is
installed but unauthenticated, circleci auth login is the whole fix.
Tell them to choose Write on the consent screen. It offers Read, Write, and Admin;
Read is enough for the audit and then fails at step 9, because registering a pipeline is
a write. Admin is not needed. Mention it whenever you send someone to auth login — a
user picking the least privilege is being sensible, and cannot know it breaks a later
step unless you say so. The scope cannot be read back or changed afterwards, so the only
remedy later is logging out and authorizing again. See references/api.md.
Then make the offer honestly, because it is genuinely a recommendation and not a gate:
everything still works without it. The config generation is the valuable part, all six verification invariants run on
gitandgrepalone, and every API step has a UI equivalent inreferences/ui-steps.md. Offer to proceed either way and let the user decide — do not stall waiting for an install, and do not quietly skip checks instead.
Whatever they choose, be explicit later about what went unverified as a result. A missing CLI must never turn into a silent pass.
Offer to regenerate what already exists
Every component found in step 1 gets an explicit choice — keep, regenerate, or
upgrade — and "already exists" is never a reason to silently skip it. Wanting a fresh
rollback.yml after the deploy job changed is a normal request, not an edge case.
Default to keep for anything complete and upgrade for anything partial, but always offer regeneration. Two things make it safe:
- Show a diff and get approval before overwriting. A regenerated file may drop hand-written customisations, so the user has to see what changes. This matters most for rollback jobs, where someone may have written real logic where you would emit a TODO.
- Regenerating a file does not require re-registration. The pipeline definition points at a path, so rewriting the contents at that path is enough. Only re-register if the file path itself changes. Do not delete and recreate a definition just to refresh a file.
If the user hand-edited a generated artifact, say plainly that regenerating will discard those edits and offer to work from their version instead.
Ground rules
Never assume the scope. Audit first, then ask what to set up, then act. Even when the user opens with "set up deploys", confirm the scope against what you found — the answer changes completely depending on whether half of it already exists.
Ask before assuming, once. Component name, environment name, and target version determine whether validation webhooks match later. A wrong guess here fails silently at step 12, not at step 6. Infer from the repo, then show the user what you inferred and let them correct it in one pass — do not interrogate them field by field. Fold this into the step 2 question rather than asking twice.
Existing is not the same as finished. Offer to regenerate or upgrade anything already present instead of skipping it. Skipping silently is how a log-only marker setup survives three onboarding attempts.
Never invent deploy or rollback logic. If the inverse of a deploy step is unclear,
emit # TODO: add rollback logic using ${TARGET_VERSION} and say so. Inventing
./rollback.sh when no such script exists produces a pipeline that fails at the worst
possible moment.
Validate before committing, always. Work through references/verification.md
and report which checks you ran. A dropped step is
the characteristic failure mode of generated config, and the invariants catch it.
Show the diff and stop. Config changes are the user's to approve. Never commit without an explicit go-ahead.
Approval of a diff is not approval of a destination. Default to a branch and a PR; push to the default branch only when the user asked for it or confirmed it. See step 8.
Secrets never enter the conversation. Never ask the user to paste a secret into the
chat, never echo or log one, never write one into a repo file, and never construct a
command containing one as a literal — composing that command is enough to put the value
in your context. Monitoring setup is handed to the user precisely so the webhook secret
stays out of it; see references/monitoring.md.
This is the practical reason to reach for the circleci CLI before curl: it supplies the
token from its own config, so no command you write ever carries a credential. See
references/api.md.
User-handoff steps stay with the user. Two actions never have a supported agent path:
designating the deploy/rollback pipelines, and minting the validation webhook secret.
Creating the definitions joins them on integrations where the API cannot. Do not attempt
undocumented internal endpoints, raw curl, or browser automation (Playwright, etc.) for
any of them — explain what to do using references/ui-steps.md, then verify designation through the
public read API when the user says they are done.
A handoff is not a silent skip. Whenever you hand a step over, say what you could not do and why, in the moment. The failure this guards against is the user believing setup is complete while nothing is registered.
Step 6: validate the config and check the invariants
Not optional, and not the same as circleci config validate. Every check in
references/verification.md describes a config that compiles cleanly while being broken:
a dropped deploy step, two plans for one deployment, an update naming a plan that was
never created, a premature SUCCESS that makes validation decorative.
Run them after generating the pipelines, so deploy.yml and rollback.yml are covered
too, and before showing the user the diff at step 7.
Report what each check found, and say plainly which ones could not be conclusive — a config using variable plan names, or block-scalar commands, limits what the greps can prove. "Validated" on its own is not a report.
Step 8: commit and open a PR
Default to a branch and a pull request. Committing straight to the default branch is opt-in, not the fallback. These are production deploy and rollback definitions; the web wizard opens a PR for the same change, and a local skill should not be the riskier path just because it has a shell.
Note what the approval in step 7 covered. "Yes, apply these changes" is consent to the
diff, not to a destination. Do not read it as permission to push to main.
Work out where you are before committing
git branch --show-current
git status --porcelain
git remote get-url origin
Three things change the answer:
- You are already on a feature branch. Commit there. No new branch needed — this is the common case when the user set things up before invoking you.
- You are on the default branch. Create a branch. Do not commit in place.
- The tree has unrelated modifications. Stop and say so. Do not sweep someone else's
work into a deploy-setup commit, and do not
git stashit away.
Committing direct to main
Only when one of these holds:
- the user asked for it, in words
- they confirmed it after you offered the PR — an explicit answer to an explicit question
A repo merely lacking branch protection is not consent. Nor is a single-contributor repo, a repo that looks like a sandbox, or a smoke-test project. If you are inferring rather than recalling something the user said, ask.
When in doubt, the cost is asymmetric: an unwanted PR is closed in a click, an unwanted
push to main is a revert to a production config path.
Opening the PR
Branch name should say what it is — deploy-setup, add-deploy-markers,
circleci-deploy-pipelines. Describe in the body what the agent did and what the human
still has to do, because steps 9 through 12 are not in the diff:
- which jobs gained markers, and whether any were upgraded from log-only
- the new files, and that they need registering as pipeline definitions
- that designating the deploy and rollback pipelines is a UI step the reviewer must do
- if validation is in scope: that monitoring needs a webhook and matching monitor tags, and that the setup is unproven until a real deploy runs
Use whatever PR tooling the environment has — gh pr create, a GitHub MCP, or just push
and hand over the compare URL. If none is available, push the branch and give the user the
link; do not fall back to committing on main because opening a PR was awkward.
What this changes downstream
| Step | Direct to main | PR flow |
|---|---|---|
| 9, create definitions | Works immediately | Works immediately; the definition is created against a path |
| 9, trigger the pipeline | Works | Not until merge — say so rather than letting them discover it |
| 12, smoke test | Run it | Run it after merge, since it needs a real deploy from the default branch |
Do not treat the PR as the end of the job. Say explicitly that you will pick step 9 back up, and what still needs doing once it merges.
Step 9: register pipelines
Split this into what you do and what the user does.
You (CLI): after commit and push, create pipeline definitions if they do not already
exist — see references/api.md. Check idempotently with circleci pipeline list --json
before creating.
If you cannot create them, say so here, plainly — and distinguish the two reasons, because only one has a workaround:
- The feature is unavailable on GitLab, Bitbucket, and Cursor Origin. There is no UI fallback; do not send the user looking for one. Markers and validation still stand.
- The GitHub App is not connected to the org. Every org can add it alongside their existing integration, and they must start from Org → VCS Connections in CircleCI — installing from GitHub's side leaves it unconnected and the create keeps failing.
When a create fails, read the error — the two common ones have opposite fixes:
- 404 — the token almost certainly lacks write access. It is not a missing
project, however much it reads like one; an authorization failure on a write returns
404, not 403. If
circleci pipeline listworks and only the create 404s, that is your confirmation. The fix iscircleci auth logoutthencircleci auth login, choosing Write. Try this before anything else. pipeline_definition.create_failed— the org has no connected GitHub App, rather than anything about this project.
Work through the diagnosis tables in references/api.md instead of retrying, and do not
invent a project-level reconnect step — there isn't one.
Never let a failed or skipped creation read as success. The committed config does nothing
until the pipelines are registered. See references/api.md for the support matrix.
The user (UI): designate which definitions are the project's deploy and rollback
pipelines. Give them the instructions from references/ui-steps.md — full URL, card
names, and the exact definition names to select (deploy, rollback). Do not try to do
this yourself.
You (verify): when the user confirms, read
GET /api/v2/deploy/projects/{project_id}/settings and check that
deploy_pipeline_definition_id and rollback_pipeline_definition_id point at the
definitions you created. Say plainly if either is missing or stale.
Step 12: prove it with a real deploy
Validation setup is not finished until a real deploy matches. Everything before this proves shape: the config compiles, the definitions exist, the webhook returns 2xx. None of it proves the monitoring payload actually resolves to a release — the ingest endpoint returns success even when nothing matches, so a synthetic POST cannot tell you.
Only a deploy from the default branch can. Trigger one, then check the release reached the
expected state and the validation attached to it, using circleci run list --branch and
circleci job output list, or the deploys UI. See references/validation.md for reading
the result and references/monitoring.md for the tag mismatches that cause silence.
If the user is not ready to deploy, say the setup is unverified rather than done, and tell them this is the step that would confirm it.
This skill ships no scripts
Everything is markdown. Verification is a set of commands you run ad hoc from
references/verification.md; monitoring setup is instructions the user follows.
That is deliberate, and worth keeping. Every skill CircleCI distributes externally is
SKILL.md plus reference markdown and nothing else, because asking someone to run a
vendor-supplied shell script against their own credentials is a much higher trust bar than
reading prose — and it needs tool-permission grants a prose-only skill never asks for.
Running commands is fine; shipping a file that runs commands is what to avoid. If the
verification logic outgrows what belongs inline, its home is a CircleCI CLI subcommand,
next to the config parser that defines what "valid" means — not a script vendored here.
The same argument applies to automating monitoring setup, which already lives with the
user for the separate reason that it keeps the webhook secret out of your context. See
references/monitoring.md.