Moving from akm 0.9 to 0.10
0.10 is a clean-up and tuning release. It replaces the engines in your config
with connections (the endpoints akm sends model requests to) and harnesses
(the agent programs you already have), and runs OpenCode 2 inside akm. It adds
no state.db migration and does not change the index.db layout (still 26). It
does remove CLI spellings, built-in improve strategies and a few workflow
features, it changes what a nightly akm improve does on its own, and it
changes how releases are numbered. This guide lists what to do, in order, and
every change that can break a script, a task or a config.
Checked against build 0.10.261013 with the connections and harnesses rework (#1244). The user-facing summary of the whole series is the 0.10 release note; the per-build detail is in the CHANGELOG.
What the upgrade preserves
- config,
state.db,index.db, task sources, frozen workflow plans and scheduler rows that 0.9.15 or later wrote; a config in theenginesform loads asconnectionsandharnessesuntil you migrate it (see Connections, harnesses and OpenCode); - every authored asset in your bundles;
- the
akm upgradeandakm migratecommands, with the same behaviour.
What it does not cover
0.10 reads what 0.9.15 and later wrote and converts nothing older. A config
still in the old stashDir / sources[] / installed[] layout fails to load
with one message that names akm migrate apply under akm 0.9.x.
An install older than 0.9.15 must go through 0.9.x first (step 1).
Upgrade procedure
1. Check your starting point
akm --version
akm migrate status
akm workflow list --active
- Older than 0.9.15? Install 0.9.31 first (
npm install -g akm-cli@0.9.31, or the same with Bun or pnpm, or the standalone binary from thev0.9.31GitHub release), runakm migrate applyunder it, then continue. Once 0.10 is thelatestrelease, a plainakm upgradewould skip that step. - 0.9.15 or later?
akm migrate statusshould end withstatus: "current". If it does not, runakm migrate applynow, under 0.9.x, and read what it changed. - Workflow runs in flight. A stored run whose plan has a
routestep or ascripttarget (both came from features 0.10 removed), or a command target frozen before plan version 8 (it froze an engine), cannot be decoded in 0.10;akm workflow runabandons it (statusfailed) and namesakm workflow run <ref>to start afresh. A run whose plan hasunit.isolationstill decodes and runs in the engine's working directory. Let active runs finish, or abandon them on purpose, before you upgrade. In 0.10akm workflow run <ref>always starts a new run (akm workflow run <run-id>continues one;resumeonly re-activates a blocked or failed one), runs are no longer scoped to a directory, and 0.9.15 does not see runs 0.10 started on the samestate.db.--newand--all-scopesare accepted and do nothing. - Pending retire proposals. 0.10 refuses to accept a retire proposal 0.9
wrote (it records no judged scope), so accept or reject pending ones with
akm proposal acceptorrejectunder 0.9 now, or reject them after the upgrade. - Quit OpenCode.
akm upgradeskips (reportsdeferred) a plugin update while an OpenCode process runs. See Plugins.
2. Find the callers that need a change
The spellings in the CLI and
improve tables are unknown flags
or commands in 0.10 (exit 2, UNKNOWN_FLAG / UNKNOWN_COMMAND), with no alias
and no hint that points to the new spelling. Search your scripts, hooks,
agent instructions, scheduled tasks and crontab for them before you upgrade:
grep -rnE -- '--shape|--target|help agents|task (list|validate)|config path --all|--reset|improve .*(--plan|--auto-accept|--run|--since)|--strategy +(quick|reflect-distill|thorough|catchup|proactive-maintenance)' <your script and task directories>
crontab -l | grep akm
--target is still valid on env run, bundle remove, bundle update and
registry remove (it names the thing to act on there). Read each hit.
Also look for akm env and akm secret calls that pass a bare name: they now
take a full ref (below).
--engine NAME is not in that list because it still runs, but search for it
too (grep -rn -- '--engine' <your script and task directories>): after the
migration it reaches only a connection or harness called NAME
(step 5).
3. Upgrade the program
akm upgrade --check
akm upgrade
akm --version
akm upgrade installs the newer release, then runs akm-migrate apply (the
migrator that shipped with the new install), then updates the harness plugins.
It exits 1 when the migration is blocked.
- Release channels. 0.10 releases are
0.10.YYMMNN. Prereleases (-alpha,-beta,-rc) publish to the npmnexttag and stable builds tolatest;akm upgrade --nextfollowsnext. See Version numbers. - OpenCode plugin installed?
akm upgradeholds the CLI to theakm-cliversion the plugin pins (see Plugins). If the CLI stays on 0.9.x and the output says it was held back, the plugin on that channel has not published a 0.10 build yet. - You can install a specific version directly with npm, Bun or pnpm
(
akm-cli@<version>), or replace the standalone binary after checking its published checksum.
4. Apply the config migration
akm migrate status
akm migrate apply --dry-run
akm migrate apply
akm upgrade already ran apply; run status to confirm. What apply does
in 0.10:
- rewrites
config.jsonunder a backup in<cache dir>/config-backups/: theengines/defaultsform becomesconnections/harnesses, the keys akm no longer reads from config move tocredentials.json, a leftovermodels.jsonis folded in and moved, and every other retired or unknown key is dropped (see Connections, harnesses and OpenCode and the removed keys below); - applies pending
state.dbmigrations. 0.10 adds none, so on a 0.9.31 install this step has nothing to do; - rewrites task files still at version 2 or 3 as task source v4 and reports
any it cannot convert as
blocked; - rewrites the retired
engine:key on commands, agents, workflows and task sources toconnection:orharness:, under one backup directory per run; - removes superseded residue files.
Until you run it, a config in the engines form loads as connections and
harnesses in memory, with one warning that names akm migrate apply, and any
other retired key is harmless: the config loads, names the key once, and
ignores it.
5. Fix what the migration cannot
-
improve.strategy(wasdefaults.improveStrategy) or--strategynames a removed strategy. The config still loads, butakm improveandakm task doctorfail (exit 78,UNKNOWN_IMPROVE_STRATEGY) with an error that namesdefault. Change the name, or define a strategy of that name yourself (below). -
Notes from
akm migrate apply. Each names a setting it dropped, or a key or an entry it could not move. A key it could not move stays on its connection asapiKey, which akm warns about and never sends: put it incredentials.json(akm setupdoes) or reference an environment variable ("apiKey": "$NAME").AKM_ENGINE_<NAME>_API_KEYandAKM_LLM_API_KEYbecome anapiKeyonly when they were set in the environment you ranapplyin; if not, the connection has no key and a note names the variables. Set the one you used and runakm setup --api-key-env NAME, or store the key withakm setup. -
Agent work no longer runs on your OpenCode (0.10 betas 0.10.261014 to 0.10.261017 only). Those builds dropped every
opencode-sdkengine when they migratedconfig.json, soakm infolists no harness, agent work runs on akm's own runtime over your default connection, and aharness:or--harnessthat names one of your old engines fails with exit 78. akm keeps the file as it was before it rewrote it in<cache dir>/config-backups/(~/.cache/akm/config-backups/by default), the five newestconfig-<timestamp>.json; the one that still holds"engines"is the one to use (grep -l '"engines"' ~/.cache/akm/config-backups/config-*.json). Read what this release converts it to, in a scratch config directory so nothing is written, with themodels.json.<timestamp>of the same run beside it if there is one, then set each harness on your config (leave out theok,shapeandschemaVersionkeys the output adds):scratch=$(mktemp -d) cp ~/.cache/akm/config-backups/config-<timestamp>.json "$scratch/config.json" cp ~/.cache/akm/config-backups/models.json.<timestamp> "$scratch/models.json" AKM_CONFIG_DIR="$scratch" akm config get harnesses akm config set harnesses.<name> '<that entry>'If no pre-migration copy is left (five later config writes prune it), write the entries yourself, one per
opencode-sdkengine you had, the onedefaults.enginenamed calleddefault:akm config set harnesses.default '{"platform":"opencode","models":{"fast":"<provider/model>","balanced":"<provider/model>","reasoning":"<provider/model>"}}'. Add"agent": "<name>"if the engine named one. Runakm infoafter: itsagentsrow names the harness and the model. -
Scripts that pass
--engineor--require-engines. They keep running, with one warning each. Change--engine NAMEto--connection <name>or--harness <name>: how an old engine name resolves, and when it stops, is under Theenginesform.--require-enginesdoes nothing now, and a scheduled caller that relied on it loses its guarantee: the run no longer checks, before any side effect, that every enabled process has a usable target (a configured connection or harness to run on, a harness program that exists, a connection that answers).akm improvestops at planning (exit 78) only when no process has anywhere to run; when some do and some do not, it runs the ones that do and lists the rest inskippedProcesses. Useakm healthfor the check:akm health && akm improve ...stops before the run when it exits 4, and itsconnections-and-harnessescheck names each connection that does not answer, each harness program that is not installed and a missing default. It looks at the configuration and the endpoints, not at whether a completion works (only a run shows that). -
Scheduled tasks that call a removed strategy, flag or command. Edit the task source, then run
akm task sync. Tasks copied from the shipped templatesakm-improve-nightly,akm-improve-frequentandakm-improve-catchupkeep their--strategy; change it todefaultorconsolidate. -
A consolidate task copied from the shipped template runs with the old 2-hour budget. The shipped
akm-improve-consolidatetask now passes--timeout-ms 3600000so its 00:20 run ends before a 02:00 nightly; add the flag to your copy if you run both. -
Bundles you relied on
akm indexto refresh.akm indexno longer fetches a git or website bundle again after twelve hours as 0.9 did; bundles are fetched when added and onakm bundle update, so scheduleakm bundle updatewhere you need them kept current. -
secret://and${secret:NAME}. Both still load with one warning, butakm migrate applyrewrites onlysecret://nameinconfig.json, andakm config setandakm bundle add --credentialno longer accept it, so write${secrets/NAME}in your env files and scripts. -
Workflows. Rewrite any
.ymlworkflow as Markdown and remove the removed workflow features. -
Pasted agent guides. If you pasted
akm help agentsoutput into anAGENTS.mdor a system prompt, regenerate it withakm hints --detail brief(orakm hintsfor the complete guide). The old text uses--shape.
6. Update the plugins and other callers
See Plugins. Do this in the same sitting: a 0.9 plugin passes
--shape agent, which 0.10 rejects, and a 0.10 plugin passes --detail agent,
which 0.9 rejects.
7. Verify
See Verify the upgrade.
Breaking changes
CLI spellings that are gone
Each is an unknown flag or command (exit 2) from 0.10.
| Gone | Use |
|---|---|
akm help agents |
akm hints (complete guide); akm hints --detail brief for the short one |
--shape agent (any command) |
--detail agent |
--shape summary (only akm show used it) |
--detail brief |
--detail values |
now brief, normal, full, agent; agent trims search, curate and show, other commands ignore it |
--target on import, env create, env remove, secret set, proposal accept, proposal diff, proposal revert |
--bundle |
akm task validate <path> |
akm lint --type tasks (also runs the two gates akm task sync runs; point --dir at a bundle root, not a file) |
akm task list |
akm search --type task |
akm config path --all |
akm info (reports the bundle, config, data, cache and state directories) |
akm improve --plan |
akm improve --dry-run |
akm improve --auto-accept |
akm improve && akm proposal drain --promote --yes, or a triage block with applyMode: "promote" |
akm improve --run, akm improve --since |
akm improve report --run / --since |
akm workflow create --reset |
--force (alone: replace with a fresh template; with --from <file>: replace from the file) |
Also gone, with no replacement needed:
- every hint that told you the new spelling of a retired 0.9.0 command or
flag. A retired command is now a plain
UNKNOWN_COMMAND(with a "did you mean" only when the name is close) and a retired flag a plainUNKNOWN_FLAG; - the error codes
INVALID_SHAPE_VALUE;INVALID_DETAIL_VALUEnow listsagent; akm search --assets, which printed nothing; it is now an unknown flag, so drop it from your scripts;task runandtask explainno longer reserve the input nametarget.
akm env create|run|path|export|remove and akm secret set|run take a full
ref (env/prod, team//secrets/token). A bare name such as prod is a usage
error (exit 2, INVALID_FLAG_VALUE) that names the full form: akm env create prod is now akm env create env/prod.
akm improve report and akm improve judge are now real subcommands. Both
spellings you used before still work; --run and --since belong to report
alone, and --strategy is also judge's own flag. akm improve [scope] is
unchanged. akm improve canary is now an asset-type scope that matches nothing.
Improve strategies, tasks and config keys
Built-in strategies. Only default and consolidate are built in.
| Removed | Why / what to do |
|---|---|
quick |
Measured at 0.75 to 0.76 of items solved against default's 0.89 to 0.92. For a reflect-only run, define your own (below). |
reflect-distill |
Same measurement (0.77 to 0.78). Use default. |
thorough |
Added only a judged triage drain, which harmed items. Use default. |
catchup |
Identical to consolidate on the pool. Use consolidate. |
proactive-maintenance |
The lane now lives in default. |
A improve.strategies.<name> block with one of these names stays valid as an
ordinary user-defined strategy, but it now inherits default and no longer
carries the old built-in's settings. A reflect-only replacement for quick:
{
"improve": {
"strategies": {
"reflect-only": {
"processes": {
"distill": { "enabled": false },
"consolidate": { "enabled": false },
"memoryInference": { "enabled": false },
"triage": { "enabled": false },
"validation": { "enabled": false },
"proactiveMaintenance": { "enabled": false }
}
}
}
}
}
Shipped task templates. akm-improve-nightly, akm-improve-frequent and
akm-improve-catchup are gone. The nightly template for a server install is
now core/improve (akm improve, 02:00), and akm setup preselects it. A
scheduled command written for 0.9 keeps running: --require-engines is
accepted and does nothing (the run stops at planning, exit 78, only when no
process has a connection or harness to run on; the check it used to make, that
every enabled process has a usable target, is gone, and akm health is the
replacement), and --engine NAME on agent,
command run, task add, proposal new and proposal extract keeps running
(step 5). Each warns once, and neither is
listed in --help.
Config keys. These are removed. A config that still sets one loads (the key
is named once by the unknown-key warning and ignored), and akm migrate apply
drops it. Paths are under improve.strategies.<name>.processes. unless noted.
| Removed key | Note |
|---|---|
consolidate.antiCollapse, consolidate.p90ChunkSecondsDefault, consolidate.minPoolSize, distill.fidelityCheck, reflect.lowValueFilter, improve.salience.outcomeWeightEnabled |
Measured no effect. The pool_below_min_size skip reason goes with minPoolSize. |
improve.salience.salienceThreshold |
The high-salience lane it tuned is gone. |
distill.limit, memoryInference.cls, proactiveMaintenance.limit, triage.policy |
Nothing read them. distill.cls and the limit of reflect and consolidate are read and stay. |
defaults.llm, defaults.agent, defaults.improve, feedbackDistillation, index.<pass>.{endpoint,provider,apiKey,baseUrl,temperature,maxTokens,capabilities}, index.stalenessDetection |
0.9 rejected these with a bespoke error. They now load like any unknown key. |
execution.allowedTools (top level) |
Asset tool requests are gone (below), so there is nothing to cap. |
Asset tools:. Agents, commands and tasks no longer restrict an agent's
tools: an agent or command's tools: (or a Claude command's
allowed-tools:) is not read, and a task's tools: is ignored with a warning.
akm show no longer reports toolPolicy, a file is no longer recognized as an
agent by a tools: key alone, and the EXECUTION_NOT_AUTHORIZED error is gone.
To run an agent with restricted tools, define that agent in the harness itself
(a Claude or OpenCode agent) and select it with the harness's agent.
Config that is newly refused: a retired source key (stashDir, sources,
installed). It was only warned about in 0.9.15 and later; the error says to
run akm migrate apply under akm 0.9.x.
Workflows
Workflows are Experimental through 0.10. Removed:
- The GitHub-shaped YAML workflow format. A
.ymlunderworkflows/is skipped at index time with the message "must use .md". Rewrite it as Markdown. This takes with it workflow-stepuses: tasks/<ref>,uses: scripts/<ref>anduses: commands/<ref>, YAMLon.scheduletriggers, and thescriptfrozen target. A task that runs a workflow (uses: workflows/<ref>, or arun:that callsakm workflow run) is a task feature and is unchanged. - Top-level
outputs:(a lint error). A completed child workflow returns the output of its last step; a parent readssteps.<composing-step>.output. routesteps (a lint error). Branch with anexecor agent step that reads its inputs.unit.isolation: worktree(a lint error).
Child workflows stay, in a simpler form: a Markdown step declares
unit: { workflow: workflows/<name>, with: { <param>: <literal or { from: <reference> }> } }.
See Workflow schema.
One change in the other direction: a param's default: is now applied. A run
starts with each declared default for the params it was not given, where it
used to leave them absent. Workflows that restated their defaults in prose can
stop.
Internal surfaces and packaging
BundleAdapter.placeNew()is removed, with its nine implementations. It was never called; every write already used the fixed type-to-directory table. There is no behaviour change. A writable bundle in a non-akm layout would need per-adapter placement back (#1163).package.jsonhas anexportsmap:akm-cli/api,akm-cli/package.jsonandakm-cli/dist/*.akm-cli/apiexportscuratefor in-process recall by the plugins (see Programmatic API). Any other deep import path no longer resolves.- The task-source migrator moved to
scripts/akm-migrate/migrate/out ofsrc/.akm migrate applyandakm-migrate applybehave as before for data 0.9.15 and later wrote. - Dropped runtime shims. The
{kind, ref, sourceId}write-back ofscheduler.enabledis gone: 0.10 writes plain refs and still reads the object form. ThetargetVocabmarker ontask_historyrows is no longer written, and the"mcp"package keyword is gone (akm has no MCP code).
Connections, harnesses and OpenCode
engines become connections and harnesses, akm setup and akm health
are rebuilt around them, and OpenCode 2 runs inside akm. Read this section even
if you never wrote an engine: akm migrate apply rewrites your config and
moves your keys.
- A connection is an OpenAI-compatible endpoint (
endpoint,apiKey,models,contextLength,timeoutMs,concurrency; any other key, on the connection or in a model entry, is a request field sent as written). A harness is an agent program you already have (platform,bin,args,workspace,agent,timeoutMs,models). There is nodefaultsblock: the entry nameddefault, or the only entry, is the default connection or harness, and anywhere one can be named and none is, the default is used. With neither configured, model features and agent work are off and each command that needs one points atakm setup; there is no fallback to anopencodebinary onPATH. - Where a process runs is set by
improve.connectionandimprove.harness(all ofakm improve),improve.processes.<process>,improve.qualityGateandindex. A strategy says which processes run, never where.defaults.improveStrategyis nowimprove.strategy. - Aliases.
fast,balancedandreasoningare set on a connection's or harness'smodels.akm modelslists a connection's aliases, then the models its endpoint lists, andakm models set <alias> <model>changes one.models.jsonand theakm models listandcopy-defaultscommands are gone. - Keys.
apiKeyis a$VARreference. Without one, the key is the entry stored for the connection and its endpoint incredentials.json, next toconfig.json(mode 0600);akm setupfills it from a masked prompt. A key is read for the endpoint it was stored for and no other. A literalapiKeyin the file is warned about and never sent.apiKeyFile, a${secrets/...}apiKeyand the implicitAKM_ENGINE_<NAME>_API_KEYandAKM_LLM_API_KEYlookups are gone. Untilakm migrate applyhas filed it, a key held inapiKeyFile, a literal or a${secrets/...}reference is not sent (akm warns);akm upgraderunsapplyfor you. akm setuptakes one flag per question (--endpoint,--api-key-env,--name,--harness,--embedding,--embedding-endpoint,--embedding-api-key-env) and--yesfor the detected default;akm setup --endpoint http://localhost:11434/v1 --yesis the quick start.--probeand--configare gone.akm healthandakm infoprint one table (theconnections-and-harnessescheck, andconnectionsAndHarnessesinakm info; a row for each connection, each harness and each kind of work, with the connection or harness and model it resolves to) in place of the engine checks. The checksdefault-engine,default-llm-engine,configured-engines,active-improve-strategy,thinking-controlandengine-last-usedare gone, and an unreachable connection is a warning, not a failure.--connection,--harnessand--modelreplace--engineonakm agent,akm command run,akm proposal new,akm proposal extractandakm task add. A scheduled command that still passes--engine NAMEor--require-engineskeeps running, with one warning each and neither listed in--help;--require-enginesdoes nothing (see above).akm migrate applyrenames the default enginedefaultand moves an olddefaultaside tolegacy-default; what--engineandengine:mean until it has rewritten every key it can reach is under Theenginesform. It cannot rewrite a command line or script: change those to--connectionor--harnessyourself.
An old config still loads. A config.json with engines and defaults is
read as the new form in memory, with one warning that names akm migrate apply; the file is not rewritten until you run it. An ordinary akm config set edits the file as it is, and removing a value the old form supplies is
refused until the file is migrated. A connection or harness whose own settings
akm cannot use (no endpoint, an endpoint that is not a URL, a harness akm cannot
run) is ignored with one warning naming it, and the rest of the file loads.
akm migrate apply converts the file. Under a backup of config.json it
writes connections and harnesses, renames the default LLM engine to
default (references follow), moves what a strategy said about where a process
runs to improve.processes and improve.qualityGate, and keeps a connection or
harness the loader cannot use in the file, with a note on what to fix. It also:
-
keeps every agent engine as a harness, with its
model,bin,args,workspace,agentandtimeoutMs. Anopencode-sdkengine with nollmEngineran your own OpenCode, with its own providers, models and logins, so it becomes anopencodeharness (withoutargs, which 0.9 did not pass to it); the harnessdefaults.enginenamed, when there are several, is renameddefault, andengine:keys and--enginefollow. Agent work keeps running on the program and model it ran on. Anopencode-sdkengine over anllmEngineran OpenCode over that connection, which is what akm's own runtime is, so it has no entry of its own; -
notes, when there is no
defaults.llmEngineand no connection, that akm's own model work (improve, index passes, extraction, judges) now runs on the default harness where 0.9 ran none: 0.9 ran it only wheredefaults.llmEngineor a setting named an engine, and a workflow gate's judge ran ondefaults.engine. To keep the 0.9 behaviour, setmodelWork: falseon that harness; a call that names the harness still runs there, and a gate's judge then needs a connection; -
moves every key akm no longer reads from config (an engine's
apiKeyFile, a literal or${secrets/...}apiKey, and the same on a connection,embeddingorsearch.curateRerank) intocredentials.json, for the connection (or theembeddingorcurateRerankservice) and the endpoint the block names, with one note per key and never its value. A key that cannot be moved (its secret does not resolve, the block names no endpoint of its own, aconnectionsentry now gives it another endpoint than its engine wrote the key for, orcredentials.jsonalready holds a different key or endpoint for that slot) stays on the connection asapiKey, with a note, until you move it.AKM_ENGINE_<NAME>_API_KEYandAKM_LLM_API_KEY, when set in the environment you runapplyin, becomeapiKey: "$VAR"instead; -
files a key in
credentials.json's older flat{ "<name>": "<key>" }form under the endpoint your config gives that block, after copying the file to<cache dir>/config-backups/credentials.json.<timestamp>. A block that already has a stored key is not overwritten: the same key for the same endpoint drops the older entry, and a different key or endpoint leaves both, with a note; -
folds
models.jsoninto themodelsof the connections and harnesses it names (a connection's own column first, then the*column and the flat shorthand, then the engine's own model; a harness engine's own model stands over every column, as it is what ran when a request named none; a model the config already names stands; the entries it cannot place are listed in the notes) and moves the file to<cache dir>/config-backups/; -
rewrites
engine:on commands, agents, workflows and task sources toconnection:orharness:by what the name is now (a name that is neither is written asharness:, with a note), under one backup directory per run. A file you (or an editor or a bundle sync) changed after the plan was made is left exactly as it now is, in no backup and no rewrite, and is reported as skipped or still ready: runningakm migrate applyagain plans it afresh. An asset that is a symbolic link is read but never rewritten: it is reported as skipped, and itsengine:key keeps its meaning until you change the file it leads to.
akm migrate apply --dry-run lists all of it first, and akm upgrade runs it
for you.
Dropped, with a note. provider, an extraParams key that shadows a
first-class setting (the setting wins), supportsJsonSchema (akm retries
without a schema when an endpoint rejects one), workflow.judgeEngine, a
strategy's engine, model, llm and timeoutMs, an index pass's engine
that names a harness (an index pass can only name a connection; with none named
it runs where all model work does, on the default connection, else the default
harness, restricted where the harness can be), models.json
entries that name nothing configured, and the model, timeout and workspace of an
opencode-sdk engine that ran over an llmEngine (akm's own runtime has no
entry in config; that connection becomes default). workflow.judgeEngine
is dropped because a gate's judge runs on the default connection, else the
default harness; its note says whether that moves the judge, and with no
workflow.judgeEngine a note says when the judge defaults.engine ran it on
is no longer where it runs. A workflow run
frozen by an earlier
release (plan version 7 or lower) whose plan holds a command target cannot be
resumed: akm workflow run abandons it with a message naming akm workflow run <ref> to start afresh. Let such runs finish before you upgrade.
Harnesses run as thin shells. akm writes only the arguments a program needs
to run without a person, hands it the prompt, and takes its standard output as
the reply, as written. It no longer asks a harness for JSON output or reads a
result or a session id out of it. Claude Code and pi take the prompt on stdin.
A harness's child gets your environment as it is, with akm's directories set
over it (The environment programs run
in).
akm agent with no --prompt starts the harness for a person.
OpenCode 1 is legacy, not deprecated for removal. The opencode harness runs
opencode run for both majors, with no change to the config. Where akm reads
its version (akm setup, akm upgrade, and model work) and finds OpenCode 1, it
warns once that OpenCode 2 is recommended; OpenCode 1 keeps working, its model
work cannot be restricted, and no removal date is set.
Model work runs on any harness, with its tools restricted where the harness
can be (Claude Code, Codex, OpenCode 2) and unrestricted, with a notice, where it
cannot (How akm runs a
harness). A config that
names an opencode harness for model work loads.
akm's own runtime is a pinned OpenCode 2 binary that akm fetches and runs.
Agent work on a connection, with no harness configured, runs on it: no entry in
config, no opencode of yours, driven by your connections only (no user or
project OpenCode config loads, though it still loads ~/.agents and OpenCode's
system config, /etc/opencode; OpenCode's own free-model provider and model
catalog fetch are off). The first run downloads the binary for your platform from
the npm registry (about 114 MB, once, into <akm cache dir>/opencode/<version>/)
and checks it against the registry's integrity hash; if akm cannot reach the
registry for that step, enable the opencode harness with an installed OpenCode
2 instead. On bare Alpine (musl) the binary needs libstdc++ and libgcc, which
the Alpine Node image already has. Its sessions are stored in
<akm data dir>/opencode-runtime/data/opencode/opencode.db, with the rest of its
files under <akm data dir>/opencode-runtime/. A run reports its token usage, and
a persona goes in the prompt, not a system channel.
platform: "opencode" is your OpenCode, whichever major is installed, run
through its CLI (opencode run, the prompt on stdin). Your OpenCode owns its
configuration, logins and sessions: akm reads, copies and embeds nothing of
yours to run it, and its runs are in your OpenCode history, which improve reads.
Behaviour changes you will notice
akm improve
-
A nightly
akm improvenow drains the proposal queue. Thedefaultstrategy runs triage inpromotemode with judgment off, up to 200 accepts a run (it was off before). It accepts proposals a quality judge already stamped as passing, when their content has not changed since, and retirements the consolidate pair pass staged with no continuity risk. It never accepts a proposal from the proactive lane (reasonproactive-needs-review), an uncertain verdict, or a distill lesson. The judgment tier is off in every built-in strategy and, if you turn it on, accepts only consolidate promotions. To keep the old behaviour of leaving every proposal for you, set this in config:{ "improve": { "strategies": { "default": { "processes": { "triage": { "enabled": false } } } } } }Every accept is an ordinary accept: a git-backed bundle gets the usual commit, and
akm proposal revertundoes it. A standaloneakm proposal drainqueues by default;--promoteaccepts, asks for confirmation, and needs--yeswhen there is no terminal. -
The proactive-maintenance lane is on in
default. It plans up to 15 assets a run that have no fresh feedback and were not reflected or distilled in the last 30 days. Its proposals wait for you.--require-feedback-signalturns it off for one run;processes.proactiveMaintenance.enabled: falseturns it off in a strategy. -
Sync before the run. On a git-backed bundle, a live run does what
akm syncdoes right after it takes its lock and before it plans: commit pending edits in the managed paths, fetch, fast-forward or merge, push. A conflict or a failed fetch warns and the run continues on local state. The result carriespreRunSync.--no-syncskips both the pre-run and the end-of-run sync, and--no-pushskips the push. -
Uncertain reflect verdicts go to a person. A reflect revision the judge does not pass but scores 3.5 or more becomes a pending proposal (
judge-uncertain, shown asgate=deferred:judge-uncertain) with no 14-day lock on the asset. A lower score is refused as before. A distill lesson or promotion whose judge is missing is queued for review, not locked out for 30 days. -
The retrieval regression gate is gone. After the judge passed a revision, reflect used to grade old and new text against the asset's retrieval queries and refuse the revision if the grade fell. It refused 12 to 17 percent of revisions the judge had passed. A judge-passed revision is now minted as a proposal with no further check. The gate had no config key.
-
captureMode: hotmemories are consolidated like any other. The pair pass may retire one and the promote pass may promote and archive one. -
Distill can extend a lesson. When a memory repeats an existing lesson, a proposal on the lesson's own ref adds the new lines (reason
distill-update). It is left for a person. -
Retirements expire. A retire proposal now expires by age like any other (
archiveRetentionDays, default 90) instead of never;akm proposal reopenbrings one back. One whose file or successor has changed is rejected once asstale-target. -
Per-run log files are purged.
$CACHE/logs/improve/and$CACHE/logs/index/files now followimprove.eventRetentionDays(default 90; 0 disables). -
akm improve <scope>warns on stderr when the scope matches no asset, naming the likely intended type. Exit code and plan are unchanged. -
A run killed by its budget watchdog now leaves an
improve_runsrow (budget_exhausted) and commits what it wrote, without pushing.
Feedback
- Manual fixes apply at once.
akm feedback --negative ... --replace/--with/--source,--superseded-byand--outdatedused to queue afeedbackproposal forakm proposal accept. They now file it and accept it in the same command (gate decisionmanual-fix, no judge). If the accept refuses, the proposal is rejected, the file is untouched and the command fails. Drop any follow-upakm proposal acceptfrom your scripts; useakm proposal revertto undo. - Feedback changes search and curate ranking. Each hit's score is
multiplied by
1 + 0.03 x (ln(1 + positives) - ln(1 + negatives)), counting your own feedback events for the asset (not improve, task or audit feedback). The effect is small: about +2 percent, +3, +5 and +9 for 1, 2, 5 and 20 positives. In keyword-only search a vote moves a hit one place whatever the keyword margin; when embeddings contribute too it breaks only near-ties. It takes effect without a reindex.rankingUpdate.appliedin theakm feedbackoutput is nowtrueexactly when the event counts toward ranking. - Utility has one formula.
akm feedbackandakm indexnow compute the utility score the same way, so the stored value no longer depends on which ran last. Improve andakm metricsread it; search does not.
Other commands
- JSON fields scripts read.
akm showdropsactiveRun,akm workflow listdropsscopeKey,akm task doctordropshistoryDir, andakm proposal extract --dry-runlists preview refs insessions[].previewRefsinstead ofdry-run:<ref>entries inproposals, so update scripts that read them. akm searchandakm curatedefault to--belief current(0.9:all), so deprecated, contradicted, superseded and archived assets leave the default results; pass--belief allwhere a script needs them.akm syncfetches first. On a writable bundle with a remote it fetches, fast-forwards or merges what another host pushed, then pushes. A merge that conflicts is aborted, your commit stays, the push is skipped andreasonnames the files. Before this it failed with exit 70 once another host had pushed.akm searchno longer warns "no embedding provider is configured" on a default install. It warns only for a remoteembedding.endpointwith noembedding.model.- Command tasks (
uses: commands/...) get the 6-hour unattended timeout that workflow and shell tasks already had. An explicit tasktimeout:, a connection's or harness'stimeoutMsortimeout: nullstill wins. - Memory inference writes to the default bundle (it used the first bundle in the list), and no longer reverts an edit made to the parent memory while the model ran.
- The session summary prompt fences the transcript as untrusted.
- A transient reflect failure (transport error, timeout, crash) no longer uses up the feedback that planned it; the ref is retried next run.
Local semantic search and installs
- akm no longer installs ONNX Runtime through npm.
akm setupwith the built-in embedder (--embedding local), or the firstakm indexafter the upgrade, downloads ONNX Runtime 1.24.3 once (about 86 MB) into akm's cache. The vectors are unchanged, so no re-index is needed. - Local embeddings are offered on Linux x64 (glibc) and
Apple-silicon macOS. Every other platform uses keyword search or an
embedding endpoint, and
akm setupoffers only those there. On such a platform, a config that still asks for local embeddings makesakm healthwarn and exit 4, so anakm health && ...chain stops until you runakm setup --embedding offor name an endpoint. - Standalone binaries are up to 36 MB smaller, and a
noexectemp directory no longer matters; akm's cache directory must still allow executing files. - On Node, the SQLite driver ships prebuilt for every supported Node
version, so
npm install -g akm-cliworks where npm skips install scripts (npm 12 does by default), and a Node upgrade no longer needsnpm rebuild. Nothing in the package runs an install script, the Node.js version check included: akm checks the version when it starts.
The environment programs run in
A harness (agent tasks and workflow agent steps included) and an exec unit's
command now run with your environment as it is. In 0.9 each got an allowlist
(PATH, HOME, locale and a few more, plus the provider keys a harness named,
and an exec unit's pass_env: names); a variable outside it, a token in your
shell included, did not reach the program. Now every variable does, and
pass_env: still loads and selects nothing. What akm scrubs from an agent's reply
is under Architecture: Connections and
Harnesses; an exec
command's output is not scrubbed of what it inherited. Where a program must not
see a credential, scope the process that runs akm (a dedicated account, a clean
environment). See How akm runs a
harness.
Codex agent work no longer gets --sandbox workspace-write and Aider no longer
gets --no-auto-commits, so set the sandbox and auto-commit behaviour you want
in each program's own configuration.
Workflow output redacts only the values substituted from secrets/ refs, so
move any credential typed straight into an env file to secrets/ and reference
it there.
Plugins
| OpenCode | Package | Config key | Cache folder |
|---|---|---|---|
| 1 | akm-opencode |
"plugin" |
~/.cache/opencode/packages/akm-opencode@<tag>/ |
| 2 | akm-opencode-v2 (new) |
"plugins" |
~/.cache/opencode/npm/akm-opencode-v2@<tag>/<build>/ |
($XDG_CACHE_HOME moves both.) Install only the package for the OpenCode you
run. For OpenCode 2, run opencode plugin add akm-opencode-v2.
- Each plugin pins one exact
akm-cli. It runs that CLI in-process, soakm upgradenever moves the CLI past the pin, and with both plugins present it holds the CLI to the older pin. It never moves the CLI backwards. If it cannot read the pin it leaves the CLI alone and exits 1.akm healthwarns when a plugin's bundledakm-clidiffers from the running CLI. - OpenCode 1 caches the plugin spec it resolved, and never re-checks it. A
new plugin build is not picked up until its cache folder is cleared.
akm upgradedoes this for@latest(and@nextwith--next) when no OpenCode process is running: it moves the folder to the trash, then re-fetches (opencode debug config). OpenCode 2 has an updater:akm upgraderunsopencode plugin update akm-opencode-v2(with the spec your config names) even while OpenCode runs; the running service keeps the old build until it restarts. (opencode plugin listandcheckprint "No plugins found" until the service has loaded plugins after a restart, andplugin updateleaves the old build folders behind.) If your config pins another spec, such asakm-opencode@0.9.30,akm upgradeleaves it alone: change the spec, quit OpenCode, move that cache folder aside and start OpenCode again. - Questions and permission requests. Nobody can answer an akm run:
OpenCode's headless
run, which akm's own runtime and theopencodeharness both use, cancels every question and rejects every permission request that would ask, and the model carries on. akm changes no OpenCode permission default. See Configuration. - Claude Code and Codex plugins come from the
akm-pluginsmarketplace and are updated byakm upgrade. Use the 0.10 plugin set with 0.10 (it passes--detail agent; see itlackey/akm-plugins#133); the plugins require akm 0.10.261004 or newer. The marketplace's default branch is stable and itsnextbranch carries prereleases: add it asitlackey/akm-plugins@nextin Claude Code, orcodex plugin marketplace add itlackey/akm-plugins --ref nextin Codex.akm upgradeupdates whichever ref the marketplace follows and cannot switch it. - Other callers. Anything of yours that passes
--shape agent(benchmark runners, hooks) needs--detail agentand akm 0.10 together. akm-eval's retrieval, skillret and longmemeval benchmarks are the known ones (itlackey/akm-eval#33). - A signal to
akm agentnow ends the harness.akm agenton theopencode,claudeandcodexCLI harnesses runs the harness in its own process group, and SIGTERM or SIGINT to akm now takes it down too.
Version numbers
From 0.10 a release is numbered 0.10.YYMMNN: the UTC year and month, then the
release within that month (01 to 99), two digits each. The first release of
2026-10 is 0.10.261001. Every release takes the next number, whatever its
stage. A prerelease carries its stage only (0.10.261001-alpha, -beta,
-rc), and a build is not promoted through stages under one number. Prereleases
go to the npm next tag and stable releases to latest. Versions sort by
month and then number, so akm upgrade and semver ranges order them correctly.
The patch number no longer says how big a change is: read the CHANGELOG, which
still marks breaking changes. The 0.9 line keeps 0.9.N, and 0.11 restarts on
the same scheme.
If you installed a 0.10 daily alpha (0.10.26101001-alpha through
0.10.26101202-alpha, an 8-digit patch), akm upgrade will not offer the
monthly numbering: semver compares the patch numerically, so 0.10.261001 is
below every daily alpha. Install the first monthly release explicitly once, for
example npm install -g akm-cli@0.10.261001-beta; akm upgrade works normally
from there.
akm help migrate 0.10.261019 (or akm help migrate latest) prints the 0.10 release note.
The loader looks a note up by its exact file name, so akm help migrate latest
and a release number such as 0.10.261001 print the CHANGELOG section
only.
Verify the upgrade
akm --version # the 0.10.YYMMNN you meant to install
akm migrate status # status "current", ok true
akm health # exit 0 ok; 4 means a warning, read the check names
akm task doctor # scheduler backend, akm path, connections and harnesses, improve triage and autonomy
akm upgrade --check # per-plugin outcomes: current, pending, deferred, failed
akm improve --dry-run # the strategy resolves, plan.triage shows the drain
akm lint --type tasks # task files parse and pass the gates task sync runs
akm lint --type workflows # workflows parse; no .yml, route, outputs or isolation
akm search --type task # your tasks are indexed
Things to look for:
akm healthcheckconnections-and-harnesseslists a row for each connection and harness (its key held and reachable, or its binary found) and for each kind of work with the connection or harness and model it resolves to;akm infoprints the same rows without probing, andakm modelsshows each alias of the default connection. A connection that is not reachable is a warning (exit 4), not a failure.akm improve --dry-runfails (exit 78,UNKNOWN_IMPROVE_STRATEGY) when the configured strategy was removed.config.jsonno longer hasenginesordefaults,credentials.jsonholds any keys that were in it, andmodels.jsonis in<cache dir>/config-backups/.akm task doctorreportsimproveTriage(enabled, mode) andimproveAutonomywith the lanes theexperimental.improveAutonomygate holds off.akm healthcheckstate-db-migrationspasses with nothing applied.- After one scheduled
akm improve,akm logshowsstash_syncedevents withphase: "pre-run"on a git-backed bundle, andakm proposal listshows what the drain left for you.
Recovery
0.10 changes neither database schema, so a downgrade needs no data change. To
go back, stop AKM and any OpenCode process, install the earlier version
(akm-cli@0.9.31), and restore config.json from the backup that
akm migrate apply wrote under <cache dir>/config-backups/: 0.9 does not read
connections, harnesses or credentials.json, so a migrated config leaves it
with no engines (the backup holds your keys as they were, and models.json is
in the same directory). The assets whose engine: key apply rewrote are in the
backup directory the report names as assetEngineKeys.backupPath, under
<akm data dir>/backups/asset-engine-keys/. Finish or abandon workflow runs
started under 0.10 first; 0.9 refuses a plan a newer akm froze. Downgrade the
plugins with the CLI: a 0.9 CLI rejects --detail agent and a 0.10 CLI rejects
--shape agent.
For the CHANGELOG entries behind each item, see the
CHANGELOG sections
0.10.26101001 to 0.10.26101202 (the daily alphas) and the monthly releases after them. For the stability tier of each command, see
STABILITY.md. The
rules each improve process follows in 0.10 are in
the improvement loop and the
improve workflow reference.