akm-cli 0.9.14 → 0.9.15-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/CHANGELOG.md +397 -0
  2. package/STABILITY.md +6 -3
  3. package/dist/assets/prompts/reflect-feedback-framing.md +1 -0
  4. package/dist/assets/prompts/reflect-llm-framed-contract.md +2 -0
  5. package/dist/assets/prompts/reflect-llm-schema-contract.md +2 -0
  6. package/dist/assets/tasks/core/improve.yml +1 -1
  7. package/dist/assets/tasks/core/index-refresh.yml +1 -1
  8. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +1 -1
  9. package/dist/assets/tasks/improve/akm-improve-catchup.yml +1 -1
  10. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +1 -1
  11. package/dist/assets/tasks/improve/akm-improve-frequent.yml +1 -1
  12. package/dist/assets/tasks/improve/akm-improve-nightly.yml +1 -1
  13. package/dist/cli/retired-commands.js +0 -1
  14. package/dist/cli/shared.js +9 -0
  15. package/dist/cli/unknown-flags.js +1 -0
  16. package/dist/cli.js +3 -2
  17. package/dist/commands/config-cli.js +85 -3
  18. package/dist/commands/env/env-cli.js +1 -42
  19. package/dist/commands/env/env.js +1 -1
  20. package/dist/commands/env/secret-cli.js +1 -2
  21. package/dist/commands/health/checks.js +357 -63
  22. package/dist/commands/health/engine-usage.js +45 -0
  23. package/dist/commands/health/improve-metrics.js +18 -0
  24. package/dist/commands/health/llm-usage.js +41 -1
  25. package/dist/commands/health/plugin-staleness.js +7 -3
  26. package/dist/commands/health/version-drift.js +93 -0
  27. package/dist/commands/health/windows.js +3 -1
  28. package/dist/commands/health.js +44 -9
  29. package/dist/commands/improve/consolidate/chunking.js +4 -2
  30. package/dist/commands/improve/improve-cli.js +99 -5
  31. package/dist/commands/improve/improve-report.js +154 -0
  32. package/dist/commands/improve/improve-result-file.js +45 -33
  33. package/dist/commands/improve/improve-strategies.js +133 -3
  34. package/dist/commands/improve/improve-usage-report.js +182 -0
  35. package/dist/commands/improve/improve.js +40 -3
  36. package/dist/commands/improve/locks.js +27 -78
  37. package/dist/commands/improve/planner.js +1 -0
  38. package/dist/commands/improve/preparation.js +9 -1
  39. package/dist/commands/improve/reflect.js +44 -4
  40. package/dist/commands/models-cli.js +50 -1
  41. package/dist/commands/proposal/repository.js +8 -3
  42. package/dist/commands/proposal/validators/proposal-quality-validators.js +41 -6
  43. package/dist/commands/proposal/validators/proposal-validators.js +24 -0
  44. package/dist/commands/read/search-cli.js +38 -2
  45. package/dist/commands/read/show.js +103 -4
  46. package/dist/commands/sources/info.js +5 -1
  47. package/dist/commands/sources/self-update.js +2 -2
  48. package/dist/commands/sources/stash-cli.js +31 -0
  49. package/dist/commands/tasks/tasks-cli.js +49 -2
  50. package/dist/commands/workflow-cli.js +86 -12
  51. package/dist/core/asset/markdown-fragments.js +35 -0
  52. package/dist/core/config/config-schema.js +14 -0
  53. package/dist/core/config/config.js +302 -24
  54. package/dist/core/env-secret-ref.js +58 -5
  55. package/dist/core/errors.js +30 -0
  56. package/dist/core/improve-result.js +51 -0
  57. package/dist/core/loopback.js +17 -0
  58. package/dist/core/paths.js +11 -0
  59. package/dist/core/run-lock.js +96 -0
  60. package/dist/core/sensitive-marker-path.js +19 -0
  61. package/dist/core/state-db.js +74 -14
  62. package/dist/indexer/index-rebuild-lock.js +73 -0
  63. package/dist/indexer/index-writer-lock.js +40 -1
  64. package/dist/indexer/index-written-assets.js +21 -1
  65. package/dist/indexer/indexer.js +18 -17
  66. package/dist/indexer/materialize-embeddings.js +282 -32
  67. package/dist/indexer/search/db-search.js +49 -2
  68. package/dist/integrations/agent/engine-resolution.js +96 -6
  69. package/dist/integrations/agent/execution-definitions.js +6 -15
  70. package/dist/integrations/agent/execution-lowering.js +6 -1
  71. package/dist/integrations/agent/execution-preparation.js +1 -1
  72. package/dist/integrations/agent/model-map.js +123 -20
  73. package/dist/integrations/agent/prompts.js +40 -8
  74. package/dist/integrations/agent/runner-dispatch.js +9 -3
  75. package/dist/integrations/agent/runner.js +2 -0
  76. package/dist/llm/client.js +8 -3
  77. package/dist/llm/embedder.js +20 -8
  78. package/dist/llm/embedders/local.js +10 -2
  79. package/dist/llm/embedders/remote.js +188 -21
  80. package/dist/output/shapes/helpers.js +38 -2
  81. package/dist/output/shapes/models-list.js +16 -0
  82. package/dist/output/shapes/passthrough.js +2 -0
  83. package/dist/output/shapes.js +4 -0
  84. package/dist/output/text/command-format.js +29 -0
  85. package/dist/output/text/helpers.js +1 -1
  86. package/dist/output/text/improve-report.js +27 -0
  87. package/dist/{commands/env/marker-path.js → output/text/models.js} +4 -3
  88. package/dist/output/text/show-format.js +4 -0
  89. package/dist/output/text.js +4 -0
  90. package/dist/scripts/akm-migrate-node.js +24798 -21732
  91. package/dist/scripts/akm-migrate.js +23408 -20343
  92. package/dist/storage/repositories/improve-runs-repository.js +34 -0
  93. package/dist/storage/repositories/index-fts-repository.js +49 -6
  94. package/dist/storage/repositories/index-vec-repository.js +30 -0
  95. package/dist/storage/repositories/workflow-runs-repository.js +55 -18
  96. package/dist/tasks/backends/cron.js +14 -7
  97. package/dist/tasks/run/run-workflow-task.js +16 -0
  98. package/dist/workflows/exec/child-workflow.js +2 -2
  99. package/dist/workflows/exec/dispatch-redaction.js +21 -9
  100. package/dist/workflows/exec/run-workflow.js +6 -5
  101. package/dist/workflows/runtime/runs.js +33 -5
  102. package/docs/migration/release-notes/0.9.15.md +52 -0
  103. package/docs/migration/release-notes/README.md +4 -0
  104. package/docs/reference/cli.md +245 -29
  105. package/docs/reference/configuration.md +180 -19
  106. package/docs/reference/data-and-telemetry.md +8 -0
  107. package/docs/reference/tasks.md +16 -1
  108. package/docs/reference/workflow-schema.md +5 -1
  109. package/package.json +1 -1
  110. package/schemas/akm-config.json +8 -0
