Migration notes for akm v0.9.0

These notes apply to the 0.9.0 release candidates and final release. If you
were already running a 0.9.0 beta, align scripts, prompts, and stash layout
with the current command surface and verify every durable artifact before
normal use.

Heads-up: 0.9.x is a refactoring and clean-up release series. Patch
releases may include breaking changes (each called out in the CHANGELOG with
a migration note) until the remaining technical debt is paid off; the 0.10.x
series returns to bug fixes and tuning with breaking changes only in major
and minor releases. See STABILITY.md for the full policy.

Key operator-facing changes:

- **This release is the format-neutral bundle-adapter refactor — for
  recognition, indexing, presentation, and validation.** The flat asset-type
  registry is replaced by per-format adapters that decide what a file *is*
  (11 adapters behind a static registry), how it is indexed and shown, and
  how it validates. Refs move from the old `type:name` grammar to
  `[bundle//]conceptId` — a subdir-qualified concept id such as
  `skills/code-review`, `memories/vpn-note`, or `env/prod`, with an optional
  `bundle//` installation prefix and an optional `#fragment`. Durable state
  is stored fully-qualified; the short bundle-omitted form is input sugar
  (resolved against `defaultBundle`, then installation-priority order).
  `akm migrate apply` re-keys all durable state, folds the former
  `workflow.db` into `state.db` (three tracked databases: `state.db` /
  `index.db` / a separate `logs.db`, down from four — `logs.db` itself sits
  outside migration control entirely, see
  [the migration guide](../v0.8-to-v0.9.md#what-migration-control-does-not-cover)),
  and migrates config from the flat `stashDir` / `sources` / `installed` /
  `wikiName` keys to `bundles` / `defaultBundle`. In AKM stashes, `index.md` /
  `log.md` are reserved structural files — never indexed as items and never
  valid item-write targets. Other bundle formats use their adapter's own
  structural-file rules.
  **What this refactor does not (yet) touch: placement.**
  `adapter.placeNew()` is defined on the interface
  (`src/core/adapter/bundle-adapter.ts`) as an optional capability method and
  already implemented by 9 of the 11 built-in adapters (all but `okf` and
  `website-snapshot`), but nothing in the write
  path calls it in 0.9.0 — writes still route through AKM's native flat
  type→directory placement table (`stashDirFor` in
  `src/core/asset/asset-placement.ts`). That wiring is deferred to 0.10 as
  its own change (see
  [STABILITY.md](../../../STABILITY.md#on-the-horizon) and
  [D12](https://github.com/itlackey/akm/blob/main/docs/architecture/specs/0.9.0-decisions.md#d12--bundleadapterplacenew-stays-unwired-until-010));
  placement is already correct for every existing bundle today, this only
  changes which code computes it. `adapter.validate()`, by contrast, is a
  REQUIRED interface member and each adapter owns its own checks in 0.9.0:
  `akm lint` dispatches to the bundle's own adapter rather than
  re-implementing its rules. One caveat worth knowing: the proposal
  pre-commit path also runs `validate()`, but **advisory only** — it reports
  findings via a warning and does not reject the write. Making it blocking
  needs the adapter and legacy ref resolvers reconciled first, so a proposal
  that trips an adapter diagnostic still applies in 0.9.0.
  The adapter layer's `index()`/`affectedItems()` capability hooks also have
  no implementors yet — every 0.9.0 adapter is scanned through the shared
  core walk. None of this blocks normal use; it means "adapter-driven" in
  this release now covers reading and validating a bundle, but not yet
  writing to one.
- **Installed non-akm bundles reclassify on your next `akm index`.** The
  indexer now dispatches each installed bundle's *detected* adapter instead of
  recognizing everything with the akm-stash adapter. No action needed — the
  index is a regenerable cache — but searches/saved refs into those bundles may
  resolve to new ref spellings afterwards.
- **OKF and llm-wiki are both consumer/read-only in 0.9.0.** Arbitrary OKF
  `type` values remain searchable and showable with heading fragments, while
  the selected adapter decides which types receive specialized behavior.
  AKM-authored Markdown now emits its native `type` field and remains
  OKF-compatible; commands, scripts, workflows, tasks, environments, and
  secrets retain AKM's progressively enhanced native handling. Both the `okf`
  adapter and the `llm-wiki` adapter are consumer-only in 0.9.0 — AKM-native
  write commands (`akm remember`, `akm import`, proposal-accept, …) reject
  OKF **and llm-wiki** targets before modifying them. Author llm-wiki `pages/`
  content the way the Karpathy pattern always intended: your agent writes the
  files directly, and akm indexes and serves the result.
- The published npm package requires Node.js >= 22 as its cross-platform
  bootstrap. The `akm` launcher prefers a working Bun >= 1.0 and otherwise
  falls back to Node.js; `akm-migrate` follows the same model, with Bun optional
  and preferred.
  The standalone binaries are runtime-free.
- The legacy `vault` asset type and `akm vault ...` command family are gone.
  Use `env/<name>` for whole `.env` groups and `secrets/<name>` for a single
  sensitive value.
- `akm save` is replaced by `akm sync` for writable-stash persistence and
  pushes, and `akm events` is replaced by `akm log`.
- The entire `akm wiki ...` command family and the `wiki` asset type are gone.
  The Karpathy-style LLM wiki structure (`schema.md` + `pages/`) is now a
  first-class **bundle format** recognized and indexed directly by `akm
  index`/`akm search`/`akm show` — no dedicated verb surface needed. `akm
  lint` still runs, now dispatching to the adapter's own wiki-shaped checks
  through `validate()` (see above); it is a read surface in 0.9.0, not a
  write target — placement isn't wired to the adapter until 0.10.
- `akm-migrate storage` performs the non-destructive
  `vaults/` -> `env/` copy for older stashes. Run it before indexing if you are
  upgrading from a stash that still stores `.env` files only under `vaults/`.
- Proposal workflow is fully consolidated around `akm improve`, `akm proposal new`,
  and `akm proposal ...`. Update any old `akm reflect`, `akm distill`,
  `akm accept`, `akm reject`, or `akm proposals` usage.
- LLM-backed sustaining work is opt-in in the shipped presets: improve-stage
  extract is off in `default` and `frequent`, and `proactiveMaintenance` is off
  in `default` and `reflect-distill`. The dedicated `proactive-maintenance`
  strategy remains enabled as an explicit opt-in. Presets that omit these
  fields inherit the `default` off values, while an explicit user
  `enabled: true` override still wins.
- Config, `state.db`, and `workflow.db` are now classified independently by the
  explicit `akm migrate` coordinator. Normal commands refuse old, future, or
  divergent durable schemas instead of attempting migration as a side effect.
- **`akm-migrate` derives the 0.9 config from your 0.8 keys** instead of
  demanding a hand-authored one: the first `apply` with no `--config` writes a
  validated starter config under the backup root and stops; a second `apply`
  performs the cutover. Engine settings are never guessed — they are reported
  in `droppedKeys` for you to re-add. Fresh 0.8 installs (whose configs carry
  no `configVersion` key) now classify as `old` instead of being blocked, and
  `migrate` reports `not-applicable` (exit 0) when there is nothing to migrate.
- **The experimental `akm workflow brief` / `akm workflow report`
  external-driver protocol is removed.** `akm workflow run` is the single
  execution surface. A legacy `experimental.workflowEngine` config key is
  accepted and ignored; scripts calling `brief`/`report` must move to `run`.
- **Engine-less installs fall back to `opencode-sdk`** for `workflow run`,
  prompt tasks, `akm agent`, `propose`, and `improve` reflect — when the
  `opencode` binary is on PATH, akm synthesizes a config-free engine that
  resolves provider, model, and auth from opencode's own configuration
  instead of failing closed with exit 78. The fallback is always announced
  (result `warnings`, task run log, or stderr). An operator-configured
  engine always wins.
- **RSS, Bluesky, and X URLs are recognized by `akm bundle add`** and
  snapshotted as knowledge assets instead of being crawled as ordinary web
  pages. X needs `X_BEARER_TOKEN` (or `X_RSS_TEMPLATE`); store it as an akm
  secret and inject it per-invocation with `akm secret run`. Website crawls
  now respect `robots.txt` by default (`"respectRobots": false` opts out),
  have a hard `crawlTimeoutMs` cap, and extract the page's main content —
  existing website snapshots will get shorter and cleaner on their next
  refresh.

Primary public command family for 0.9.0:

- `akm improve <ref> [--task "..."]`
- `akm proposal new <type> <name> (--task "..." | --file <path>)`
- `akm proposal list`
- `akm proposal show <id>`
- `akm proposal diff <id>`
- `akm proposal accept <id>`
- `akm proposal reject <id> --reason "..."`

## Release validation

> Unit/integration test counts below are point-in-time snapshots from the
> validation passes named next to each figure, not a promise about the count
> on any later commit — the suite keeps growing after each pass. Run
> `bun run check` yourself for the current count; do not treat a number below
> as still accurate.

Release validation was repeated on 2026-07-31. An isolated manual pass covered
114 first-run, CLI, indexing, search/show, output-format, strict-flag,
tools-only agent classification, multi-bundle write/lint, workflow, task,
llm-wiki, env/secret, feedback/log, config/migration, health, upgrade, and
registry checks with no failures. `bun run release:check`, as run on
2026-07-31, verified the packed npm installation, Node fallback and Bun
launcher paths, migration and task execution from published 0.8.14, the Linux
standalone scheduler artifact, its then-current unit/integration test counts,
and all seven Docker install targets. The gated semantic-search suite passed
9 tests; Node 24 passed all 9 fallback smoke steps and 25 compatibility tests.

The post-release checklist audit added a separate 125-check deterministic pass
for cross-bundle identity, write fidelity, output destinations, lint/task
behavior, env secrecy, durable log cursors, workflow transitions, proposal
dry-runs, setup recovery, fresh health initialization, and source-install
safety. It passed 125/125 on Linux. The branch as of that same pass also
passed `bun run check` and `bun run build`.

A container-isolated follow-up passed 188 destructive crash/recovery checks,
including real `SIGKILL` windows across proposal, workflow, and lock journals,
plus deterministic interruption replay across phase-free migration sentinels.
The container also passed `release:check --skip-docker`, the seven-image
Docker install matrix, 9 semantic-search tests, all 9 Node 22 smoke steps, all
25 Node compatibility tests, and the offline full gate. This pass exposed and
fixed host-scheduler and co-located Node/Bun assumptions in three tests; no
production behavior changed.

Live credential-backed agent/LLM calls and native macOS/Windows execution were
not run from this Linux host. Their deterministic paths remain covered by the
full unit/integration suite; release artifacts still require their normal
platform CI/release checks.

Required upgrade checks:

- Before crossing from 0.8 to 0.9, create an independent filesystem backup and
  prepare a valid 0.9 config. The installed 0.8 binary does not know the 0.9
  migration protocol: install or stage the 0.9 binary, then run
  `akm migrate apply --config <prepared-0.9-config>` before any normal command.
- On an existing 0.9 installation, run `akm migrate status`. If it reports
  `ready`, run `akm migrate apply`; an already-current active config is used as
  the target.
- Do not continue when status reports `blocked`. Preserve the reported backup
  run and resolve the named artifact or active-operation error first.
- Restore is explicit and destructive: `akm-migrate restore --for 0.9.0 --run
  <backup-run-id> --confirm`. It creates and verifies a rescue backup before
  replacing current artifacts.
- Run `akm help migrate 0.9.0` for the storage and command-surface checklist.
- Run `akm-migrate storage --yes` once if the stash ever used `vaults/`.
- Rebuild derived search data with `akm index` only after migration status is
  `current`; indexing does not migrate config or durable schemas.
- Review agent instructions and docs for old `vault`, `reflect`, and `distill`
  examples.
- Review scheduled improve invocations if they relied on inherited extract or
  proactive-maintenance enablement. Standalone extraction remains available
  as `akm proposal extract`, but every invocation must select
  `--type <harness>` or `--auto`; a bare invocation is invalid. Update any
  installed extract task to `akm proposal extract --auto` for all-harness
  discovery. The bundled template remains an unselected opt-in and now uses
  that valid command.

## 0.9.0 command-surface overhaul (hard break, no aliases)

The 0.9.0 CLI surface was restructured in full. Known retired spellings fail
with `UNKNOWN_COMMAND` and a replacement hint. Update assets,
scripts, task YAML, prompts, and agent instructions (CLAUDE.md quick
references) using this table, then run `akm task sync --rebind` once so
installed schedules re-emit the new spellings. `akm hints` prints the complete
agent guide (`--detail brief` selects the compact version), while `akm help
agents` is short by default; the root `akm --help` groups the surviving surface
into AGENT LOOP / ASSETS / AUTOMATION / SYSTEM sections, including `migrate`
under SYSTEM. For migration usage details rather than the bare `--help`
listing, see [the migration guide](../v0.8-to-v0.9.md).

Command renames and moves:

| Old spelling | 0.9.0 replacement |
| --- | --- |
| `akm init` | `akm bundle create` |
| `akm add <source>` | `akm bundle add <source>` |
| `akm list` | `akm bundle list` |
| `akm remove <source>` | `akm bundle remove <source>` |
| `akm update` | `akm bundle update` (self-update stays `akm upgrade`) |
| `akm tasks <sub>` | `akm task add\|run\|sync\|doctor\|history` (singular; `list`, `show`, `remove`, `init`, `enable`, and `disable` are removed) |
| `akm extract` | `akm proposal extract` |
| `akm propose` | `akm proposal new` |
| `akm log list` | `akm log` (now a single command) |
| `akm registry search <q>` | `akm search <q> --from registry` |
| `akm workflow template` | `akm workflow create --print` |
| `akm workflow validate` | `akm lint --type workflows` (add `--fail-on-flagged` to keep CI-gate exit semantics) |
| `akm config show` | `akm config list` |

Removed outright (with the supported replacement procedure):

| Removed | Use instead |
| --- | --- |
| `akm history` | `akm log --ref <ref>` |
| `akm graph` (all subcommands) | counts in `akm health`; refresh via `akm improve --strategy graph-refresh` |
| `akm lessons coverage` / `strength` | lesson strength is indexed; `akm search --type lesson` |
| `akm mv` | move the file, then `akm index` + `akm lint`; optional `bun scripts/rekey-asset-ref.ts <old-ref> <new-ref>` (source checkout) carries ranking signal |
| `akm log tail` | poll `akm log --since @offset:<id>` (durable cursor) |
| `akm workflow watch` | `akm log --run <run-id>` |
| `akm env set` / `env unset` | edit the `.env` file directly; akm loads it as-is |
| `akm config validate` | config is validated on every load |
| `akm task enable` / `disable` | edit `enabled:` in the task YAML, then `akm task sync` |
| `akm task init` | `akm setup` seeds the default schedules |
| `akm improve canary` | `bun scripts/refresh-canary-set.ts [--refresh]` (from a source checkout — helper scripts are not shipped in the npm package) |
| `akm registry build-index` | `bun scripts/build-registry-index.ts` (maintainer tooling) |
| `akm index --background` | removed (the flag never backgrounded; use `--quiet`) |
| `akm setup --detect-only` / `--reset-recommended` | removed; environment detection runs inside `akm setup`, and `akm info` reports the *configured* capabilities |
| `extract --watch` / `--debounce-ms` | schedule `akm proposal extract --auto` as a task |

Flag and value renames:

| Old | New |
| --- | --- |
| `search`/`curate` `--source stash\|registry\|both` | `--from local\|registry\|all` |
| `remember`/`clone`/`improve`/the `task` group `--target <bundle>` | `--bundle <bundle>` (`import`, `proposal accept`, `env create`, `env remove`, `secret set` keep `--target`) |

Environment and JSON-payload renames ("stash" is retired; the noun is
"bundle" everywhere):

| Old | New |
| --- | --- |
| `AKM_STASH_DIR` | `AKM_BUNDLE_DIR` |
| `akm info` field `stashDir` | `bundleDir` |
| `akm config path --all` key `stash` | `bundle` |
| `bundle create` result `defaultStashUpdated` / `previousStashDir` | `defaultBundleUpdated` / `previousBundleDir` |

Full changelog: https://github.com/itlackey/akm/blob/main/CHANGELOG.md
