Migration notes for akm v0.9.2
Exact-prefix additive state.db upgrades remain automatic. The released
historical migration 018 is classified separately because it removes retired
dead-lane state: ordinary commands stop before it. Run akm upgrade --force;
after executable replacement AKM writes and verifies a sibling
state.db.pre-018-drop-dead-lane-schema.<UTC-digits>.<UUID>.bak snapshot, then
applies the immutable migration. The exact ledger recheck, snapshot, and 018
transaction share one SQLite writer-exclusion window. There is no general
database migration command.
A newly created state.db still bootstraps automatically, but only when this
invocation atomically created and retained ownership of that exact inode. An
already-existing file with no applied migration IDs is not fresh, whether its
schema_migrations table is absent or empty: ordinary commands reject it
without writing. akm upgrade --force first verifies a
descriptor-bound state.db.pre-001-initial-schema.<UTC-digits>.<UUID>.bak
snapshot. The same writer-exclusion transaction then initializes the ledger and
applies migrations 001–002, so an old-schema writer cannot commit data between
the recovery snapshot and migration 002's rebuild. Snapshot readers and targets
are bound to their held inodes, not swappable pathnames. A failed snapshot path
is reported and never removed by cleanup code.
Task sources now use task source v4. Normal execution rejects task-v3 and
task-v2 files with TASK_SCHEMA_VERSION_UNSUPPORTED; preview the
repository-wide conversion with akm migrate apply --dry-run, review every
changed, skipped, or blocked result, then run akm migrate apply — it
now runs both the v2→v3 and v3→v4 generations in one pass. The migrator
validates each replacement before it backs up and replaces a source, and
ambiguous cases (an argv array with no safe shell equivalent, a with:
block with no v4 equivalent, an ambiguous scheduling source, and similar)
remain blocked for manual review. Task source v4 adds typed inputs: with
defaults, a single bounded output: schema, optional schedule:, and
per-schedule-binding enablement. See
Task sources and
The migration procedure.
Task run history's target.kind result field also changed vocabulary:
"prompt" is now "command" (an agent/LLM dispatch), and the old shared
"command" split into "shell" and "script". akm task history reads
both generations of existing rows correctly, forever, keyed on a per-row
targetVocab marker — but a pre-0.9.2 akm's decoder does not recognize
that marker and throws reading a row this release (or later) wrote, so
upgrade once and don't downgrade below 0.9.2 for a given state.db. See
Task history result vocabulary.
Workflows now accept peer Markdown (.md) and GitHub-shaped YAML (.yml)
sources through source IR v1. Runs freeze durable plan irVersion 5, the
only executable plan format. Pre-irVersion-5 stored plans cannot resume,
next, complete, or run — status, list, and abandon keep working, and
akm workflow abandon <id> followed by a fresh akm workflow run <ref>
recovers a blocked run; no data is lost. A resume does not re-read the
authored workflow, configuration, or asset index. Scheduled fires are new
starts, so they read the current source and create a fresh freeze. .yml
also rejects inherit_env; use exact named environment bindings and
pass_env names instead. See
Workflow cutover.
A workflow step can now compose another workflow as a child — directly
(uses: workflows/<ref>) or through a task whose own target is a workflow
— bounded by composition depth, cycle detection, and aggregate embedded-plan
size, all checked at freeze before the parent run is published. Running the
step drives the child to completion inline, in the parent's own process:
cancellation propagates because it is the same process, the child is
independently resumable, and akm workflow status on the parent renders a
children: tree. A workflow may also declare outputs: — a run-level
export resolved once from persisted step evidence at completion, which a
composing parent step promotes as its own output. See
Child workflows and
Workflow outputs.
A workflow step's with: on a uses: tasks/<ref> target now binds the
task's declared inputs: — literal values or {from: "steps.<id>.output…"}
references resolved just before dispatch (the reference grammar also
accepts {from: "params.<name>"}, but a composing step's own document can
never declare params:, so that form is not reachable in this release) —
instead of being silently dropped. A with: on a task with no inputs:,
or on a commands//scripts/ target (never binding surfaces), is now
rejected at freeze rather than discarded. See
with: on a task-composed step now binds — or rejects.
Three recognized-but-limited constructs are removed outright in 0.9.2: the
GitHub Action uses: locator (owner/repo[/path]@ref) is no longer
recognized anywhere — it was always rejected before dispatch in every prior
release, so this deletes the recognition, not a working capability;
multi-job GitHub-shaped YAML is rejected at the source adapter instead of
parsing clean and being refused later in two different places — split a
multi-job document into single-job workflows composed with a child-workflow
step; and the second task scheduling syntax (akm.schedule / a task's
top-level on:) is gone along with task v3, leaving task source v4's
optional top-level schedule: as the one canonical form. See
GitHub Action locators are no longer recognized anywhere
and
Multi-job YAML is rejected at the adapter boundary.
Two new read-only introspection verbs: akm workflow plan <ref>
(secret-free by construction) compiles, resolves, and freezes a workflow
without publishing a run, printing the canonical step graph, target/child
expansion, and input bindings; akm task explain <ref> prints a task's
resolved target, declared and supplied inputs: (secret-shaped values
redacted on a best-effort heuristic basis), and schedule bindings — its
default and --format json output are the same raw JSON. See
New commands.
Task-source, workflow-source, and composition failures now report
phase-specific UsageError codes (TASK_SOURCE_INVALID,
TASK_SCHEMA_VERSION_UNSUPPORTED, TARGET_REF_INVALID,
WORKFLOW_SOURCE_INVALID, COMPOSITION_INVALID, INPUT_BINDING_INVALID,
TASK_TARGET_UNSUPPORTED, WORKFLOW_OUTPUT_INVALID,
WORKFLOW_IR_VERSION_UNSUPPORTED) instead of the generic
INVALID_FLAG_VALUE; exit codes are unchanged. See
Diagnostics.
akm command run --dry-run performs authorization and adapter lowering but
does not dispatch or materialize credentials. It writes no authored source or
durable state and records no usage, events, or accounting. Safe provenance and
lowering notices omit resolved, prompt, command, environment, and credential
values. --verbose writes those safe diagnostics to stderr without changing
the command result on stdout. akm health adds offline
selected-model-aliases and configured-engines advisories; their evidence
does not disclose endpoint values, exact model IDs, credential values, or
provider output.
improve.strategies.<name>.processes.triage.judgment now accepts a boolean or
an object. Set judgment: false to disable the tier explicitly. A newly
authored object defaults to enabled, while unknown object keys are rejected.
The standalone proposal command's --judgment option remains an explicit
invocation override and does not rewrite strategy configuration.
See the long-form guide for complete task examples, workflow boundaries, compatibility details, and upgrade checks.