akm-cli 0.9.14 → 0.9.15-beta.2

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 (120) hide show
  1. package/CHANGELOG.md +559 -0
  2. package/STABILITY.md +6 -3
  3. package/dist/akm +54 -1
  4. package/dist/akm-migrate +34 -1
  5. package/dist/assets/prompts/reflect-feedback-framing.md +1 -0
  6. package/dist/assets/prompts/reflect-llm-framed-contract.md +2 -0
  7. package/dist/assets/prompts/reflect-llm-schema-contract.md +2 -0
  8. package/dist/assets/tasks/core/improve.yml +1 -1
  9. package/dist/assets/tasks/core/index-refresh.yml +1 -1
  10. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +1 -1
  11. package/dist/assets/tasks/improve/akm-improve-catchup.yml +1 -1
  12. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +1 -1
  13. package/dist/assets/tasks/improve/akm-improve-frequent.yml +1 -1
  14. package/dist/assets/tasks/improve/akm-improve-nightly.yml +1 -1
  15. package/dist/cli/retired-commands.js +0 -1
  16. package/dist/cli/shared.js +9 -0
  17. package/dist/cli/unknown-flags.js +1 -0
  18. package/dist/cli.js +40 -3
  19. package/dist/commands/config-cli.js +85 -3
  20. package/dist/commands/env/env-cli.js +1 -42
  21. package/dist/commands/env/env.js +1 -1
  22. package/dist/commands/env/secret-cli.js +1 -2
  23. package/dist/commands/health/checks.js +357 -63
  24. package/dist/commands/health/engine-usage.js +45 -0
  25. package/dist/commands/health/improve-metrics.js +18 -0
  26. package/dist/commands/health/llm-usage.js +41 -1
  27. package/dist/commands/health/plugin-staleness.js +7 -3
  28. package/dist/commands/health/version-drift.js +93 -0
  29. package/dist/commands/health/windows.js +3 -1
  30. package/dist/commands/health.js +44 -9
  31. package/dist/commands/improve/consolidate/chunking.js +4 -2
  32. package/dist/commands/improve/improve-cli.js +99 -5
  33. package/dist/commands/improve/improve-report.js +154 -0
  34. package/dist/commands/improve/improve-result-file.js +45 -33
  35. package/dist/commands/improve/improve-strategies.js +133 -3
  36. package/dist/commands/improve/improve-usage-report.js +182 -0
  37. package/dist/commands/improve/improve.js +40 -3
  38. package/dist/commands/improve/locks.js +28 -78
  39. package/dist/commands/improve/planner.js +1 -0
  40. package/dist/commands/improve/preparation.js +9 -1
  41. package/dist/commands/improve/reflect.js +44 -4
  42. package/dist/commands/models-cli.js +50 -1
  43. package/dist/commands/proposal/repository.js +8 -3
  44. package/dist/commands/proposal/validators/proposal-quality-validators.js +41 -6
  45. package/dist/commands/proposal/validators/proposal-validators.js +24 -0
  46. package/dist/commands/read/search-cli.js +38 -2
  47. package/dist/commands/read/show.js +103 -4
  48. package/dist/commands/sources/info.js +5 -1
  49. package/dist/commands/sources/installed-stashes.js +58 -16
  50. package/dist/commands/sources/self-update.js +2 -2
  51. package/dist/commands/sources/stash-cli.js +48 -0
  52. package/dist/commands/tasks/tasks-cli.js +49 -2
  53. package/dist/commands/workflow-cli.js +86 -12
  54. package/dist/core/asset/markdown-fragments.js +35 -0
  55. package/dist/core/config/config-schema.js +14 -0
  56. package/dist/core/config/config.js +302 -24
  57. package/dist/core/config/schema/embedding.js +41 -0
  58. package/dist/core/env-secret-ref.js +58 -5
  59. package/dist/core/errors.js +30 -0
  60. package/dist/core/file-lock.js +49 -15
  61. package/dist/core/improve-result.js +51 -0
  62. package/dist/core/loopback.js +17 -0
  63. package/dist/core/parent-watchdog.js +64 -0
  64. package/dist/core/paths.js +11 -0
  65. package/dist/core/run-lock.js +107 -0
  66. package/dist/core/sensitive-marker-path.js +19 -0
  67. package/dist/core/state-db.js +74 -14
  68. package/dist/indexer/index-rebuild-lock.js +73 -0
  69. package/dist/indexer/index-writer-lock.js +40 -1
  70. package/dist/indexer/index-written-assets.js +29 -1
  71. package/dist/indexer/indexer.js +93 -29
  72. package/dist/indexer/materialize-embeddings.js +564 -48
  73. package/dist/indexer/search/db-search.js +49 -2
  74. package/dist/indexer/search/search-source.js +23 -1
  75. package/dist/integrations/agent/engine-resolution.js +96 -6
  76. package/dist/integrations/agent/execution-definitions.js +6 -15
  77. package/dist/integrations/agent/execution-lowering.js +6 -1
  78. package/dist/integrations/agent/execution-preparation.js +1 -1
  79. package/dist/integrations/agent/model-map.js +123 -20
  80. package/dist/integrations/agent/prompts.js +40 -8
  81. package/dist/integrations/agent/runner-dispatch.js +9 -3
  82. package/dist/integrations/agent/runner.js +2 -0
  83. package/dist/llm/client.js +8 -3
  84. package/dist/llm/embedder.js +20 -8
  85. package/dist/llm/embedders/local.js +10 -2
  86. package/dist/llm/embedders/remote.js +497 -32
  87. package/dist/output/shapes/helpers.js +38 -2
  88. package/dist/output/shapes/models-list.js +16 -0
  89. package/dist/output/shapes/passthrough.js +2 -0
  90. package/dist/output/shapes.js +4 -0
  91. package/dist/output/text/command-format.js +29 -0
  92. package/dist/output/text/helpers.js +1 -1
  93. package/dist/output/text/improve-report.js +27 -0
  94. package/dist/{commands/env/marker-path.js → output/text/models.js} +4 -3
  95. package/dist/output/text/show-format.js +4 -0
  96. package/dist/output/text.js +4 -0
  97. package/dist/scripts/akm-migrate-node.js +25146 -21759
  98. package/dist/scripts/akm-migrate.js +24271 -20885
  99. package/dist/storage/repositories/embedding-salvage-repository.js +184 -0
  100. package/dist/storage/repositories/improve-runs-repository.js +34 -0
  101. package/dist/storage/repositories/index-fts-repository.js +49 -6
  102. package/dist/storage/repositories/index-schema.js +16 -0
  103. package/dist/storage/repositories/index-vec-repository.js +30 -0
  104. package/dist/storage/repositories/workflow-runs-repository.js +55 -18
  105. package/dist/tasks/backends/cron.js +14 -7
  106. package/dist/tasks/run/run-native-task.js +23 -1
  107. package/dist/tasks/run/run-workflow-task.js +16 -0
  108. package/dist/workflows/exec/child-workflow.js +2 -2
  109. package/dist/workflows/exec/dispatch-redaction.js +21 -9
  110. package/dist/workflows/exec/run-workflow.js +6 -5
  111. package/dist/workflows/runtime/runs.js +33 -5
  112. package/docs/migration/release-notes/0.9.15.md +133 -0
  113. package/docs/migration/release-notes/README.md +5 -0
  114. package/docs/reference/cli.md +271 -30
  115. package/docs/reference/configuration.md +234 -21
  116. package/docs/reference/data-and-telemetry.md +8 -0
  117. package/docs/reference/tasks.md +16 -1
  118. package/docs/reference/workflow-schema.md +5 -1
  119. package/package.json +1 -1
  120. package/schemas/akm-config.json +47 -0