@@ -117,6 +117,7 @@ Every command exits with one of the following codes:
117
117
  | 2 | Usage / bad input | `UsageError` |
118
118
  | 4 | Health warning (`akm health` only) | — |
119
119
  | 70 | Internal / unclassified error | unexpected throw |
120
+ | 75 | Transient — retry shortly (sysexits `EX_TEMPFAIL`); another akm process holds a lock or is writing `state.db` right now, not a bad command line | `TransientError` |
120
121
  | 78 | Configuration error | `ConfigError` |
121
122
 
122
123
  Failures classified by akm emit a JSON error envelope on **stderr** before
@@ -195,7 +196,7 @@ The setup wizard configures AKM in two steps:
195
196
 
196
197
  **Step 1 — Small model connection** (for background processing)
197
198
  Configures the OpenAI-compatible endpoint and model used for `akm index`
198
- metadata enhancement, `akm remember --enrich`, and `akm curate --rerank`. Supports Ollama,
199
+ metadata enhancement and `akm remember --enrich`. Supports Ollama,
199
200
  OpenAI, LM Studio, or any custom endpoint. Skipping disables enrichment features.
200
201
 
201
202
  **Step 2 — Agent connection** (for agentic commands)
@@ -222,6 +223,8 @@ akm index --full # Full rebuild
222
223
  akm index --verbose # Print phase progress to stderr
223
224
  akm index --clean # Normal index + remove stale entries from the DB
224
225
  akm index --clean --dry-run # Report stale entries without deleting
