ant apply: your agents, skills, and schedules as files in the repo
In brief
On September 3, 2026 Anthropic shipped `ant apply` in version 1.30.0 of the ant CLI. It reads agents, environments, skills, memory stores, and scheduled deployments from files in your repository, prints a plan, and reconciles the Claude API against them once you approve. A committed claude-lock.json maps each file to the resource it created. This is the piece that was missing between clicking an agent together in the Console and having one your team can review, diff, and roll back.
Contents
Anthropic shipped ant apply on September 3, 2026, in version 1.30.0 of the ant CLI. It creates and updates five kinds of Claude API resource — agents, environments, skills, memory stores, and scheduled deployments — from files that live in your repository.
You write each resource as a file, run ant apply, and approve the plan it prints. It writes a claude-lock.json recording which file produced which resource ID. You commit that alongside the files, and every later run — on your laptop or in CI — updates those same resources instead of making duplicates.
If you have used Terraform, you already know the shape. If you have not: the point is that the state of your agents stops living in a web console where one person changed something in March and nobody can say what or why.
The problem it solves
Until now, a Managed Agent was something you created through the Console UI or a one-off ant beta:agents create call. That works for one agent. It stops working at about four, and it fails in specific ways:
- No diff. Someone tightened the reviewer agent's system prompt. What did it say before? Nobody knows.
- No review. Prompt changes are the highest-leverage edits in the whole system and they were the only ones not going through a pull request.
- No rollback. A worse prompt shipped on Tuesday and there is no previous version to restore.
- No environments. Staging and production agents drift apart because they were built by hand, twice.
ant apply moves all five resource kinds into the same review path as your application code.
Your first agent
An agent is a Markdown file. The frontmatter is its configuration; the prose is its system prompt.
---
name: Summarizer
model: claude-opus-5
tools:
- type: agent_toolset_20260401
---
You are a helpful assistant that writes concise summaries.
Save it as agents/summarizer.md and apply it:
ant apply agents/summarizer.md
In an interactive terminal it prints a plan and waits:
First apply ./claude-lock.json does not exist yet and will be created
Resources will be created with
credentials API key (--api-key / ANTHROPIC_API_KEY)
host api.anthropic.com
organization 1b0c2a4d-6c1f-4f0e-9a57-2e8d1c3b4a5f
workspace wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ
± Name Plan
+ ./agents/summarizer.md create
Resources + 1 to create
Apply these changes? (y)es / (n)o / (d)etails y
Answer d for a field-by-field view before committing to it. --dry-run prints that detailed plan and exits without touching anything.
Edit the file, run again, and the plan shows an update rather than a create.
The lockfile is the important part
{
"version": 1,
"origin": {
"base_url": "https://api.anthropic.com",
"organization_id": "1b0c2a4d-6c1f-4f0e-9a57-2e8d1c3b4a5f",
"workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
},
"resources": {
"./agents/summarizer.md": {
"kind": "agent",
"id": "agent_011CYm1BLqPXpQRk5khsSXrs",
"version": "1",
"hash": "d23251c8d99b3613a64f3f8d87f5fad4",
"remote_hash": "1b771bee5bdbf600a5ad972fdac32d94"
}
}
}
Two hashes, and they do different jobs. hash fingerprints what the CLI last sent; remote_hash fingerprints what the API returned. Comparing the first against the file on disk tells ant apply you edited the file. Comparing the second against the live resource tells it somebody else edited the resource. That second check is the one that saves you.
The lockfile is written in the directory you run from, so run it from the repository root. It also pins the organization and workspace: ant apply refuses credentials that resolve anywhere else, which is what stops a misconfigured CI job from creating a parallel set of agents in the wrong workspace.
Commit it. It is also where you read an agent's ID when you need to start a session against it.
The other four resource kinds
Each file holds the request body you would otherwise POST to that kind's create endpoint. The kind is inferred from the directory:
| Kind | Location | Format |
|---|---|---|
| Agent | agents/ |
Markdown — frontmatter is config, prose is system |
| Environment | environments/ |
YAML |
| Memory store | memory_stores/ |
YAML |
| Deployment | deployments/ |
Markdown — prose becomes the message that starts each run |
| Skill | skills/<name>/SKILL.md |
A directory, uploaded as one bundle |
Anything except a skill can be YAML, JSON, or Markdown. In Markdown, the prose fills the kind's text field: an agent's system, an environment's or memory store's description, a deployment's first message.
If a file is not in one of those directories, ant apply falls back to a top-level type field, then to a filename prefix like environment_staging.md. Files matching none of the three — READMEs, CI config — are skipped when walking a directory.
Resources point at each other by path
This is the part that makes it a project rather than five separate files. Wherever the API wants another resource's ID, you write the relative path to that resource's file instead.
---
name: Code reviewer
model: claude-opus-5
tools:
- type: agent_toolset_20260401
skills:
- ../skills/pr-summary
---
You review pull requests for correctness, security, and readability.
---
name: Nightly review
agent: ../agents/reviewer.md
environment_id: ../environments/cloud.yaml
resources:
- path: ../memory_stores/review-notes.yaml
access: read_write
schedule:
type: cron
expression: "0 3 * * *"
timezone: America/Los_Angeles
---
Review any open pull requests. Start with the oldest.
ant apply . resolves the dependency order, creates the skill and the environment first, and substitutes real IDs. A path also works inside an object — the deployment's resources entry keeps its access key alongside the resolved ID.
Agent and skill references are pinned to the version applied in that same run, so editing the skill updates every agent that uses it in one command.
To point at something these files do not manage, write the literal ID (agent_..., skill_...). Anything else, like {type: anthropic, skill_id: xlsx} for a built-in skill, is passed through as written.
Skills can also come from GitHub, in the form https://github.com/<owner>/<repo>/tree/<branch>/<dir> — for example a directory of Anthropic's open-source skills repository. It downloads and uploads that directory, pinned to the resolved commit until you pass --upgrade. Set GITHUB_TOKEN for a private repo.
What happens when someone edits in the Console
This is the behaviour worth knowing before you adopt it, because it will happen in your first month.
If a resource was edited, archived, or deleted outside these files, the plan ends with This plan cannot be applied: and the reason, and the command exits with refusing to apply. It does not silently overwrite the Console edit.
--force overwrites it or creates a replacement. Reach for it only after you have looked at what the other change was.
Two more behaviours in the same family:
- Deleting a file does not delete the resource. You get a warning;
--prunearchives it (or deletes it, for a skill). - Renaming a file declares a new resource. The old one stays until you prune. Rename and prune in the same change, or you will quietly run two agents.
ant applycannot adopt an existing resource. Applying a file that describes an agent you built in the Console creates a second agent. The exception: the Console's Export as code download ships with its ownclaude-lock.json, so applying that updates what you already built.
Running it in CI
Without a terminal it prints the plan and stops: cannot ask for confirmation without a terminal; re-run with --yes to apply, or --dry-run to see the plan only.
The setup Anthropic documents:
# On pull requests — informational, exits 0 even when blocked
ant apply --dry-run .
# On the default branch after merge
ant apply --yes .
Four things that are easy to get wrong:
- Name the directory. A bare
ant apply --yesreconciles only what the lockfile already tracks, so a newly added file is silently skipped.ant apply --yes .picks it up. - Commit the updated lockfile even when the step failed. A partial apply still created things, and the lockfile is the only record.
- One apply at a time. Nothing locks the lockfile.
- Use Workload Identity Federation, not a stored API key. The identity has to resolve to the organization and workspace in the lockfile or the apply refuses.
The flags
| Flag | Effect |
|---|---|
--dry-run |
Print the plan, change nothing, do not write the lockfile |
--yes |
Apply without confirmation — required with no terminal |
--force |
Apply over a resource changed outside these files |
--prune |
Remove resources in the lockfile that no file declares any more |
--upgrade |
Re-resolve GitHub-referenced skills off their pinned commit |
--lock-file <path> |
Use a specific lockfile — keep one per organization or workspace |
--verbose, -v |
Show unchanged resources and full field values |
What this changes about how you work
Three things, in rough order of how much they matter.
Prompt changes get reviewed. The system prompt is the single highest-leverage line in an agent and it was the only part of your stack not going through a pull request. Now the diff on agents/reviewer.md shows exactly what someone changed about how the reviewer thinks.
Staging and production stop drifting. Two lockfiles, two workspaces, one set of files. The staging agent is the production agent because it is the same file.
Rollback is git revert plus one command. Which means you can afford to try a riskier prompt.
What it does not give you: an evaluation gate. ant apply will happily ship a worse prompt. That is still on you — see How to evaluate your agents and wire the eval run into the same CI job, before the apply step.
Try this today
Thirty minutes, and you end with one agent under version control.
Step 1 — upgrade and check. ant --version needs to report 1.30.0 or later. brew upgrade ant on macOS.
Step 2 — export what you already have. If you built an agent in the Console, use Export as code rather than retyping it. The download includes a claude-lock.json, so your first apply updates that agent instead of cloning it. This is the single step that most people skip and then regret.
Step 3 — apply it into a scratch workspace first. Not production. Run ant apply --dry-run . and read the plan in full. Then apply it for real and read claude-lock.json.
Step 4 — break it on purpose. Open the Console, change the agent's name there, and run ant apply again. You should see refusing to apply and the reason. Now you have seen the drift check work, which is the thing you need to trust before you point this at production.
Step 5 — commit. The files and the lockfile, in one commit, with the workspace named in the message.
Do not wire up CI on day one. Run it by hand for a week first, so that when the CI job refuses to apply you already know what that message means.
Related: The ant CLI · Claude Managed Agents · Managed Agents got budgets, an advisor, and geo pinning · Persistent memory for Managed Agents · Running Managed Agents on your own infrastructure · Deploying a Claude application to production · Claude Skills · When your agent breaks