@@ -3,7 +3,10 @@
3
3
  AKM reads one user configuration file: `$XDG_CONFIG_HOME/akm/config.json`
4
4
  (normally `~/.config/akm/config.json` on Linux and macOS, or
5
5
  `%APPDATA%\akm\config.json` on Windows). Set `AKM_CONFIG_DIR` to override the
6
- directory. Project `.akm/config.json` files are not merged.
6
+ directory. Project `.akm/config.json` files are not merged. A config file may
7
+ optionally extend one other config via `extends` (see "Sharing configuration
8
+ across installs" below) — this is a single, explicit, user-opted-in key, not
9
+ automatic project-config discovery.
7
10
 
8
11
  ## Version 0.9
9
12
 
@@ -89,14 +92,21 @@ LLM endpoints must be complete `http://` or `https://` chat-completions URLs
89
92
  ending in `/chat/completions`, without userinfo, query, or fragment. API keys
90
93
  are symbolic only: `$VAR` or `${VAR}`. AKM resolves them only at dispatch.
91
94
 
92
- An LLM engine may set `reasoningEffort` to a non-empty provider-supported
93
- value such as `"none"`, `"low"`, or `"high"`. AKM sends it as the top-level
94
- OpenAI-compatible `reasoning_effort` parameter alongside the existing
95
- `enableThinking` control, because providers do not all honor the same thinking
96
- switch. `reasoning_effort` is AKM-owned and cannot be set through
97
- `extraParams`. If a response reports reasoning tokens despite
98
- `enableThinking: false`, AKM emits a runtime warning so an ineffective provider
99
- control is visible.
95
+ An LLM engine may set `enableThinking: false` to turn thinking off and
96
+ `reasoningEffort` to a value such as `"none"`, `"low"`, or `"high"`. AKM sends
97
+ **both** wire forms — `chat_template_kwargs.enable_thinking` and top-level
98
+ `enable_thinking` whenever `enableThinking` resolves, from engine config
99
+ or a calling process (improve's `consolidate`/`reflect` and the distill
100
+ quality gate always request `enableThinking: false` for a machine-readable
101
+ payload); `reasoningEffort` is always sent as top-level `reasoning_effort`
102
+ when set. Backend support: llama.cpp direct honors both forms
103
+ (`reasoning_effort` from build ≥ b10644); vLLM honors
104
+ `chat_template_kwargs`; Bifrost drops `chat_template_kwargs` and passes
105
+ `reasoning_effort` through, so also set `reasoningEffort: "none"` behind it; a
106
+ strict hosted API may 400 on unrecognized keys. Both fields are AKM-owned, not
107
+ settable via `extraParams`. A response with reasoning tokens despite
108
+ `enableThinking: false` triggers a runtime warning and the `akm health`
109
+ `thinking-control` advisory.
100
110
 
101
111
  An agent engine may set `bin`, `args`, `workspace`, `model`, and `timeoutMs`.
102
112
  Only `platform: "opencode-sdk"` may set `llmEngine`; it names
@@ -147,19 +157,54 @@ the same version-1 schema as the installed file:
147
157
  ```
148
158
 
149
159
  Each engine mapping is either a non-empty exact model string or a structured
150
- profile with the documented fields `model` and `inference`. A user profile may
151
- omit `model` when the installed layer already supplies it, as the partial
152
- Claude override above does. After overlay, every alias/engine entry must have a
153
- usable model. Unknown profile fields are rejected; JSON-safe fields inside
154
- `inference` are preserved for engine adapters to lower optimistically.
160
+ profile with the documented fields `model`, `inference`, and `engine`. A user
161
+ profile may omit `model` when the installed layer already supplies it, as the
162
+ partial Claude override above does. After overlay, every alias/engine entry
163
+ must have a usable model. Unknown profile fields are rejected; JSON-safe
164
+ fields inside `inference` are preserved for engine adapters to lower
165
+ optimistically.
166
+
167
+ A profile's `engine` field (0.9.15, #946) borrows a column's `model` (and, for
168
+ an `llm`-kind engine, its inference defaults) from a configured
169
+ `engines.<name>` connection instead of hand-typing a literal model a second
170
+ time:
171
+
172
+ ```json
173
+ {
174
+ "version": 1,
175
+ "aliases": {
176
+ "fast": {
177
+ "opencode": { "engine": "local-fast" }
178
+ }
179
+ }
180
+ }
181
+ ```
182
+
183
+ With `engines.local-fast` configured (agent-kind or llm-kind), this column
184
+ resolves to that engine's own `model` string. `model` and `engine` are
185
+ mutually exclusive on the same profile — `engine` is an indirection for the
186
+ model value, never an engine-selection override; which engine `akm agent`
187
+ dispatches to is still decided entirely by `--engine`/`defaults.engine` (see
188
+ [Engine selection](#engines)). The referenced engine's `model` must itself be
189
+ literal, not another alias, and akm copies it verbatim: it does not translate
190
+ between an engine's connection and an agent platform's own provider registry,
191
+ so the value must already be meaningful for the column's platform (e.g. a
192
+ `kind: "agent", platform: "opencode"` engine's `model` should already be a
193
+ string opencode itself understands, such as `krang/qwen3.5-9b`). Run
194
+ `akm models list` to see, for every alias/column, the resolved model and
195
+ whether it came from the installed defaults, the user overlay, and a literal
196
+ value or an `engine` reference.
155
197
 
156
198
  The user file overlays the installed file by alias, engine, and nested object
157
199
  field. Objects merge recursively. Arrays, scalars, and explicit `null` replace
158
- the lower value; omitted fields preserve it. Alias and engine keys are
159
- case-normalized, and case-colliding definitions are rejected. Unknown model
160
- inputs still pass through byte-for-byte as exact identifiers. Once a name is a
161
- known merged alias, selecting an engine with no mapping is an actionable
162
- configuration error rather than silently sending the alias as a model ID.
200
+ the lower value; omitted fields preserve it. A layer setting a literal `model`
201
+ clears any `engine` inherited from a farther layer, and vice versa the
202
+ nearer layer's choice of literal-vs-engine always wins outright rather than
203
+ merging. Alias and engine keys are case-normalized, and case-colliding
204
+ definitions are rejected. Unknown model inputs still pass through
205
+ byte-for-byte as exact identifiers. Once a name is a known merged alias,
206
+ selecting an engine with no mapping is an actionable configuration error
207
+ rather than silently sending the alias as a model ID.
163
208
 
164
209
  The common execution cascade reads these files for current direct command and
165
210
  non-interactive agent calls, task source v4 runs, and improve/proposal/index
@@ -351,8 +396,62 @@ unless a remote `embedding` config is provided.
351
396
  `akm improve`'s memory-inference/consolidate passes when they call an
352
397
  embedding model: `provider`, `endpoint`, `model`, `apiKey` (symbolic
353
398
  reference, same rules as engine `apiKey`), `dimension`, `localModel`,
354
- `maxTokens`, `batchSize`, `chunkSize`, `contextLength`, and
355
- `ollamaOptions.num_ctx`.
399
+ `maxInputTokens`, `maxTokens`, `batchSize`, `chunkSize`, `contextLength`,
400
+ `timeoutMs`, `concurrency`, and `ollamaOptions.num_ctx`.
401
+
402
+ The knobs that bound request/document size and rate, all optional (defaults
403
+ apply when unset), for a remote endpoint (`src/llm/embedders/remote.ts`):
404
+
405
+ | Key | Default | Bounds |
406
+ | --- | --- | --- |
407
+ | `embedding.maxInputTokens` | `512` | Per-DOCUMENT cap, applied before batching (#956). A document's embedded text is truncated to its head (unicode-safe) at this many estimated tokens instead of ever being skipped for size alone — a document is skipped only when its truncated head is empty. |
408
+ | `embedding.maxTokens` | `8000` (`DEFAULT_TOKEN_BUDGET`) | Per-REQUEST token budget: how many (already-capped) documents' estimated tokens fit in one HTTP request. With the 512-token default document cap, a request carries about 16 documents by default. |
409
+ | `embedding.batchSize` | `100` | Per-REQUEST document-COUNT safety cap, independent of the token budget — guards against many tiny documents packing an oversized request. |
410
+ | `embedding.contextLength` | unset | Ollama's `num_ctx` ONLY, forwarded verbatim as `options.num_ctx` on the native `/api/embed` request. Does **not** feed the request token budget above (#956) — the two used to share this one field, so setting it for the server's context window silently changed request batching too. |
411
+ | `embedding.timeoutMs` | `120000` (120s) | Per-request wall timeout — see below. |
412
+ | `embedding.concurrency` | `1` loopback / `2` remote | In-flight request window — see below. |
413
+
414
+ `embedding.timeoutMs` (positive integer, default `120000` — 120s) is the
415
+ budget for a request at the FULL token budget (`embedding.maxTokens`); a
416
+ local model server on a large, token-budget-bounded batch legitimately takes
417
+ longer than the prior fixed 30s cut off. A smaller request gets a
418
+ proportionally smaller timeout —
419
+ `clamp(timeoutMs × requestTokens / tokenBudget, 30000, timeoutMs)` — so a
420
+ dead endpoint is still detected in seconds on the common case of small
421
+ documents. Set `embedding.timeoutMs` lower to fail fast against a
422
+ known-fast endpoint, or higher for a slow local server on large batches.
423
+
424
+ A request TIMEOUT (not a rejection for exceeding the context window) never
425
+ drops its batch immediately: field confirmation showed that once akm
426
+ abandons a timed-out request, the endpoint (e.g. llama-server) keeps
427
+ computing it anyway, so dropping it right away just grows the provider's
428
+ queue while every following batch dies the same way. Instead akm backs off
429
+ (5s, doubling, capped at 60s) and retries the same request once; a second
430
+ timeout splits it in half and retries each half the same way, down to
431
+ individual documents, and a single document that still times out is finally
432
+ skipped (logged at the default `warn` level). After 3 consecutive failures
433
+ at single-document size (timeout or network error), or 3 consecutive
434
+ network errors at any size, the embedding phase stops dispatching further
435
+ requests and reports failure — batches already committed are kept; rerun
436
+ `akm index` once the endpoint is healthy.
437
+
438
+ `akm index` keeps a small number of `/v1/embeddings` requests in flight at
439
+ once (a remote endpoint only; the local transformer path is unaffected):
440
+ `1` for a loopback endpoint (`localhost`, `127.0.0.0/8`, etc. — a local
441
+ model server serves one inference at a time, and parallel requests thrash
442
+ it) and `2` for a remote one, unless `embedding.concurrency` (positive
443
+ integer, 1-16) overrides it. This default holds for the overwhelming
444
+ majority of setups; set the override only for an endpoint that genuinely
445
+ serves parallel requests — a local server started with a multi-slot flag
446
+ (llama.cpp's `--parallel N`, vLLM) — not to "speed up" an ordinary
447
+ single-slot model server, which the default already protects from
448
+ reload-thrash. Request SIZE remains the first throughput lever regardless:
449
+ `embedding.batchSize` (a document-count cap, default 100) together with
450
+ `embedding.maxTokens` (an estimated token budget per request, default 8000
451
+ — NOT `embedding.contextLength`, see the table above) control how many
452
+ documents land in one request — with the default 512-token
453
+ `embedding.maxInputTokens` document cap, that is about 16-32 documents,
454
+ taking about the same wall time as a single one against a healthy endpoint.
356
455
 
357
456
  ## Search tuning
358
457
 
@@ -484,6 +583,94 @@ Arrays replace, `null` is only valid for nullable fields, and `config unset` is
484
583
  the only deletion operation. `configVersion` cannot be set or unset with the
485
584
  generic walker.
486
585
 
586
+ `config get <key> --show-source` wraps the (redacted) value as
587
+ `{ value, source }`, where `source` is `"local"` when the local file's own
588
+ JSON sets the key, `"extends:<ref>"` for the nearest `extends` chain member
589
+ that sets it, or `"default"` when neither does. It is opt-in — plain
590
+ `config get` keeps its Stable, script-safe bare-value shape.
591
+
592
+ ### Sharing configuration across installs
593
+
594
+ Five hosts running the same fleet often carry an identical `engines` map and
595
+ `improve.strategies` block, differing only in credential delivery (`apiKey`
596
+ vs `apiKeyFile`), bundle paths, and cron offsets. Hand-syncing that block
597
+ across hosts drifts silently. `extends` fixes this: put the shared block in
598
+ one file, and have each host's local config extend it.
599
+
600
+ ```jsonc
601
+ // bundles/fleet/config/shared.json — versioned with the bundle, shared by every host
602
+ {
603
+ "configVersion": "0.9.0",
604
+ "engines": {
605
+ "fast": { "kind": "llm", "endpoint": "https://api.example.test/v1/chat/completions", "model": "qwen3" }
606
+ },
607
+ "improve": { "strategies": { "nightly": { "engine": "fast" } } }
608
+ }
609
+ ```
610
+
611
+ ```jsonc
612
+ // ~/.config/akm/config.json — this host's local file, under 20 lines
613
+ {
614
+ "configVersion": "0.9.0",
615
+ "extends": "fleet//config/shared.json",
616
+ "bundles": {
617
+ "fleet": { "git": "https://github.com/example/fleet-bundle.git" },
618
+ "stash": { "path": "~/akm-stash", "writable": true }
619
+ },
620
+ "defaultBundle": "stash",
621
+ "engines": { "fast": { "apiKeyFile": "/run/secrets/fast-api-key" } }
622
+ }
623
+ ```
624
+
625
+ `extends` accepts either form:
626
+
627
+ - A filesystem path — relative paths resolve against the directory of the
628
+ config file that declares them; a leading `~` expands.
629
+ - A `bundle//<path>` ref — a plain file path *relative to that bundle's
630
+ content root* (e.g. `config/shared.json`), resolved through the bundle's
631
+ configured `path`, not the search index — so it never needs `akm index` to
632
+ have run. This is not an asset ref: the path after `//` needs no asset type
633
+ (`scripts/`, `knowledge/`, …) and the shared file is never indexed; it can
634
+ live anywhere under the bundle. An empty, absolute, or content-root-escaping
635
+ path is rejected. Only a filesystem bundle (`bundles.<id>.path`) can host an
636
+ `extends` source; sync a `git`/`website` bundle with `akm bundle
637
+ add`/`akm sync` first so the file is materialized locally, then point
638
+ `extends` at it.
639
+
640
+ There is no `extends: <url>` form: config load is synchronous and runs on
641
+ every invocation, and akm deliberately does not fetch network resources at
642
+ load time (the same reason `registries` is never fetched until a
643
+ registry-touching command runs). A URL-backed shared config should be synced
644
+ as a `git`/`website` bundle and referenced as `extends: bundle//<path>`
645
+ once materialized, reusing the sync machinery akm already has instead of a
646
+ second one inside config load.
647
+
648
+ The base config runs through the exact same load pipeline as the local
649
+ file — its own version shim, its own legacy-shape shim — so it can carry an
650
+ older `configVersion` independently, and it may itself set `extends`
651
+ (chained). Cycle detection (`ConfigError`, "extends cycle detected") stops A
652
+ extends B extends A instead of recursing forever. Merge order is
653
+ `DEFAULT_CONFIG` (outermost) → the resolved `extends` chain → the local
654
+ file's own keys (local always wins) — the same `deepMergeConfig` "override
655
+ wins" semantics `config set` already uses. A referenced file/bundle that does
656
+ not already exist locally is a load-time `ConfigError` naming the ref — akm
657
+ never fetches or syncs one on your behalf.
658
+
659
+ `akm config diff <path|bundle//path>` compares this host's EFFECTIVE
660
+ config (its own `extends` already applied) against another config file or
661
+ bundle-relative file (loaded through the same loader, so ITS `extends` is
662
+ honoured too), printing sorted `{ path, local, other }` rows for every leaf
663
+ that differs. Both sides are redacted the same way `config get`/`list` are
664
+ before comparison, so a differing secret never round-trips into the diff
665
+ output. Cross-host comparison (`ssh host2 akm config diff ...` in a loop) is
666
+ left to the operator; akm has no concept of a networked fleet to compare
667
+ against directly.
668
+
669
+ ```sh
670
+ akm config diff ~/other-host/config.json
671
+ akm config diff fleet//config/shared.json
672
+ ```
673
+
487
674
  ## Environment
488
675
 
489
676
  | Variable | Purpose |
@@ -513,6 +700,32 @@ not itself a secret. Setting both `apiKey` and `apiKeyFile` on the same
513
700
  engine is rejected. A missing, unreadable, or empty file fails the call
514
701
  closed, naming the engine and path but never the file's content.
515
702
 
703
+ `engines.<name>.apiKey` also accepts `secret://<name>`, a reference into
704
+ AKM's own secret store (`akm secret set <name> --from-file <file>`), for a
705
+ launch context where the credential's environment variable is deliberately
706
+ not sourced into the process — a scheduled task's crontab preamble, or a
707
+ container entrypoint that keeps the user's env out on purpose — and a
708
+ file-backed credential is not an option. Like `apiKeyFile`, only the
709
+ reference is kept in `config.json`; the store lookup happens at dispatch
710
+ time, and an unresolved reference fails the call closed, naming the
711
+ reference but never the value. `akm improve`, workflow LLM steps, and `akm
712
+ health`'s engine probes all resolve `secret://` the same way direct LLM and
713
+ embedding calls have since 0.9.13 (#917); resolution order for a single
714
+ `apiKey` field is: an env reference (`$VAR`/`${VAR}`) first, then
715
+ `apiKeyFile`, then `secret://<name>` — though in practice a config sets only
716
+ one of the three per engine.
717
+
718
+ `embedding.apiKey` accepts the same three forms and resolves `secret://` the
719
+ same way, on every path that sends an embedding request: `akm index`
720
+ (including its `bundle update` post-commit embedding pass and the targeted
721
+ re-embed a write command like `akm remember` triggers), `akm improve`'s
722
+ consolidate pass (memory dedup and similarity clustering), and the
723
+ fingerprint-rename canary `akm index` runs when the embedding config
724
+ changes. All of them build the
725
+ provider request through the same `RemoteEmbedder`/`resolveSecret` boundary,
726
+ so a `secret://` reference resolves identically regardless of which command
727
+ triggered the request (#953).
728
+
516
729
  Use `AKM_SQLITE_JOURNAL_MODE=DELETE` or `TRUNCATE` when WAL is unavailable,
517
730
  such as on some NFS/SMB mounts. With the default `WAL` setting, AKM detects a
518
731
  network filesystem for the data directory and falls back to `DELETE`.
@@ -230,6 +230,14 @@ the set of types the code actually emits at HEAD (verified against every
230
230
  | `llm_usage_summary` | The owning LLM telemetry sink's terminal-record count marker | `expectedTerminalRecords` |
231
231
  | `health_probe` | `akm health`'s state.db round-trip write/read probe. **Not durably retained**: the row is inserted then deleted within the same connection once the round trip is confirmed, so the net effect on the `events` table is always zero rows | n/a (ephemeral) |
232
232
 
233
+ `llm_usage` rows also carry `process`/`engine`/`stage` (each optional; a call
234
+ made outside any attributed scope carries none of them). `akm improve`
235
+ (#944) aggregates a run's own `llm_usage` events into a process x engine x
236
+ model cross-tab — `summarizeLlmUsageCrossTab` in `src/commands/health/llm-usage.ts`
237
+ — persisted on the run result as `usageReport.byProcessEngineModel` and
238
+ queryable per-run or aggregated with `akm improve report`; see
239
+ `docs/reference/cli.md`'s `#### improve report` section.
240
+
233
241
  ### 2. Usage Events Table
234
242
 
235
243
  `usage_events` is the local analytical record behind utility ranking,
@@ -121,6 +121,20 @@ key in task source v4: `agent`, `engine`, `model`, `inference`, `tools`,
121
121
  number, or boolean values. Keep credentials out of task source; `redact`
122
122
  contains environment variable names, never secret values.
123
123
 
124
+ `timeout:` (milliseconds) means a different mechanism depending on the
125
+ target. For `run:` (native shell/script) and `workflows/<name>` targets it is
126
+ an outer supervisory deadline: the runner kills the child process, or aborts
127
+ the workflow run at its next step boundary, when it fires. For `uses:
128
+ akm/command`, `commands/<name>`, and any other agent/LLM dispatch target
129
+ there is no outer process kill — `timeout:` instead resolves through the
130
+ execution cascade (config/persona/command/task layers) into the dispatch's
131
+ own deadline, and the SDK/CLI runner races each phase against it internally.
132
+ Either way, a dispatch that times out is recorded as `status: failed` with
133
+ `detail.reason: "timeout"` in `task_history` — not a silent `completed` — and
134
+ `akm task run` exits non-zero for it; see [health-advisories.md's
135
+ `task-fail-rate` row](https://github.com/itlackey/akm/blob/main/docs/architecture/internals/health-advisories.md)
136
+ for how `akm health` surfaces a timeout-dominant failure pattern.
137
+
124
138
  ## Scheduling
125
139
 
126
140
  Scheduling is **optional**. Omit `schedule:` entirely for a manual-only
@@ -381,7 +395,8 @@ for full before/after examples and recovery guidance.
381
395
 
382
396
  ## Operations
383
397
 
384
- - `akm search --type task` and `akm show tasks/<id>` inspect task assets.
398
+ - `akm search --type task` (or its alias `akm task list`) and
399
+ `akm show tasks/<id>` inspect task assets.
385
400
  - `akm task explain <ref>` prints a task's declared inputs, resolved target,
386
401
  effective execution settings, and schedule bindings without running
387
402
  anything — see [`akm task explain`](#akm-task-explain) above.
@@ -1352,7 +1352,11 @@ optional user `models.json` files:
1352
1352
 
1353
1353
  Resolution checks the selected engine name or canonical harness column. A
1354
1354
  known alias without that column fails rather than guessing a provider model;
1355
- an unknown string is treated as an exact model selector. See the [Author's Guide](https://github.com/itlackey/akm/blob/main/docs/guides/author-workflows.md#choosing-engines-and-models)
1355
+ an unknown string is treated as an exact model selector. A column may itself
1356
+ be an `engine`-backed indirection (0.9.15) rather than a literal model string
1357
+ — see [Model-map files](configuration.md#model-map-files) — so a step naming
1358
+ `model: fast` also benefits from whatever engine-backed mapping the operator
1359
+ configured for the selected engine, with no workflow-authored change. See the [Author's Guide](https://github.com/itlackey/akm/blob/main/docs/guides/author-workflows.md#choosing-engines-and-models)
1356
1360
  for guidance on which tier to pick per step.
1357
1361
 
1358
1362
  ## See also
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akm-cli",
3
- "version": "0.9.14",
3
+ "version": "0.9.15-beta.2",
4
4
  "type": "module",
5
5
  "description": "akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cursor.",
6
6
  "keywords": [
@@ -9,6 +9,10 @@
9
9
  "type": "string",
10
10
  "const": "0.9.0"
11
11
  },
12
+ "extends": {
13
+ "type": "string",
14
+ "minLength": 1
15
+ },
12
16
  "engines": {
13
17
  "type": "object",
14
18
  "additionalProperties": {
@@ -207,6 +211,10 @@
207
211
  "type": "string",
208
212
  "minLength": 1
209
213
  },
214
+ "maxInputTokens": {
215
+ "type": "integer",
216
+ "exclusiveMinimum": 0
217
+ },
210
218
  "maxTokens": {
211
219
  "type": "integer",
212
220
  "exclusiveMinimum": 0
@@ -232,6 +240,15 @@
232
240
  }
233
241
  },
234
242
  "additionalProperties": true
243
+ },
244
+ "timeoutMs": {
245
+ "type": "integer",
246
+ "exclusiveMinimum": 0
247
+ },
248
+ "concurrency": {
249
+ "type": "integer",
250
+ "exclusiveMinimum": 0,
251
+ "maximum": 16
235
252
  }
236
253
  },
237
254
  "additionalProperties": true
@@ -1696,6 +1713,10 @@
1696
1713
  "type": "string",
1697
1714
  "const": "0.9.0"
1698
1715
  },
1716
+ "extends": {
1717
+ "type": "string",
1718
+ "minLength": 1
1719
+ },
1699
1720
  "engines": {
1700
1721
  "type": "object",
1701
1722
  "additionalProperties": {
@@ -1894,6 +1915,10 @@
1894
1915
  "type": "string",
1895
1916
  "minLength": 1
1896
1917
  },
1918
+ "maxInputTokens": {
1919
+ "type": "integer",
1920
+ "exclusiveMinimum": 0
1921
+ },
1897
1922
  "maxTokens": {
1898
1923
  "type": "integer",
1899
1924
  "exclusiveMinimum": 0
@@ -1919,6 +1944,15 @@
1919
1944
  }
1920
1945
  },
1921
1946
  "additionalProperties": true
1947
+ },
1948
+ "timeoutMs": {
1949
+ "type": "integer",
1950
+ "exclusiveMinimum": 0
1951
+ },
1952
+ "concurrency": {
1953
+ "type": "integer",
1954
+ "exclusiveMinimum": 0,
1955
+ "maximum": 16
1922
1956
  }
1923
1957
  },
1924
1958
  "additionalProperties": true
@@ -3463,6 +3497,10 @@
3463
3497
  "type": "string",
3464
3498
  "minLength": 1
3465
3499
  },
3500
+ "maxInputTokens": {
3501
+ "type": "integer",
3502
+ "exclusiveMinimum": 0
3503
+ },
3466
3504
  "maxTokens": {
3467
3505
  "type": "integer",
3468
3506
  "exclusiveMinimum": 0
@@ -3488,6 +3526,15 @@
3488
3526
  }
3489
3527
  },
3490
3528
  "additionalProperties": true
3529
+ },
3530
+ "timeoutMs": {
3531
+ "type": "integer",
3532
+ "exclusiveMinimum": 0
3533
+ },
3534
+ "concurrency": {
3535
+ "type": "integer",
3536
+ "exclusiveMinimum": 0,
3537
+ "maximum": 16
3491
3538
  }
3492
3539
  },
3493
3540
  "additionalProperties": true