226
+ akm index --reembed # Force re-embedding of every entry
227
+ akm index --skip-if-locked # for scheduled/opportunistic runs: skip (exit 0) if a run is already in progress
225
228
  ```
226
229
 
227
230
  Returns stats: `totalEntries`, `generatedMetadata`, `directoriesScanned`,
@@ -239,6 +242,30 @@ Use `--clean` to resolve the edge case where a deleted file in an unchanged
239
242
  directory lingers in the index across incremental runs. With `--dry-run`, reports
240
243
  which entries would be removed without modifying the database.
241
244
 
245
+ **`--reembed` flag:** Forces a full purge and re-embed of every entry,
246
+ independent of the embedding-model-rename compatibility check described
247
+ below. Ordinary indexing already tells a config-only rename of
248
+ `embedding.model` (e.g. a gateway that changes how it names the same model)
249
+ apart from a genuine model change, and keeps the stored vectors when they
250
+ are still compatible; `--reembed` skips that check and forces a rebuild
251
+ regardless of what it would have decided.
252
+
253
+ **`--skip-if-locked` flag:** Every explicit `akm index` run acquires an
254
+ opt-in, PID-liveness-only rebuild lock and releases it on exit — this is
255
+ advisory, never the blocking lock #872 removed (see
256
+ [Locks](https://github.com/itlackey/akm/blob/main/docs/architecture/internals/indexing.md#locks)). A human-typed
257
+ `akm index` with no flag is never gated by it: if another run already holds
258
+ the lock, it warns and proceeds anyway, contending with the existing run.
259
+ `--skip-if-locked` changes that only for the invocation that passes it: if
260
+ the lock is already held by a live process, it skips gracefully (exit 0,
261
+ `{ ok: true, skipped: { reason: "lock-held", pid, startedAt } }`) instead of
262
+ contending. `akm index` and `akm curate` are both safe to call frequently —
263
+ `curate` never blocks on a rebuild in progress ([read-path indexing stays
264
+ non-blocking](#curate)) — but a hook, cron job, or scheduled task that
265
+ invokes `akm index` directly should pass `--skip-if-locked` so it steps
266
+ aside instead of piling up behind a longer rebuild (the shipped
267
+ `index-refresh` task does this).
268
+
242
269
  `akm index` always rebuilds the search index and keeps metadata in the index.
243
270
  When a selected named LLM engine (`defaults.llmEngine` or an indexing-pass
244
271
  override) is configured and the per-pass gate allows it, metadata
@@ -261,6 +288,10 @@ Returns a JSON object with:
261
288
  | `version` | Current akm version |
262
289
  | `bundleDir` | Primary bundle directory — same resolution `akm bundle list` uses |
263
290
  | `defaultBundle` | Name of the primary bundle from config, or `null` when none is configured |
291
+ | `dataDir` | Resolved data directory (`getDataDir()`) |
292
+ | `configDir` | Resolved config directory (`getConfigDir()`) |
293
+ | `cacheDir` | Resolved cache directory (`getCacheDir()`) |
294
+ | `stateDir` | Resolved state directory (`getStateDir()`) |
264
295
  | `assetTypes` | List of recognized asset types |
265
296
  | `searchModes` | Active search modes (`fts`, optionally `semantic` and `hybrid`) |
266
297
  | `semanticSearch` | Semantic search status: `mode`, `status`, and optional `reason`/`message` |
@@ -277,6 +308,10 @@ Returns a JSON object with:
277
308
 
278
309
  Use `akm info` to verify that semantic search is working after setup.
279
310
 
311
+ Scripts that need akm's resolved paths (for example a health check that
312
+ differs between a host install and a container) can read them with
313
+ `akm info --format json | jq -r .dataDir` instead of hardcoding a path.
314
+
280
315
  ### health
281
316
 
282
317
  Check akm runtime health, durable state, and recent improve-loop telemetry.
@@ -298,14 +333,15 @@ akm health --report --window-compare 7d --format html
298
333
  | `--window-compare` | Compare the current window against the prior window of the same duration (e.g. `24h`, `7d`). With `--report`, overrides the default trend window. |
299
334
  | `--group-by` | Group rows by `run` (one row per `improve_runs` entry). Omit for the default summary. |
300
335
  | `--windows` | Explicit comparison window(s) as `name=...,since=ISO,until=ISO` (repeatable, up to 4). Mutually exclusive with `--window-compare`. |
301
- | `--no-probe` | Skip the `default-llm-engine` / `configured-engines` reachability probes (for an offline or air-gapped host). |
336
+ | `--no-probe` | Skip the `default-llm-engine` / `configured-engines` reachability probes and the `cli-version` update check (for an offline or air-gapped host). |
302
337
 
303
338
  The command reads `state.db`, verifies that the required tables exist, performs a
304
339
  write-read probe against the events stream, inspects `task_history`, checks the
305
340
  default agent engine, and summarizes recent `improve_*` events. Unless
306
341
  `--no-probe` is given, it also sends a bounded (3s timeout) reachability probe
307
342
  to the `default-llm-engine` and every `configured-engines` LLM connection (and
308
- an SDK engine's LLM fallback), one probe per distinct endpoint.
343
+ an SDK engine's LLM fallback), one probe per distinct endpoint, and checks the
344
+ installed akm-cli version against the latest GitHub release (`cli-version`).
309
345
 
310
346
  Primary result fields:
311
347
 
@@ -313,7 +349,7 @@ Primary result fields:
313
349
  | --- | --- |
314
350
  | `status` | Overall health verdict: `pass`, `warn`, or `fail` |
315
351
  | `hardChecks` | Deterministic checks such as `state-db-schema`, `state-db-round-trip`, `state-db-migrations`, `task-log-backing`, `active-runs`, `default-engine`, `model-map-files`, `default-llm-engine`, `configured-engines`, and `active-improve-strategy` |
316
- | `advisories` | Non-fatal warnings including `semantic-search-runtime` and `session-extraction` (akmExtract pipeline health) |
352
+ | `advisories` | Non-fatal warnings including `semantic-search-runtime`, `session-extraction` (akmExtract pipeline health), `cli-version` (installed vs latest release), `thinking-control` (an `enableThinking: false` engine whose recorded usage still shows reasoning tokens), and `engine-last-used` (an engine bound to an enabled improve process with no recorded use in 30 days) |
317
353
  | `metrics` | Aggregate task/runtime metrics: `taskFailRate`, `agentFailureRate`, `stuckActiveRuns`, `logBackingRate`, `probeRoundTripMs` |
318
354
  | `improve` | Recent improve-loop counts derived from `improve_invoked`, `improve_skipped`, and `improve_completed` events |
319
355
 
@@ -333,10 +369,25 @@ holds a pending historical-destructive migration and something other than
333
369
  `default-llm-engine` and `configured-engines` probe reachability (not just
334
370
  configuration) for a `kind: "llm"` engine — an unreachable endpoint is a hard
335
371
  `fail` for `default-llm-engine` and a `warn` for any other engine. `--no-probe`
336
- skips this. `active-improve-strategy` names the resolved engine per process
372
+ skips this. When a required credential is missing from the shell but an
373
+ `env/` asset defines the same variable name, the warn names that asset's ref
374
+ (never the variable name) and points at `akm env run <ref> -- ...`.
375
+ `active-improve-strategy` names the resolved engine per process
337
376
  in its evidence and message, so a strategy-level `engine` pin that shadows
338
377
  `defaults.llmEngine` is visible without config archaeology.
339
378
 
379
+ `cli-version` compares the installed akm-cli version against the latest
380
+ GitHub release — the same source `akm upgrade` trusts — and `warn`s with the
381
+ upgrade command when a newer release exists. `--no-probe`, offline, or a
382
+ rate-limited request all degrade it to `unknown`, never a false `warn`.
383
+
384
+ `engine-last-used` checks, for every engine bound to an enabled process in
385
+ the active improve strategy, whether it has a recorded `llm_usage` call in
386
+ the last 30 days (independent of `--since`). It `warn`s naming the idle
387
+ engine and its bound process, and stays `unknown` — not a noisy `warn` —
388
+ until at least one improve run has been recorded (started) in that window,
389
+ so a fresh install is quiet.
390
+
340
391
  The `session-extraction` advisory is derived from the `extract_sessions_seen`
341
392
  ledger for the last 7 days — not `improve_runs`, which the hook-driven `akm
342
393
  proposal extract --session-id ...` invocation never writes. It reports
@@ -439,6 +490,12 @@ availability:
439
490
  - **`ref`** -- The asset handle to pass to `akm show` (for example
440
491
  `team//scripts/deploy.sh`); present at `brief`, `full`, and `agent` for local
441
492
  hits
493
+ - **fragment provenance** -- when `ref` selects an indexed Markdown fragment,
494
+ `selectedRef` and `parentRef` distinguish the ranked evidence from its parent;
495
+ one-based `fragmentOrdinal`, `fragmentCount`, source-line bounds, neighbor
496
+ refs, and separate fragment/parent size estimates are available without
497
+ changing ranking. `estimatedTokens` describes the fragment for a
498
+ fragment-qualified hit; `parentEstimatedTokens` describes the whole asset.
442
499
  - **`name`** -- The asset's filename or identifier; present at all levels
443
500
  - **`origin`** -- The source bundle (e.g. `npm:@scope/pkg`), present only for
444
501
  managed source assets; surfaced at `full` only
@@ -482,9 +539,9 @@ ranking.
482
539
 
483
540
  ### curate
484
541
 
485
- Pick the assets worth loading for a task. Unlike `akm search`, curate reranks by
486
- intent, attaches a preview and run details per hit, adds related support refs,
487
- and summarizes the set — the usual starting point for an agent.
542
+ Pick the assets worth loading for a task. Unlike `akm search`, curate attaches
543
+ a preview and run details per hit, adds related support refs, and summarizes
544
+ the set — the usual starting point for an agent.
488
545
 
