Upgrades and releases
Maintainers release, consumers upgrade, and the CHANGELOG is the contract between them.
A plugin update replaces files in the plugin directory. Your home was copied out of templates/ once at init and has been yours to edit ever since, so a code update cannot safely overwrite it. The home is reconciled separately, on your terms.
Detecting "behind", locally
The home records its template version in .state/version.json (git-tracked, so it survives a clone). Compared against the installed plugin.json, that yields three states, shown as an upgrade notice (above the prompt or in the session banner) and on the dashboard badge:
| State | Meaning | Signal |
|---|---|---|
current | baseline equals installed | nothing |
pending | baseline behind installed; migrations await | "Upgrade ready" notice, an alert at two or more releases behind; amber badge "upgrade · N" |
onboard | no version.json yet | "Turn on update tracking" notice; badge "enable updates" |
The consumer flow
.state/updates/<from>-to-<to>/.deps runs bun install; settings merges missing permission entries and never removes yours; file copies new files only if absent; template/<file> section-merges AGENTS.md, SOUL.md, and friends: new sections added, changed ones updated, sections you added preserved. Optional changes ask first, with a diff.Guarantees: always backs up first, never overwrites a file wholesale, never deletes a section it does not recognize, only auto-applies what the release marked mandatory or additive, idempotent.
Renaming survives upgrades: the skill resolves the agent's name from your IDENTITY.md before diffing, so template changes arrive phrased in your agent's name.
Moving to .state in 0.7.0
Before 0.7.0 the data dir was named after the agent (.kevin/). From 0.7.0 every agent uses .state/, and version.json inside it records which plugin owns the folder. The first upgrade after updating to 0.7.0 moves the folder for you, with nothing to answer:
"plugin": "agent-kevin" into .kevin/version.json..state/secrets deny rules to the home's .claude/settings.json and the .state/ rules to .gitignore, before anything lands there. The old rules stay..kevin/ to .state/ in one step, with everything inside it..kevin/ path in your machine-local config to .state/: a server in .mcp.json that loads .kevin/secrets/.env, and anything you put in .claude/settings.local.json yourself, such as an env value, a hook or a permission.Every file it rewrites is backed up under .state/updates/ first, and running upgrade again finishes a move that stopped partway. The old rules stayed beside the new ones until 0.8.0, whose upgrade removes them (below). From 0.8.0 the plugin no longer reads or moves .kevin/: a home still on it needs v0.7.3's upgrade first.
Close the other sessions first
Close the agent's other sessions before you run upgrade. A session started on the older plugin stops recognizing the home once the folder moves: its tools refuse and its transcript is not captured.
Two things stop the move without changing anything. On Windows, a folder can't be renamed while a file inside it is open (an editor, a sync client, another session); close it and run upgrade again. And if a .state/ folder already exists that does not record this plugin (one you made by hand to hold a key, say), move what you put there into .kevin/, move .state/ aside, and run upgrade again.
One name per knob in 0.8.0
Before 0.8.0 a KEVIN_* variable overrode its AGENT_* twin. The plugin now reads AGENT_* alone, and the first upgrade renames what your home still holds:
env keys in .claude/settings.json and settings.local.json, and $KEVIN_* references in any string there..state/secrets/.env, line by line, keeping values, comments and the file's permissions.env keys in .mcp.json..kevin/secrets deny rules the 0.7.0 move left in both settings files, and the .kevin lines in .gitignore. Your own rules that mention .kevin stay, and a home that still has a .kevin/ folder keeps all of them.Where both spellings are set, the KEVIN_* value wins, since it was the one in use. Every file is read before any is written, so one that doesn't parse stops the run with nothing changed, and each rewritten file is backed up first. The report names keys, never values. Restart Claude Code (and Codex) afterwards.
upgrade lists, but never edits, KEVIN_* keys in your user-level ~/.claude/settings.json; nothing reads them any more. Delete each there, and move a per-home value into each home's settings.local.json as AGENT_*.
Media and scripts at the home root in 0.8.1
.claude/ now holds only what Claude Code itself reads. The first upgrade moves the avatar from .claude/assets/ to assets/ and each of your browser flows from .claude/browser-flows/<flow>/ to scripts/browser/<flow>/, its .env with it, then points IDENTITY.md at the moved avatar. Where the new path already holds the same file, the old copy goes; where it holds a different one, both stay and the report names it. Running upgrade again changes nothing.
A seed bundle made before 0.8.1 no longer imports. Export it again from an updated home.
GitHub writes and a token per owner in 0.8.3
Nothing changes until you choose it. upgrade offers, in a home with the GitHub pack, to grant the four write tools (github_issue_create, github_issue_comment, github_issue_update, github_pr_update) and to deny gh in the agent's own shell; a home wired for Codex gets the deny as a forbidden rule. Decline it to keep the pack read-only. Your GITHUB_TOKEN keeps working for every repo.
When your repos sit under more than one GitHub owner, add a GITHUB_TOKEN_<OWNER>= line per owner to .state/secrets/.env in your editor (my-org → GITHUB_TOKEN_MY_ORG) and restart. For writes, give that owner's token Issues or Pull requests: Read and write. See GitHub pack.
Helpdesk queues and the App Store pack in 0.8.4
upgrade adds the helpdesk skill's grant and the manual template's lines for reports/helpdesk/ and a project's helpdesk.md on its own. In a home that already has the Helpdesk pack, it offers to grant the four new reads (helpdesk_connections, helpdesk_accounts, helpdesk_lookups, helpdesk_stats); decline and each asks on first use. Your existing helpdesk keys keep working as the default connection.
To work a project's queue, run helpdesk setup acme-shop or say "set up helpdesk for acme-shop". To read an app's App Store reviews, run configure-skills → App Store. See Helpdesk.
Raising tickets in 0.8.5
upgrade updates two lines of the manual on its own: scratch files keep the exact path mktemp printed, with nothing after the X's, and a claim about the machine's current state is checked in the same turn.
Two steps are yours. In each queue profile (projects/<slug>/helpdesk.md), rename ## Filing bugs to ## Raising and say where feature requests and tasks go if they shouldn't follow bugs; the skill no longer reads the old heading. In a home with the Xcode pack, add the ground rule "Set the run destination after every scheme switch" to .claude/rules/xcode.md; other homes skip it. See Helpdesk.
Pull requests and hand-offs in 0.8.6
upgrade adds github_pr_create to permissions.ask on its own, in every home, so opening a pull request always waits for you. Until it does, the server refuses the tool. In a home with the Xcode pack, it offers to add mcp__xcode__DocumentationSearch to permissions.allow, and in a home with the GitHub pack, github_comment_update. A Codex home gets its tool prompts when upgrade regenerates the wiring. See MCP tools.
Assigning tickets in 0.8.7
In a home whose Helpdesk pack grants helpdesk_note, upgrade offers to grant helpdesk_assign beside it; decline and it asks on first use. One step is yours on each SupportCandy site a connection reads: if the site runs a caching plugin, turn off REST API caching (LiteSpeed Cache → Cache → Cache REST API) or exclude /wp-json/supportcandy/, then purge. A ticket list that answers 200 to a request with no login is being served from the cache. See Helpdesk pack.
The attention skill in 0.8.8
upgrade runs a one-time migration: each projects/<slug>/focus.html becomes attention.html (an existing attention.html wins), the queue cache moves from .state/focus/ to .state/attention/, and any focus_write or Skill(agent-kevin:focus) rule in either settings file becomes its successor in the same allow, ask, or deny list. Both settings files are read first, so one that doesn't parse stops the run with nothing changed. The manual's memory-routing row and reports/radar/ comment name the attention skill. One step is yours: a schedule or script outside the home that runs /agent-kevin:focus, /focus where-am-i or /focus triage needs /agent-kevin:attention or /attention checkpoint all. See Attention.
From 0.8.8 a renamed tool's permission rule migrates the way a retired skill's already did: upgrade and seed import map it to its successor in the same allow, ask, or deny list, so a dead grant never comes back and a gate you placed carries over.
The GitHub sweep in 0.8.9
Nothing changes until you choose it. In a home with the GitHub pack, upgrade offers to grant github_sweep beside the other GitHub tools; decline and it asks on first use. It also offers the SOUL line that makes "tldr" restart step by step, and the IDENTITY line that says the evening wrap ends on tomorrow's first moves. See Everything waiting on you.
Per-agent subscriptions in 0.9.0
Claude Code 2.1.314 is required first: upgrade stops below it with claude update. Then, only in a home whose .claude/settings.local.json sets CLAUDE_CODE_OAUTH_TOKEN, upgrade runs a one-time migration: the token moves to .state/secrets/.env.claude.json (owner-only, with an AGENT_SUBSCRIPTION marker) and the key leaves settings.local.json, every other setting kept in place. A different token already in that file stops the move and says so. A home without a token sees none of this.
When the home has a subscription, upgrade asks whether to add the agent command to your shell profile (~/.zshrc, ~/.bashrc or the PowerShell profile, which live outside the home), to show you the one-line command instead, or to skip. From then on, start that agent with agent from its home; after the session ends, run source ~/.zshrc (PowerShell: . $PROFILE.CurrentUserAllHosts) or open a new terminal so the shell knows the command. See Billing per agent.
The maintainer flow
release diffs everything since the last tag, groups it into Added / Changed / Fixed, detects what consumers need by inspecting the diff (dependency changes, touched templates, new skills or tools needing permissions), writes the Upgrade block, bumps the version, prepends the CHANGELOG entry, and stages a commit and tag for approval. It never commits or pushes on its own.
The Upgrade-block format
Each release carries an ### Upgrade section. Every actionable line is a backticked tag plus a note:
- `<kind>: <severity>` — <note>| kind | severity | what the upgrade does |
|---|---|---|
deps | required | runs bun install |
settings | mandatory | adds the named permission, hook, or env entries |
file | additive | copies a new file if absent |
template/<f> | mandatory | section-merges, applied automatically |
template/<f> | optional | section-merges, asks first with a diff |
script | required | runs a one-time migration at skills/upgrade/scripts/<version>.ts through the run_upgrade tool, outside the sandbox |
manual | any | a step only you can do; surfaced, never silent |
A code-only release writes one line: None — code-only, no bun install or HOME changes.