489
546
  ```sh
490
547
  akm curate "plan a release"
@@ -515,6 +572,10 @@ only for read-only items. Their `followUp` remains `akm show <ref>` rather than
515
572
  being replaced by clone guidance.
516
573
  Use `--type workflow` when you want curated step-by-step procedures instead of
517
574
  individual scripts, skills, or docs.
575
+ `akm curate` is safe to call frequently, including from a hook that fires on
576
+ every prompt: it only ever reads the index as it currently stands (the same
577
+ non-blocking `ensureIndex()` path `search` uses) and never waits on or
578
+ contends with a full `akm index` rebuild in progress.
518
579
  Use `--no-track-usage` when this inspection must not update local usage or
519
580
  ranking signals.
520
581
 
@@ -535,6 +596,7 @@ akm show commands/release
535
596
  akm show workflows/ship-release
536
597
  akm show knowledge/guide # the whole document
537
598
  akm show knowledge/guide#authentication # just that section
599
+ akm show '<search-result-ref>' --context lead --max-tokens 800
538
600
  akm show knowledge/guide#nope # lists the available fragment slugs
539
601
 
540
602
  # Bundle .meta/ orientation docs — direct-read, not indexed:
@@ -548,6 +610,14 @@ akm show memories/retro --filter user=alice
548
610
  akm show memories/retro --filter user=alice --filter agent=claude
549
611
  ```
550
612
 
613
+ | Flag | Values | Default | Description |
614
+ | --- | --- | --- | --- |
615
+ | `--context` | `exact`, `lead` | `exact` | Fragment presentation. `exact` preserves the selected-section behavior. `lead` returns the indexed-safe first fragment followed by `[Selected matching fragment]` and the selected fragment. |
616
+ | `--max-chars` | positive integer | `3200` for `lead` | Hard contextual content budget in characters; requires `--context lead` and is mutually exclusive with `--max-tokens`. |
617
+ | `--max-tokens` | positive integer | _(none)_ | Approximate contextual budget using four characters per token; requires `--context lead` and is mutually exclusive with `--max-chars`. |
618
+ | `--filter` | `<key>=<value>` | _(none)_ | Repeatable scope filter (`user`, `agent`, `run`, `channel`). |
619
+ | `--track-usage`, `--no-track-usage` | flag | `true` | Record or suppress local usage-event and ranking updates for this successful read. |
620
+
551
621
  `meta` is not an asset type — `[<origin>//]meta[:<name>]` direct-reads a
552
622
  human-authored orientation doc from a bundle's optional `.meta/` directory
553
623
  (`<name>` defaults to `index`; `.meta/<name>.md` is tried before an
@@ -575,8 +645,27 @@ reduced metadata-first view without `content`/`template`/`prompt`;
575
645
  `editable` is `false`, `editHint`; `--shape agent` strips non-action metadata
576
646
  (e.g. `origin`, `tags`) down to the action-relevant field set while still
577
647
  including `ref`/`path`/`editable`; `--shape summary`
578
- returns a compact view with only `type`, `name`, `ref`, `description`, `tags`,
579
- `parameters`, `workflowTitle`, `action`, `run`, `origin`, and `keys`.
648
+ returns a compact view with `type`, `name`, `ref`, `description`, `tags`,
649
+ `parameters`, `workflowTitle`, `action`, `run`, `origin`, and `keys`, plus the
650
+ optional fragment metadata described below.
651
+
652
+ Opaque fragment shows and `--context lead` keep `ref` as the canonical parent
653
+ identity and add
654
+ `selectedRef`, `parentRef`, one-based `fragmentOrdinal`, `fragmentCount`,
655
+ `startLine`, `endLine`, optional `previousRef`/`nextRef`, and separate
656
+ fragment/parent character and token estimates. Contextual shows also report
657
+ `contextMode`, `contextMaxChars`, and `contextTruncated`. Heading aliases are
658
+ canonicalized in contextual `selectedRef` to the resolved opaque indexed
659
+ selector. Default exact shows through a friendly `#heading` retain their
660
+ source-live body and do not attach indexed-safe provenance that could describe
661
+ a different revision or projection.
662
+
663
+ `--context lead` is opt-in and accepts only fragment-qualified indexed Markdown
664
+ assets. Both the lead and selected content come from the same line-preserving,
665
+ safe indexed revision used by fragment search, even when the source file changes
666
+ between search and show. The selected block is labelled and kept last. When the
667
+ budget is tight, AKM clips or omits lead content before clipping selected
668
+ evidence; `contextTruncated` reports either case.
580
669
 
581
670
  Returns type-specific payloads:
582
671
 
@@ -618,6 +707,7 @@ akm workflow resume <run-id>
618
707
  akm workflow abandon <run-id>
619
708
  akm workflow list --active
620
709
  akm workflow list --children # also list child workflow runs
710
+ akm workflow list --all-scopes # include runs started from a different working directory
621
711
  akm workflow plan workflows/ship-release # compile+freeze preview, zero writes
622
712
  ```
623
713
 
@@ -630,8 +720,8 @@ Subcommands:
630
720
  | --- | --- |
631
721
  | `create <name>` | Validate and write a Markdown workflow under `workflows/`. `--path <dir>` places it in a subdirectory; `--from <file>` imports content; `--force` (requires `--from` or `--reset`) overwrites; `--print` prints the template that would be written instead of writing it |
632
722
  | `run <run-id\|ref>` | Stable canonical start/resume/execute command. A ref starts a run or resumes the active run in the current scope (announced as `resumed: true`, see below); a run id continues that exact active run. `--new` starts a fresh run even when one is already active. Executes until completion, failure, verification rejection, interruption, or an explicit limit |
633
- | `status <run-id\|ref>` | Show the full run state, including all step statuses. `--units` also lists per-unit rows from the run journal (diagnostics only). Renders a `children:` tree when the run composes child workflows |
634
- | `list` | List workflow runs (optionally filtered by `--ref`; `--active` shows only `status=active` runs, excluding `blocked`/`failed`/`completed`). Child workflow runs are excluded unless `--children` is passed |
723
+ | `status <run-id\|ref>` | Show the full run state, including all step statuses. `--units` also lists per-unit rows from the run journal (diagnostics only). Renders a `children:` tree when the run composes child workflows. `--all-scopes` widens the ref-fallthrough lookup (only reached when the target does not resolve to a run id) to every scope instead of just the current one |
724
+ | `list` | List workflow runs (optionally filtered by `--ref`; `--active` shows only `status=active` runs, excluding `blocked`/`failed`/`completed`). Child workflow runs are excluded unless `--children` is passed. `--all-scopes` searches every scope instead of only the current one (#942) |
635
725
  | `resume <run-id>` | Flip a `blocked` or `failed` run back to `active`. Completed runs cannot be resumed |
636
726
  | `abandon <run-id>` | Mark a run failed so it stops counting as active (`resume` can reopen it) |
637
727
  | `plan <ref>` | **Evolving.** Compile and freeze a workflow WITHOUT publishing a run: the canonical step graph, per-step frozen target kinds, task/child expansion, input bindings, source read set, and lowering notices — zero durable writes. Returns the full JSON envelope by default, like every other command; pass `--format text` for a human-readable summary |
@@ -662,6 +752,7 @@ akm workflow run workflows/ship-release --version 1.2.3
662
752
  akm workflow run workflows/review --files a.ts --files b.ts
663
753
  akm workflow run <run-id> --max-steps 3
664
754
  akm workflow run <run-id> --max-retries 2 --timeout 10m
755
+ akm workflow run <run-id> --skip-if-locked # for scheduled runs: skip (exit 0) instead of failing on contention
665
756
  ```
666
757
 
667
758
  Parameter flags must follow the target and exactly match keys declared in the
@@ -686,6 +777,7 @@ The old `--params <json>` bag is removed.
686
777
  | `--max-retries <n>` | When a step fails, reopen the same run and retry the failed step up to this many additional times. Range: 0 through 100; default 0. Gate rejection and interruption are not retried. |
687
778
  | `--timeout <duration>` | Abort the whole invocation after `N`, `Nms`, `Ns`, or `Nm`; bare `N` is milliseconds. The active step remains resumable. |
688
779
  | `--new` | Start a fresh run even when one is already active for this ref, instead of resuming it. The existing active run is left untouched — it is never abandoned automatically. A workflow ref only: passing a run id with `--new` is a usage error (exit 2). Parameter flags are allowed together with `--new`, since it is starting a new run. |
780
+ | `--skip-if-locked` | If another akm process already holds this run's engine lease (`RUN_LEASE_HELD`), or `state.db` is busy with another writer (`STATE_DB_CONTENDED`), skip gracefully (exit 0) instead of failing (exit 75, `TransientError`). The envelope reports `{ skipped: { reason: "lock-held" \| "state-db-contended", message } }`. Every other failure (a bad flag, an unresolvable target) still fails loudly regardless of this flag. Use for high-frequency scheduled runs so they don't pile up failures while a longer-running invocation is in progress — same family as `improve --skip-if-locked`. |
689
781
 
690
782
  **Resuming an active run is announced, not silent.** Passing a ref that
691
783
  already has an active run in the current scope resumes that run rather than
@@ -729,9 +821,10 @@ ancestor when present, otherwise the nearest git root, otherwise the bundle root
729
821
  when the cwd is inside it, otherwise the cwd itself. In practice this means:
730
822
 
731
823
  - `workflow run workflows/<name>` resumes the active run for the current project/worktree/directory (announced with `resumed: true`), or starts one when none is active. `--new` always starts a fresh run.
732
- - `workflow status workflows/<name>` resolves the most-recently-updated run in the current scope only.
733
- - `workflow list` shows runs for the current scope only.
734
- - Direct run-id commands like `workflow status <run-id>` still work even if the run was started from another directory.
824
+ - `workflow status workflows/<name>` resolves the most-recently-updated run in the current scope only, unless `--all-scopes` is passed.
825
+ - `workflow list` shows runs for the current scope only, unless `--all-scopes` is passed. Its envelope always carries a top-level `scopeKey` naming the scope that was searched (`null` under `--all-scopes`), so an empty `runs: []` is never indistinguishable from "nothing anywhere".
826
+ - Direct run-id commands like `workflow status <run-id>`, `workflow resume <run-id>`, and `workflow abandon <run-id>` still work even if the run was started from another directory.
827
+ - Starting a ref by name (`workflow run workflows/<name>`) never collides across scopes — each scope can hold its own active run of the same ref — but if an active run of that ref exists in a *different* scope, the started run's envelope carries a `warnings[]` entry naming that run's id, scope, and start time, with the `akm workflow run <id>` / `akm workflow abandon <id>` remedy, so a stray run in another scope does not go unnoticed (#942).
735
828
 
736
829
  #### workflow create
737
830
 
@@ -772,13 +865,16 @@ affect the in-flight run.
772
865
  akm workflow status <run-id>
773
866
  akm workflow status workflows/ship-release
774
867
  akm workflow status <run-id> --units # also list per-unit rows from the run journal
868
+ akm workflow status workflows/ship-release --all-scopes # resolve across every scope, not just the current one
775
869
  ```
776
870
 
777
871
  Accepts a run id, a unique 8+ character run-id prefix, or a workflow ref.
778
872
  When given a workflow ref, resolves to the most-recently-updated run for that
779
- ref in the current working scope. `--units` adds per-unit rows (unit id,
780
- status, failure reason, and any result/error diagnostic text) from the run
781
- journal diagnostics only; step evidence stays deterministic and is
873
+ ref in the current working scope, unless `--all-scopes` is passed (only
874
+ relevant when the target does not resolve to a run id; a run id is always
875
+ scope-agnostic, `--all-scopes` or not, #942). `--units` adds per-unit rows
876
+ (unit id, status, failure reason, and any result/error diagnostic text) from
877
+ the run journal — diagnostics only; step evidence stays deterministic and is
782
878
  unaffected.
783
879
 
784
880
  #### workflow plan
@@ -1565,28 +1661,35 @@ error (exit 2), the canonical bare-group behavior — name a subcommand.
1565
1661
  ```sh
1566
1662
  akm config list # List current config
1567
1663
  akm config get output.format # Read one key
1664
+ akm config get output.format --show-source # Read one key, with where it came from
1568
1665
  akm config set output.detail full # Set one key
1569
1666
  akm config set output.detail full --silent # Set without the post-write config dump on stdout
1570
1667
  akm config unset llm # Remove an optional key
1571
1668
  akm config path # Print path to config file
1572
1669
  akm config path --all # Print all config-related paths
1670
+ akm config diff other-host/config.json # Effective-config differences, secrets redacted
1573
1671
  ```
1574
1672
 
1575
1673
  Subcommands:
1576
1674
 
1577
1675
  | Subcommand | Description |
1578
1676
  | --- | --- |
1579
- | `get <key>` | Read one config key |
1677
+ | `get <key>` | Read one config key (the effective, post-`extends` value). `--show-source` wraps it as `{ value, source }`, where `source` is `local`, `extends:<ref>`, or `default`. |
1580
1678
  | `list` | List current configuration |
1581
1679
  | `set <key> <value>` | Set one config key; prints the resulting config with `ok: true` |
1582
1680
  | `unset <key>` | Unset an optional key, or a whole `embedding`/engine section; prints the resulting config with `ok: true` |
1583
1681
  | `path` | Show paths to config, bundle, cache, and index. `--all` prints every path; without it, just the config path. Load-bearing: `config path` is the one subcommand the CLI still allows to run when the on-disk config itself fails to load, so you always have a way to locate a broken config. |
1682
+ | `diff <path\|bundle//path>` | Compare this instance's effective config (its own `extends` already applied) against another config file or bundle-relative file (loaded through the same loader — its `extends` honoured too); prints sorted `{ path, local, other }` rows for every differing leaf, secrets redacted on both sides. |
1584
1683
 
1585
1684
  `set` and `unset` accept `--silent` to suppress the post-write config dump
1586
1685
  entirely — nothing is printed on stdout, and the exit code is the status (the
1587
1686
  write still happens and errors still print) — use it from hooks and CI
1588
1687
  scripts.
1589
1688
 
1689
+ See [configuration.md](configuration.md)'s "Sharing configuration across
1690
+ installs" for the `extends` config key that `diff` and `get --show-source`
1691
+ work with.
1692
+
1590
1693
  > **Removed in 0.9.0:** `akm config enable`/`akm config disable`. Use
1591
1694
  > `akm registry add|remove` to toggle a registry, the general mechanism.
1592
1695
  > `akm config show` (an alias of `list`) and `akm config validate` (load-time
@@ -1597,14 +1700,22 @@ See [configuration.md](configuration.md) for details.
1597
1700
  ### models
1598
1701
 
1599
1702
  Manage the installed and operator-owned model intent map. Bare `akm models`
1600
- is a usage error; use the explicit copy operation when you want an editable
1601
- full map.
1703
+ is a usage error; use `list` to inspect the effective table or `copy-defaults`
1704
+ when you want an editable full map.
1602
1705
 
1603
1706
  ```sh
1707
+ akm models list
1604
1708
  akm models copy-defaults
1605
1709
  akm models copy-defaults --overwrite
1606
1710
  ```
1607
1711
 
1712
+ `list` shows the fully resolved alias table — one row per (alias, column)
1713
+ pair with its `model`, optional `inference`, `source` (`default`: unchanged
1714
+ from the installed file; `user`: touched by the user overlay), and `via`
1715
+ (`literal`: a model string; `engine`: borrowed from a configured
1716
+ `engines.<name>` connection, in which case the row also names that `engine`).
1717
+ Read-only; it never writes `models.json`.
1718
+
1608
1719
  `copy-defaults` validates the packaged version-1 `models.json`, then stages and
1609
1720
  syncs it beside the normal AKM configuration target. Creation uses an atomic
1610
1721
  no-replace publish and fails safely on filesystems that cannot provide it.
@@ -1614,7 +1725,8 @@ filesystems do not offer a conditional rename that locks the previously
1614
1725
  observed inode. Symlinks and other non-regular targets observed during checks
1615
1726
  are refused. See
1616
1727
  [Model-map files](configuration.md#model-map-files) for schema, overlay, and
1617
- resolution semantics.
1728
+ resolution semantics — including the `engine` field (0.9.15) that lets a
1729
+ column borrow its model from a configured engine instead of a literal string.
1618
1730
 
1619
1731
  ### help
1620
1732
 
@@ -2068,8 +2180,13 @@ akm agent [<agent-ref>] [--engine <name>] [--prompt <text>] [--model <model>] [-
2068
2180
 
2069
2181
  When `<agent-ref>` is provided, akm resolves the bundle agent's persona,
2070
2182
  `modelHint`, and requested `toolPolicy`. The `--model` flag wins over any model
2071
- specified in the asset. The requested tool policy never grants access by
2072
- itself: authorization runs before lowering, credentials, or provider dispatch.
2183
+ specified in the asset. An alias resolves per the selected `--engine`'s
2184
+ model-map column (see [Model-map files](configuration.md#model-map-files)),
2185
+ which — as of 0.9.15 — may itself be an `engine`-backed indirection, so
2186
+ `--engine local-fast --model fast` can resolve to `local-fast`'s own
2187
+ `engines.local-fast.model` instead of a hardcoded per-platform literal. The
2188
+ requested tool policy never grants access by itself: authorization runs before
2189
+ lowering, credentials, or provider dispatch.
2073
2190
  The current CLI has no built-in allow-all authorizer, so a nonempty request is
2074
2191
  rejected rather than silently weakened.
2075
2192
  Selecting a persona or model without `--prompt` or `--prompt-stdin` is also
@@ -2175,14 +2292,22 @@ akm improve memory
2175
2292
  akm improve skills/code-review
2176
2293
  akm improve workflows/release-checklist --task "reduce duplication"
2177
2294
  akm improve --skip-if-locked # for high-frequency scheduled runs: skip (exit 0) if a run is already in progress
2295
+ akm improve --require-engines # for scheduled runs: abort (exit 78) instead of degrading if an engine/credential is unavailable
2178
2296
  akm improve --no-sync # skip the end-of-run git commit entirely (default: on for git-backed bundles)
2179
2297
  akm improve --sync --no-push # commit only, skip the push after it
2298
+ akm improve --plan --strategy thorough # preview thorough's resolved engine/model routing; nothing is dispatched
2299
+ akm improve report # LLM usage/routing report for the most recent real run
2300
+ akm improve report --run <id> # ...for one specific improve_runs id
2301
+ akm improve report --since 7d # ...aggregated over every real run started in the last 7 days
2180
2302
  ```
2181
2303
 
2182
2304
  | Flag | Description |
2183
2305
  | --- | --- |
2306
+ | `--run <id>` | `report` scope only (#944): show the usage report for one specific `improve_runs` row instead of the most recent real run. Mutually exclusive with `--since`. Rejected with any other scope, or no scope. |
2307
+ | `--since <window>` | `report` scope only (#944): aggregate the usage report over every real (non-dry-run) run started since `<window>` (a duration like `24h`/`7d`, or an ISO timestamp) instead of one run. Mutually exclusive with `--run`. Rejected with any other scope, or no scope. |
2184
2308
  | `--task` | Optional extra guidance for this improvement pass |
2185
2309
  | `--dry-run` | Show the schema-v2 result on stdout without creating config, data, state, cache, bundle, log, or result artifacts. Dry-run results are never persisted, including on errors or signals. |
2310
+ | `--plan` | Alias for `--dry-run` (#947). Sets the exact same internal flag; no separate code path. Prefer this spelling when the goal is previewing `plan.processes` (resolved process -> engine -> model routing) rather than checking what would be written. |
2186
2311
  | `--bundle` | Select the proposal/write target; when the ref scope is bundle-qualified, it must name the same bundle |
2187
2312
  | `--limit <n>` | Base cap for ordinary assets (highest utility first); configured replay slots are additive |
2188
2313
  | `--timeout-ms <ms>` | Wall-clock budget for the run (default: `7200000` = 2 hours) |
@@ -2190,6 +2315,7 @@ akm improve --sync --no-push # commit only, skip the push after it
2190
2315
  | `--strategy <name>` | Override the active improve strategy (a built-in or entry under `improve.strategies`) |
2191
2316
  | `--json-to-stdout` | Also emit the full persisted JSON result on stdout for a live run. Without this flag, stdout stays empty. Dry-runs always emit their result and are never persisted. |
2192
2317
  | `--skip-if-locked` | If another improve run already holds the lock, skip gracefully (exit 0) instead of failing with "already running" (exit 78). Use for high-frequency scheduled runs so they don't pile up failures while a longer run is in progress. |
2318
+ | `--require-engines` | Abort (exit 78, before any indexing, lock, or log side effect) if the active strategy would enable a process whose engine or credential cannot be resolved in this process's environment. Without this flag, improve degrades gracefully: it skips the affected processes and reports them in the result's `skippedProcesses`. Recommended alongside `--skip-if-locked` for scheduled runs, since the operator's own shell can pass config validation while a scheduler's stripped-down environment (see #953) cannot. |
2193
2319
  | `--sync` / `--no-sync` | Commit (and optionally push) the git-backed primary bundle when the run finishes. Default: on for git-backed bundles (per profile config). |
2194
2320
  | `--push` / `--no-push` | Push after the end-of-run sync commit when writable with a remote configured. `--no-push` commits only, skipping the push. Default: per profile config (`true`). `sync.push` stays outside the autonomy gate — this is a per-run opt-out, not a default change. |
2195
2321
 
@@ -2227,6 +2353,24 @@ Selection behavior defaults to recent feedback signals first, with a
2227
2353
  zero-feedback retrieval fallback for high-traffic refs. Use
2228
2354
  `--require-feedback-signal` to disable retrieval fallback for the run.
2229
2355
 
2356
+ When the active strategy enables a process (or the triage judgment engine)
2357
+ whose engine or credential cannot be resolved in this process's environment,
2358
+ the run does not silently do nothing for it: the process is skipped, and the
2359
+ result carries `skippedProcesses` — an array of `{process, configKey, reason}`
2360
+ entries (omitted entirely when nothing was skipped). When the process resolved
2361
+ a real engine whose credential just isn't reachable here (as opposed to never
2362
+ resolving an engine at all), the entry also carries the structurally resolved
2363
+ `engine`/`model`/`contextLength` it would have used — never the credential
2364
+ itself. `ok` and the exit code are unchanged either way, matching `extract`'s
2365
+ `skipReasons` contract: consumers that need to know branch on
2366
+ `skippedProcesses` (or pass `--require-engines` to abort instead of
2367
+ degrading). `reason` names which engine and which credential reference (an env
2368
+ var, `apiKeyFile` path, or `secret://` reference — never its value) is
2369
+ missing. A `--dry-run`/`--plan` preview never dispatches, so it never aborts
2370
+ on an unavailable credential either — even a strategy left with every process
2371
+ disabled this way still returns its plan, with the affected processes in
2372
+ `skippedProcesses`.
2373
+
2230
2374
  For dry runs, `plannedRefs` is the effective post-limit work set, not every
2231
2375
  ref in the requested scope. The `plan` object preserves both views: raw scope
2232
2376
  size and per-gate removals, configured and effective caps, final ranked refs
@@ -2243,11 +2387,75 @@ not an atomic cross-store snapshot or a reservation. Live execution re-inspects
2243
2387
  mutable inputs, so a later run can differ after index, state, filesystem,
2244
2388
  clock, or session-log changes.
2245
2389
 
2390
+ `plan.processes` (#947) is the resolved process -> engine -> model routing
2391
+ table: one row per improve process (`reflect`, `distill`, `consolidate`,
2392
+ `memoryInference`, `graphExtraction`, `extract`, `validation`, `triage`,
2393
+ `proactiveMaintenance`), plus a `triage.judgment` row when the strategy
2394
+ configures a judgment engine. Each row carries `enabled`, the resolved
2395
+ `engine`/`model` (llm-backed processes only) and `engineKind`, this process's
2396
+ own lowering `notices`, and — for reflect/distill/consolidate only —
2397
+ `eligibleRefs`, the count of this run's `effectiveRefs` the process would act
2398
+ on (`shouldSkipRef`'s allowedTypes/process-disabled check; a count, not a
2399
+ per-ref matrix, to keep the envelope bounded). A row that could not resolve an
2400
+ engine or credential carries `unavailable: {configKey, reason}` — the same
2401
+ data behind `skippedProcesses` above, reshaped per process. When the process
2402
+ resolved a real engine whose credential just isn't reachable here, the row
2403
+ still carries that engine's `engine`/`model`/`engineKind` alongside
2404
+ `unavailable`, rather than omitting them the way a never-configured process
2405
+ does — so a preview can show what would have run. This table is
2406
+ resolved before any dispatch on every invocation (dry or live), so
2407
+ `akm improve --dry-run --strategy <name>` (or `--plan`) previews an ad-hoc
2408
+ strategy override without changing config first; `akm health`'s
2409
+ `active-improve-strategy` check performs the equivalent resolution but only
2410
+ for the configured default strategy (`defaults.improveStrategy`), and reports
2411
+ no model or per-process notices. Neither `--dry-run` nor `--plan` probes
2412
+ engine reachability over the network — pair with `akm health --probe` (or the
2413
+ default probe-on behavior) to check whether a named engine actually answers.
2414
+
2246
2415
  When reinforced facts need promotion, `knowledge` is the higher-authority
2247
2416
  destination than `memory`. The deterministic search ranking also prefers
2248
2417
  `knowledge` over `memory` hits, including inferred `.derived` memories, when
2249
2418
  the evidence is otherwise comparable.
2250
2419
 
2420
+ #### improve report
2421
+
2422
+ `akm improve report` (#944) answers "which engine did each LLM-backed process
2423
+ use this run, how much did it cost, and which enabled processes made zero
2424
+ calls (and why)" without hand-written SQLite against `state.db`. It is a
2425
+ `scope` value, not a subcommand — `report` is not, and will never be, a real
2426
+ asset type, so it is intercepted before any lock/log/index side effect (same
2427
+ precedent as the retired `canary` scope).
2428
+
2429
+ Every real (non-dry-run) `akm improve` invocation persists a `usageReport`
2430
+ field on the result (`result_json` in `improve_runs`, and in the
2431
+ `--json-to-stdout` / dry-run JSON): `{ byProcessEngineModel, noCalls }`.
2432
+ `byProcessEngineModel` is a cross-tab of this run's own `llm_usage` events
2433
+ (#576) — one row per distinct `(process, engine, model)` triple, each with
2434
+ `calls`, `failures`, `promptTokens`, `completionTokens`, `totalTokens`,
2435
+ `reasoningTokens`, and `totalDurationMs`. `noCalls` lists every LLM-backed
2436
+ process (`reflect`, `distill`, `consolidate`, `memoryInference`,
2437
+ `graphExtraction`, `extract`, `validation` — not `triage`/`proactiveMaintenance`,
2438
+ which never make an attributable LLM call themselves) the active strategy
2439
+ enabled but that ended the run with zero calls, each with a `reason` drawn
2440
+ from the existing skip-reason vocabulary: `"engine_unavailable"` (also in
2441
+ `skippedProcesses`), `"autonomy_gated"`, `"strategy_filtered_all_passes"`, a
2442
+ reflect/distill dominant skip reason (e.g. `"no_new_signal"`, `"cooldown"`),
2443
+ or `"no_signal"` as the fallback — never a fabricated category. The field is
2444
+ omitted entirely when both would be empty. The same table is printed to
2445
+ stderr (`[improve] usage report ...`) after every real run, independent of
2446
+ `--json-to-stdout`.
2447
+
2448
+ `akm improve report` reads that field back: with no flags, the most recent
2449
+ real run; `--run <id>`, one specific run; `--since <window>`, summed across
2450
+ every real run in the window (`byProcessEngineModel` rows merged by
2451
+ `(process, engine, model)`; `noCalls` lists a process only if it made zero
2452
+ calls across every included run). A run recorded before 0.9.15 has no
2453
+ persisted `usageReport` — the command recomputes `byProcessEngineModel` from
2454
+ that run's own `llm_usage` events instead of erroring, sets `noCalls` to `[]`
2455
+ (eligibility reasons are not reconstructable after the fact), and adds a
2456
+ `notes` entry saying so rather than fabricating precision the old row can't
2457
+ support.
2458
+
2251
2459
  ### proposal
2252
2460
 
2253
2461
  Manage the proposal queue. The canonical grammar is `akm proposal <verb>`:
@@ -2532,13 +2740,14 @@ shell commands. It manages on-disk task definitions under
2532
2740
  (cron / launchd / schtasks). Task source v4 YAML (`version: 4`) is the only
2533
2741
  executable source contract this release accepts; `akm task add` writes v4 —
2534
2742
  see the canonical [Tasks reference](tasks.md). The
2535
- group is `add | run | explain | validate | sync | doctor | history | prune`
2536
- — there is no `list` or `remove`; use `akm search --type task` /
2537
- `akm show tasks/<id>` to inspect, and edit the file + `akm task sync` to
2538
- change or remove a schedule.
2743
+ group is `add | run | explain | validate | list | sync | doctor | history | prune`
2744
+ — there is no `show` or `remove`; use `akm show tasks/<id>` to inspect one
2745
+ task, and edit the file + `akm task sync` to change or remove a schedule.
2746
+ `task list` is a delegating alias for `akm search --type task` — both
2747
+ spellings return the identical envelope.
2539
2748
 
2540
2749
  ```sh
2541
- akm search --type task # List tasks (cross-bundle)
2750
+ akm task list # List tasks (cross-bundle) — alias for `search --type task`
2542
2751
  akm show tasks/<id> # Inspect one task
2543
2752
  akm task add <id> --schedule "@daily" \ # Register a new task and install it
2544
2753
  --command "akm improve --strategy default"
@@ -2563,6 +2772,13 @@ scheduler), `--force` (overwrite an existing task with the same id), and
2563
2772
  `--rebind` (explicitly permit scheduler creation from a local invocation that
2564
2773
  would otherwise be considered ineligible).
2565
2774
 
2775
+ `akm task list [<query>] [--limit <n>] [--from local|registry|all]` is a
2776
+ pure alias for `akm search --type task` with the query, `--limit`, and
2777
+ `--from` flags passed through — same envelope, same `results` alias, no
2778
+ second implementation. 0.9.0 removed `task list` as a redundant
2779
+ implementation of task listing (see the 0.9.0 CHANGELOG entry); this
2780
+ reintroduces only the spelling, not the logic.
2781
+
2566
2782
  `akm task explain <ref> [input flags]` prints a task's declared `inputs:`,
2567
2783
  the values that would actually be supplied (with provenance), the resolved
2568
2784
  target, effective execution settings, and schedule bindings — **read-only**: