akm-cli 0.9.16-alpha.1 → 0.9.16

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 (147) hide show
  1. package/CHANGELOG.md +56 -132
  2. package/dist/assets/hints/cli-hints-full.md +13 -6
  3. package/dist/assets/tasks/core/index-refresh.yml +1 -1
  4. package/dist/assets/tasks/improve/akm-improve-catchup.yml +3 -6
  5. package/dist/cli/retired-commands.js +0 -4
  6. package/dist/cli/unknown-flags.js +3 -36
  7. package/dist/commands/env/env-binding.js +4 -4
  8. package/dist/commands/env/env-cli.js +3 -3
  9. package/dist/commands/improve/collapse-detector.js +2 -2
  10. package/dist/commands/improve/consolidate.js +4 -6
  11. package/dist/commands/improve/improve-cli.js +20 -15
  12. package/dist/commands/improve/reflect.js +23 -2
  13. package/dist/commands/lint/base-linter.js +9 -0
  14. package/dist/commands/lint/env-key-rules.js +2 -2
  15. package/dist/commands/proposal/propose.js +15 -1
  16. package/dist/commands/proposal/repository.js +3 -12
  17. package/dist/commands/proposal/validators/proposal-quality-validators.js +40 -3
  18. package/dist/commands/proposal/validators/proposal-validators.js +5 -4
  19. package/dist/commands/read/curate.js +44 -34
  20. package/dist/commands/read/search.js +35 -54
  21. package/dist/commands/read/show.js +21 -2
  22. package/dist/commands/registry-cli.js +5 -5
  23. package/dist/commands/sources/add-cli.js +59 -16
  24. package/dist/commands/sources/bundle-cli.js +35 -11
  25. package/dist/commands/sources/bundle-config-ops.js +30 -0
  26. package/dist/commands/sources/dangerous-env-audit.js +4 -4
  27. package/dist/commands/sources/info.js +8 -8
  28. package/dist/commands/sources/installed-stashes.js +55 -61
  29. package/dist/commands/sources/source-add.js +39 -38
  30. package/dist/commands/sources/source-manage.js +34 -12
  31. package/dist/commands/sources/stash-cli.js +111 -119
  32. package/dist/commands/sources/stash-skeleton.js +6 -3
  33. package/dist/commands/tasks/explain.js +4 -1
  34. package/dist/commands/tasks/tasks-cli.js +31 -9
  35. package/dist/commands/tasks/tasks.js +239 -194
  36. package/dist/commands/tasks/validate.js +20 -32
  37. package/dist/core/activation-policy.js +4 -4
  38. package/dist/core/adapter/adapters/akm-adapter.js +8 -35
  39. package/dist/core/adapter/adapters/akm-metadata.js +1 -11
  40. package/dist/core/adapter/execution-source.js +10 -29
  41. package/dist/core/asset/asset-placement.js +0 -35
  42. package/dist/core/config/config-schema.js +64 -8
  43. package/dist/core/config/config-sources.js +96 -2
  44. package/dist/core/config/config.js +190 -24
  45. package/dist/core/config/legacy-source-shape-shim.js +9 -0
  46. package/dist/core/config/schema/embedding.js +30 -7
  47. package/dist/core/config/schema/execution.js +23 -0
  48. package/dist/core/config/schema/experimental.js +1 -1
  49. package/dist/core/config/schema/scheduler.js +20 -0
  50. package/dist/core/config/schema/search.js +10 -12
  51. package/dist/core/config/schema/sources-bundles.js +32 -1
  52. package/dist/core/content-safety.js +52 -0
  53. package/dist/core/errors.js +2 -5
  54. package/dist/core/maintenance-barrier.js +11 -13
  55. package/dist/core/paths.js +11 -0
  56. package/dist/core/run-lock.js +2 -5
  57. package/dist/core/state/migrations.js +1 -26
  58. package/dist/core/state-db.js +27 -63
  59. package/dist/core/type-presentation.js +1 -1
  60. package/dist/core/write-source.js +13 -8
  61. package/dist/indexer/bundle-identity-guard.js +45 -8
  62. package/dist/indexer/ensure-index.js +0 -5
  63. package/dist/indexer/index-db-contention.js +56 -0
  64. package/dist/indexer/index-rebuild-lock.js +73 -0
  65. package/dist/indexer/index-written-assets.js +171 -133
  66. package/dist/indexer/indexer.js +1621 -458
  67. package/dist/indexer/lookup/adapter-concept-owner.js +5 -19
  68. package/dist/indexer/materialize-embeddings.js +785 -0
  69. package/dist/indexer/passes/dir-staleness.js +161 -0
  70. package/dist/indexer/passes/metadata.js +1 -18
  71. package/dist/indexer/scan/drain-dir.js +70 -27
  72. package/dist/indexer/search/db-search.js +89 -373
  73. package/dist/indexer/search/ranking-contributors.js +16 -21
  74. package/dist/indexer/search/ranking.js +57 -135
  75. package/dist/indexer/search/search-source.js +29 -11
  76. package/dist/integrations/agent/execution-lowering.js +3 -2
  77. package/dist/integrations/agent/execution-preparation.js +32 -1
  78. package/dist/integrations/agent/prompts.js +1 -1
  79. package/dist/integrations/agent/request-lowering.js +3 -2
  80. package/dist/llm/client.js +3 -11
  81. package/dist/llm/embedder.js +3 -10
  82. package/dist/llm/embedders/remote.js +104 -133
  83. package/dist/llm/feature-gate.js +2 -4
  84. package/dist/llm/rerank-client.js +3 -3
  85. package/dist/output/html-render.js +2 -1
  86. package/dist/output/shapes/passthrough.js +2 -1
  87. package/dist/output/stdout.js +24 -0
  88. package/dist/output/text/command-format.js +13 -19
  89. package/dist/output/text/helpers.js +1 -1
  90. package/dist/output/text/index.js +2 -5
  91. package/dist/output/text.js +4 -3
  92. package/dist/registry/resolve.js +37 -10
  93. package/dist/scripts/akm-migrate-node.js +15197 -11351
  94. package/dist/scripts/akm-migrate.js +15514 -11668
  95. package/dist/setup/semantic-assets.js +2 -2
  96. package/dist/setup/setup.js +3 -3
  97. package/dist/setup/steps/connection.js +2 -3
  98. package/dist/setup/steps/tasks.js +29 -36
  99. package/dist/sources/providers/git-install.js +17 -11
  100. package/dist/sources/providers/git-provider.js +12 -5
  101. package/dist/sources/providers/git-stash.js +38 -16
  102. package/dist/sources/snapshot-fetchers/website-ingest.js +3 -3
  103. package/dist/storage/repositories/embedding-salvage-repository.js +184 -0
  104. package/dist/storage/repositories/index-connection.js +3 -1
  105. package/dist/storage/repositories/index-entries-repository.js +68 -77
  106. package/dist/storage/repositories/index-entry-schema.js +25 -16
  107. package/dist/storage/repositories/index-fts-repository.js +263 -29
  108. package/dist/storage/repositories/index-meta-repository.js +29 -0
  109. package/dist/storage/repositories/index-schema.js +122 -115
  110. package/dist/storage/repositories/index-utility-repository.js +1 -1
  111. package/dist/storage/repositories/index-vec-repository.js +435 -22
  112. package/dist/tasks/activation-config.js +90 -0
  113. package/dist/tasks/backends/cron.js +9 -0
  114. package/dist/tasks/backends/launchd.js +1 -0
  115. package/dist/tasks/backends/schtasks.js +2 -0
  116. package/dist/tasks/embedded.js +4 -5
  117. package/dist/tasks/scheduler-binding.js +2 -2
  118. package/dist/tasks/scheduler-sync-preview.js +8 -1
  119. package/dist/tasks/scheduler-sync.js +19 -10
  120. package/dist/tasks/source/parse-task-source.js +10 -113
  121. package/dist/tasks/source/project-v4.js +2 -2
  122. package/dist/tasks/source/task-source-v4.js +4 -12
  123. package/dist/tasks/source/task-to-v3.js +4 -12
  124. package/dist/tasks/source/task-to-v4.js +40 -7
  125. package/docs/migration/README.md +1 -0
  126. package/docs/migration/release-notes/0.9.15.md +36 -34
  127. package/docs/migration/release-notes/0.9.16.md +60 -98
  128. package/docs/migration/release-notes/README.md +0 -5
  129. package/docs/migration/v0.9.1-to-v0.9.2.md +6 -9
  130. package/docs/reference/cli.md +124 -122
  131. package/docs/reference/configuration.md +137 -133
  132. package/docs/reference/data-and-telemetry.md +1 -2
  133. package/docs/reference/tasks.md +34 -29
  134. package/package.json +1 -1
  135. package/schemas/akm-config.json +170 -6
  136. package/schemas/akm-task.json +1 -2
  137. package/dist/commands/sources/index-status.js +0 -99
  138. package/dist/core/hash.js +0 -18
  139. package/dist/indexer/drain.js +0 -306
  140. package/dist/indexer/embedding-identity.js +0 -20
  141. package/dist/indexer/enrich.js +0 -260
  142. package/dist/indexer/reconcile.js +0 -890
  143. package/dist/indexer/scan/parse-file.js +0 -66
  144. package/dist/indexer/units/unit.js +0 -159
  145. package/dist/llm/embedders/provider-limits.js +0 -288
  146. package/dist/storage/repositories/files-repository.js +0 -181
  147. package/dist/storage/repositories/units-repository.js +0 -510
@@ -16,14 +16,13 @@ auto-upgrade in memory (see "Version read shim" below). Missing, newer,
16
16
  numeric, and any other unrecognized version are rejected by ordinary
17
17
  commands without rewriting the file — an older binary never guesses at a
18
18
  newer, unknown shape. Pre-0.9 config and database layouts are not runtime
19
- inputs and are not migrated by `akm upgrade`. Configure the current schema
20
- directly. The standalone migrator exists only for explicit task migration:
21
- task v2 to task v3, then task v3 to task source v4, in one pass.
19
+ inputs. Historical task sources and scheduler activation are handled by the
20
+ standalone `akm-migrate` executable, also invoked by `akm migrate` / `akm
21
+ upgrade`; ordinary runtime code reads only the current shape.
22
22
 
23
23
  ### Version read shim
24
24
 
25
- Like the task-source v2/v3 auto-shim (`akm migrate apply`'s in-memory
26
- counterpart, documented under Migration below), a known older `configVersion`
25
+ For config only, a known older `configVersion`
27
26
  is converted to the current shape in memory on load — with a one-line stderr
28
27
  deprecation warning — rather than hard-failing every command. Nothing is
29
28
  written back to disk by the shim itself; the very next config-mutating
@@ -64,6 +63,9 @@ the first bump that will need it, per #863.
64
63
  "maxConcurrency": 8,
65
64
  "judgeEngine": "reviewer"
66
65
  },
66
+ "execution": {
67
+ "allowedTools": ["read_file", "search"]
68
+ },
67
69
  "improve": {
68
70
  "strategies": {
69
71
  "nightly": {
@@ -78,6 +80,25 @@ the first bump that will need it, per #863.
78
80
  }
79
81
  ```
80
82
 
83
+ ## Scheduler activation
84
+
85
+ `scheduler.enabled` is this host's explicit scheduling allow-list. Each entry
86
+ has a `kind` (`task` or `workflow`), a canonical fully qualified `ref`, and a
87
+ `sourceId` binding the grant to the configured source installation that was
88
+ approved. Absence means disabled. Replacing a bundle's path or locator under
89
+ the same name invalidates the old grant; ordinary updates from the same origin
90
+ do not. Authored task/workflow files may describe schedules but cannot grant
91
+ themselves authority to create native scheduler entries. Do not edit
92
+ `sourceId` manually: `akm task enable` writes it, and `akm migrate apply`
93
+ upgrades grants written by older releases.
94
+
95
+ This key is deliberately local: if a config uses `extends`, any `scheduler`
96
+ section in the base is ignored with a warning. Only the top-level local config
97
+ can activate schedules. Prefer `akm task enable <ref>` and `akm task disable
98
+ <ref>` over editing the JSON by hand; both update the allow-list and sync the
99
+ affected bundle. An unscoped `akm task sync` reconciles enabled refs across all
100
+ enabled configured bundles.
101
+
81
102
  ## Engines
82
103
 
83
104
  `engines` is the only public execution map. An engine name is lowercase
@@ -112,6 +133,12 @@ An agent engine may set `bin`, `args`, `workspace`, `model`, and `timeoutMs`.
112
133
  Only `platform: "opencode-sdk"` may set `llmEngine`; it names
113
134
  the LLM engine used as that SDK engine's fallback connection.
114
135
 
136
+ Executable assets may request tools, but the request is not authority. Configure
137
+ the host-local `execution.allowedTools` list to define the ceiling; `"*"` is an
138
+ explicit allow-all. The default is an empty list. Asset frontmatter cannot set
139
+ `workspace`, `environment`, or opaque `runtime` values; those belong to local
140
+ engine configuration or workflow environment bindings.
141
+
115
142
  `platform: "opencode-sdk"` needs the **`opencode` binary** on PATH (or a `bin`
116
143
  pointing at it). akm bundles `@opencode-ai/sdk`, but that package is an HTTP
117
144
  client with no dependencies — it spawns `opencode serve` and talks to it — so
@@ -357,17 +384,11 @@ bundled.
357
384
  ## Indexing
358
385
 
359
386
  AKM-native Markdown contributes a normalized body projection to the
360
- lowest-weight `content` search field. The projection removes frontmatter,
361
- comments, fenced code, and link destinations, and is never produced for
362
- secret, env, session, or session-checkpoint assets.
363
-
364
- Embedding input is not capped or truncated at all (index redesign): each
365
- entry's structured fields (name/description/tags/hints) become one "card"
366
- unit and each Markdown fragment becomes one "fragment" unit
367
- (`src/indexer/units/unit.ts`), and a unit whose text would still exceed the
368
- embedding provider's own probed window is split into ordinal sub-units that
369
- share its fragment id — never truncated. See [Semantic
370
- search](#semantic-search) for how that window is probed.
387
+ lowest-weight `content` search field. The projection is capped at 16,384
388
+ characters, removes frontmatter, comments, fenced code, and link destinations,
389
+ and is never produced for secret, env, session, or session-checkpoint assets.
390
+ Embedding input is separately capped at 8,192 characters with structured
391
+ metadata placed before body content.
371
392
 
372
393
  ## Semantic search
373
394
 
@@ -402,80 +423,76 @@ unless a remote `embedding` config is provided.
402
423
  `akm improve`'s memory-inference/consolidate passes when they call an
403
424
  embedding model: `provider`, `endpoint`, `model`, `apiKey` (symbolic
404
425
  reference, same rules as engine `apiKey`), `dimension`, `localModel`,
405
- `timeoutMs`, `concurrency`, and `ollamaOptions.num_ctx`.
406
-
407
- Request PACKING — how many documents land in one HTTP request, and the
408
- token budget that bounds it — is no longer config at all. `akm index`
409
- probes the embedding endpoint itself (llama.cpp's `GET /props`, Ollama's
410
- `POST /api/show`) for its real context window and in-flight slot count
411
- before packing any request, calibrating its chars-per-token estimate
412
- against the provider's own tokenizer (llama.cpp's `/tokenize`) where it
413
- offers one; an endpoint that answers neither probe (an OpenAI-compatible server, a gateway) gets a
414
- conservative built-in default. This replaced four retired keys —
415
- `maxInputTokens`, `maxTokens`, `batchSize`, `contextLength` — see
416
- [Retired Configuration](#retired-configuration).
417
-
418
- The knobs that remain, both optional (defaults apply when unset), for a
419
- remote endpoint (`src/llm/embedders/remote.ts`):
426
+ `maxInputTokens`, `maxTokens`, `batchSize`, `contextLength`, `timeoutMs`,
427
+ `concurrency`, and `ollamaOptions.num_ctx`.
428
+
429
+ The knobs that bound request/document size and rate, all optional (defaults
430
+ apply when unset), for a remote endpoint (`src/llm/embedders/remote.ts`):
420
431
 
421
432
  | Key | Default | Bounds |
422
433
  | --- | --- | --- |
434
+ | `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. |
435
+ | `embedding.maxTokens` | `6000` (`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 11 documents by default. Lowered from 8000 to 6000 (#954): the 4-chars-per-token estimator undercounts dense technical text by 7-55%, so 8000 regularly overshot an 8192-token endpoint's real context window. |
436
+ | `embedding.batchSize` | `100` | Per-REQUEST document-COUNT safety cap, independent of the token budget — guards against many tiny documents packing an oversized request. |
437
+ | `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. |
423
438
  | `embedding.timeoutMs` | `120000` (120s) | Per-request wall timeout — see below. |
424
- | `embedding.concurrency` | `1` loopback / `2` remote, or the provider's own probed slot count | In-flight request window — see below. |
425
-
426
- **What used to fix the field's 8k-context overflow.** A 0.9.15-beta field
427
- report described documents estimated under the request budget that still
428
- tokenized to 8.5k-12.4k real tokens against an 8192-token endpoint, because
429
- the 4-chars-per-token estimator undercounts dense technical text.
430
- 0.9.15-beta answered it with three of the four now-retired keys; none of
431
- them does anything in this release (see [Retired
432
- Configuration](#retired-configuration)), but the shape of the old fix is
433
- worth knowing because the probed-window replacement above closes the same
434
- gap structurally instead of by convention:
435
-
436
- - `embedding.maxInputTokens: 512` used to be a per-DOCUMENT cap, applied
437
- before batching. This was the actual fix for the original overflow: no
438
- single document could contribute more than 512 estimated tokens to a
439
- request, no matter how `maxTokens` or `contextLength` were set.
440
- - `embedding.maxTokens: 6000` used to be the per-REQUEST budget: how many
441
- already-capped documents' estimated tokens fit in one HTTP request. A
442
- request-level budget alone could not stop one oversized document from
443
- overflowing a request — only the per-document cap above did that.
444
- - `embedding.contextLength: 8192` fed only Ollama's `num_ctx`, forwarded
445
- verbatim on a native `/api/embed` request. It never bounded request or
446
- document sizing, and had no effect at all against a non-Ollama endpoint.
447
-
448
- None of the three is read any more. A field config still carrying
449
- `contextLength: 8192` + `maxTokens: 8000` (the exact 0.9.15-beta values
450
- from the original report) loads on this release without error and without
451
- effect — the same "ignored, unvalidated, no warning" handling every retired
452
- key gets (see below) — because `akm index` now probes the endpoint's real
453
- context window itself and packs every request against that instead of
454
- against a configured estimate, so the original overflow is unreachable
455
- regardless of what either retired key is set to.
439
+ | `embedding.concurrency` | `1` loopback / `2` remote | In-flight request window — see below. |
440
+
441
+ **Which knob fixed the field's 8k-context overflow, worked examples.** A
442
+ 0.9.15-beta field report described documents estimated under the request
443
+ budget that still tokenized to 8.5k-12.4k real tokens against an
444
+ 8192-token endpoint, because the 4-chars-per-token estimator undercounts
445
+ dense technical text. Three knobs changed shape between beta and this
446
+ release; only one of them makes that overflow structurally unreachable:
447
+
448
+ - `embedding.maxInputTokens: 512` — per-DOCUMENT cap, applied before
449
+ batching. Example: a 6,000-character API reference page is truncated to
450
+ its first ~2,000 characters (512 estimated tokens) before it is ever
451
+ counted toward a request. This is the fix for the original overflow: no
452
+ single document can contribute more than 512 estimated tokens to a
453
+ request, no matter how `maxTokens` or `contextLength` are set.
454
+ - `embedding.maxTokens: 6000` — per-REQUEST budget: how many already-capped
455
+ documents' estimated tokens fit in one HTTP request. Example: with the
456
+ default 512-token document cap, a request packs about 11 documents before
457
+ this budget is reached and the request is sent; if the run's first
458
+ request is still rejected for exceeding the endpoint's real context
459
+ window, akm shrinks this budget to three quarters of its value (floored
460
+ at twice `maxInputTokens`) for every later request in the same run. A
461
+ request-level budget alone cannot stop one oversized document from
462
+ overflowing a request — only the per-document cap above does that.
463
+ - `embedding.contextLength: 8192` — Ollama's `num_ctx` only, forwarded
464
+ verbatim on a native `/api/embed` request. It has no effect on request or
465
+ document sizing, and no effect at all against a non-Ollama endpoint — see
466
+ below for why that used not to be true.
467
+
468
+ A field config of `contextLength: 8192` + `maxTokens: 8000` (the exact
469
+ 0.9.15-beta values from the original report) produces no 400s on 0.9.15:
470
+ `maxInputTokens` (512, new this release) caps every document before it is
471
+ counted, so the original 8.5k-12.4k-token documents that overflowed the
472
+ 8192-token endpoint can never reach the request budget in the first place —
473
+ independent of whatever `maxTokens` or `contextLength` are set to.
456
474
 
457
475
  `embedding.timeoutMs` (positive integer, default `120000` — 120s) is the
458
- budget for a request at the FULL (probed) token budget; a local model
459
- server on a large, token-budget-bounded batch legitimately takes longer
460
- than the prior fixed 30s cut off. A smaller request gets a proportionally
461
- smaller timeout —
476
+ budget for a request at the FULL token budget (`embedding.maxTokens`); a
477
+ local model server on a large, token-budget-bounded batch legitimately takes
478
+ longer than the prior fixed 30s cut off. A smaller request gets a
479
+ proportionally smaller timeout —
462
480
  `clamp(timeoutMs × requestTokens / tokenBudget, 30000, timeoutMs)` — so a
463
481
  dead endpoint is still detected in seconds on the common case of small
464
482
  documents. Set `embedding.timeoutMs` lower to fail fast against a
465
483
  known-fast endpoint, or higher for a slow local server on large batches.
466
484
 
467
- The probed token budget is also a run-scoped adaptive starting point, not a
468
- hard ceiling, but ONLY when the endpoint did not report a real window of
469
- its own (an OpenAI-compatible server or gateway, the conservative built-in
470
- default): on the FIRST rejection of an `akm index` run for exceeding the
471
- endpoint's context window, akm shrinks the request budget to three quarters
472
- of its current value for every request not yet sent, and prints one line
473
- naming the new value. A window akm actually probed from the endpoint
474
- (llama.cpp, Ollama) is treated as authoritative and is never second-guessed
475
- this way — a rejection against it still recovers via the same
476
- split-and-retry every rejection gets (below), just without lowering the
477
- budget for the rest of the run. This never fires a second time in the same
478
- run either way.
485
+ `embedding.maxTokens` (or its default) is also a run-scoped adaptive
486
+ starting point, not a hard ceiling (#954): on the FIRST rejection of an
487
+ `akm index` run for exceeding the endpoint's context window, akm shrinks
488
+ the request budget to three quarters of its current value — floored at
489
+ twice `embedding.maxInputTokens` — for every request not yet sent, and
490
+ prints one line naming the new value. This never changes the rejected
491
+ request's own split-and-retry (below), never shrinks a second time in the
492
+ same run, and never grows the budget back up. Users who set
493
+ `embedding.maxTokens` explicitly are unaffected by the LOWERED DEFAULT
494
+ above but still benefit from this same-run recovery if their own value
495
+ turns out to be too high for the endpoint.
479
496
 
480
497
  A request TIMEOUT (not a rejection for exceeding the context window) never
481
498
  drops its batch immediately: field confirmation showed that once akm
@@ -495,17 +512,19 @@ requests and reports failure — batches already committed are kept; rerun
495
512
  once (a remote endpoint only; the local transformer path is unaffected):
496
513
  `1` for a loopback endpoint (`localhost`, `127.0.0.0/8`, etc. — a local
497
514
  model server serves one inference at a time, and parallel requests thrash
498
- it) and `2` for a remote one, unless the provider's own probed slot count
499
- (llama.cpp's `total_slots`) or `embedding.concurrency` (positive integer,
500
- 1-16, checked first) overrides it. This default holds for the overwhelming
501
- majority of setups; set an explicit override only for an endpoint that
502
- genuinely serves parallel requests — a local server started with a
503
- multi-slot flag (llama.cpp's `--parallel N`, vLLM) — not to "speed up" an
504
- ordinary single-slot model server, which the default already protects from
515
+ it) and `2` for a remote one, unless `embedding.concurrency` (positive
516
+ integer, 1-16) overrides it. This default holds for the overwhelming
517
+ majority of setups; set the override only for an endpoint that genuinely
518
+ serves parallel requests — a local server started with a multi-slot flag
519
+ (llama.cpp's `--parallel N`, vLLM) — not to "speed up" an ordinary
520
+ single-slot model server, which the default already protects from
505
521
  reload-thrash. Request SIZE remains the first throughput lever regardless:
506
- the probed token budget and document-count cap described above control how
507
- many documents land in one request, taking about the same wall time as a
508
- single one against a healthy endpoint.
522
+ `embedding.batchSize` (a document-count cap, default 100) together with
523
+ `embedding.maxTokens` (an estimated token budget per request, default 6000
524
+ — NOT `embedding.contextLength`, see the table above) control how many
525
+ documents land in one request — with the default 512-token
526
+ `embedding.maxInputTokens` document cap, that is about 11 documents,
527
+ taking about the same wall time as a single one against a healthy endpoint.
509
528
 
510
529
  ## Search tuning
511
530
 
@@ -513,6 +532,7 @@ single one against a healthy endpoint.
513
532
 
514
533
  | Key | Purpose |
515
534
  | --- | --- |
535
+ | `search.minScore` | Drop results below this score |
516
536
  | `search.defaultExcludeTypes` | Asset types excluded from results by default |
517
537
 
518
538
  ### Graph boost search tuning
@@ -521,35 +541,22 @@ single one against a healthy endpoint.
521
541
  | --- | --- |
522
542
  | `search.graphBoost.*` | Entity-graph relevance boost: `directBoostPerEntity`/`directBoostCap` (directly related entities), `hopBoostPerEntity`/`hopBoostCap` (multi-hop, capped at `maxHops` ≤ 3), `confidenceMode` (`blend`, the only supported value), `confidenceWeight` (0–1, default `0.2`) |
523
543
 
524
- ### Search rerank (#951)
525
-
526
- An optional cross-encoder rerank pass over `akm search`'s already-ranked
527
- LOCAL stash hits, via a standalone `/rerank`-style HTTP endpoint (NOT one of
528
- the `engines.*` `"llm"`/`"agent"` kinds). Disabled by default; a
529
- misconfigured endpoint, network failure, timeout, or malformed response
530
- falls back to search's own ranking unchanged. Applied once to local hits
531
- before `--from local`/`--from all` diverge, so both see the reranked order
532
- and neither double-applies it; registry hits (`--from registry`, and the
533
- registry half of `--from all`) are never reranked and never trigger the
534
- endpoint — registry results staying separate from stash hits is a locked
535
- contract (AGENTS.md).
544
+ ### Curate rerank (#951)
536
545
 
537
- Reranking changes hit ORDER only. Each hit's `score` is left as the
538
- retrieval score `akm search` already computed — see the score-vs-order note
539
- in `docs/reference/cli.md`'s search section for why.
540
-
541
- Moved here from `akm curate` in 0.9.16 (`search.curateRerank` →
542
- `search.rerank`) — the pass was always meant for search, not curate; see
543
- `docs/migration/release-notes/0.9.16.md`.
546
+ An optional cross-encoder rerank pass over `akm curate`'s already-selected
547
+ candidates, via a standalone `/rerank`-style HTTP endpoint (NOT one of the
548
+ `engines.*` `"llm"`/`"agent"` kinds). Disabled by default; a misconfigured
549
+ endpoint, network failure, timeout, or malformed response falls back to
550
+ curate's own ranking unchanged.
544
551
 
545
552
  | Key | Purpose |
546
553
  | --- | --- |
547
- | `search.rerank.enabled` | Turn the rerank pass on (default `false`) |
548
- | `search.rerank.endpoint` | Full URL of the reranker's rerank endpoint |
549
- | `search.rerank.model` | Model name sent to the endpoint (optional) |
550
- | `search.rerank.apiKey` | `$VAR`/`secret://<name>` credential reference (optional) |
551
- | `search.rerank.timeoutMs` | Request timeout (default `10000`) |
552
- | `search.rerank.topN` | How many of search's ranked LOCAL hits to send (default `8`, max `50`) |
554
+ | `search.curateRerank.enabled` | Turn the rerank pass on (default `false`) |
555
+ | `search.curateRerank.endpoint` | Full URL of the reranker's rerank endpoint |
556
+ | `search.curateRerank.model` | Model name sent to the endpoint (optional) |
557
+ | `search.curateRerank.apiKey` | `$VAR`/`secret://<name>` credential reference (optional) |
558
+ | `search.curateRerank.timeoutMs` | Request timeout (default `10000`) |
559
+ | `search.curateRerank.topN` | How many of curate's ranked candidates to send (default `8`, max `50`) |
553
560
 
554
561
  ## Feedback
555
562
 
@@ -571,6 +578,12 @@ bundle's `components.<id>.adapter` key pins it to a specific format adapter
571
578
  instead of relying on auto-detection — see [Bundle Types](bundle-types.md)
572
579
  for the full adapter list and what each one reads/writes.
573
580
 
581
+ Each physical content root has one bundle id. Duplicate paths and symbolic-link
582
+ aliases are rejected because source ownership, scheduler authority, and default
583
+ selection must not depend on which spelling a caller used. If an older config
584
+ contains aliases, choose the id whose durable refs should survive and remove
585
+ the other entry before running ordinary commands.
586
+
574
587
  ### defaultWriteTarget
575
588
 
576
589
  `defaultWriteTarget` names the bundle that write commands (`akm remember`,
@@ -720,6 +733,16 @@ one file, and have each host's local config extend it.
720
733
  add`/`akm sync` first so the file is materialized locally, then point
721
734
  `extends` at it.
722
735
 
736
+ Shared layers carry portable policy, not host authority. `bundles`, source and
737
+ write defaults, registries, embedding connections, scheduler grants,
738
+ `execution`, `experimental`, and setup state are ignored when inherited.
739
+ Engine definitions may be shared, but credentials and executable authority
740
+ (`apiKey`, `apiKeyFile`, `bin`, `args`, and `workspace`) must be supplied by
741
+ the local file. Improve publication (`strategies.*.sync`) and reranker network
742
+ configuration are local as well. Bundle-relative chains stay physically inside
743
+ the bundle root for every hop; lexical `..` paths and symlink escapes are both
744
+ rejected before a referenced file is read.
745
+
723
746
  There is no `extends: <url>` form: config load is synchronous and runs on
724
747
  every invocation, and akm deliberately does not fetch network resources at
725
748
  load time (the same reason `registries` is never fetched until a
@@ -824,22 +847,3 @@ profile identities.
824
847
  `embedding.chunkSize` was never read by anything under `src/` (#954), so a
825
848
  config that still sets it is simply ignored — it still loads, unvalidated
826
849
  and without warning.
827
-
828
- `search.minScore` was never read by anything under `src/` as of 0.9
829
- (index-redesign B5c), so a config that still sets it is simply ignored — it
830
- still loads, unvalidated and without warning. It used to tune a
831
- semantic-only floor over the old entries_fts + entries_vec search path,
832
- calibrated for that path's 0-1 cosine/BM25 scores. The single search path is
833
- `units_fts` + `units_vec`, scoring lexical evidence by BM25 magnitude and
834
- semantic evidence by cosine similarity on the same 0.7/0.3 split as before,
835
- on the scale the ranking contributors expect — no separate floor is applied.
836
-
837
- `embedding.maxInputTokens`, `embedding.maxTokens`, `embedding.batchSize`,
838
- and `embedding.contextLength` are retired (index redesign): `akm index`
839
- packs requests against the embedding provider's own probed context window
840
- and slot count instead (see [Semantic search](#semantic-search)). A config
841
- that still sets any of them is simply ignored — it still loads, unvalidated
842
- and without warning, the same as `embedding.chunkSize` above.
843
- `embedding.contextLength` specifically fed Ollama's `num_ctx`; that request
844
- field is now sent automatically from the same probe, or set explicitly via
845
- `embedding.ollamaOptions.num_ctx`.
@@ -208,8 +208,7 @@ the set of types the code actually emits at HEAD (verified against every
208
208
  | `events_purged` | Old events deleted by improve maintenance (90-day default retention) | `purgedCount`, `retentionDays` |
209
209
  | `improve_runs_purged` | Old `improve_runs` rows deleted by improve maintenance (same retention window as events) | `purgedCount`, `retentionDays` |
210
210
  | `improve_cycle_metrics_purged` | Old `improve_cycle_metrics` rows (365-day retention) deleted by improve maintenance | `purgedCount`, `retentionDays` |
211
- | `task_logs_purged` | Old task-log rows (log lines in `logs.db`) deleted by improve maintenance | `purgedCount`, `retentionDays` |
212
- | `task_log_files_purged` | Old per-run flat task log files (the transitional `<taskId>/<timestamp>.log` tail files under the task log dir) deleted by improve maintenance | `purgedCount`, `retentionDays` |
211
+ | `task_logs_purged` | Old scheduled-task log files purged by improve maintenance | |
213
212
 
214
213
  *Workflows*
215
214
 
@@ -148,12 +148,10 @@ name: Nightly review
148
148
  run: akm improve --strategy default
149
149
  schedule:
150
150
  - cron: "@daily"
151
- enabled: false
152
151
  ```
153
152
 
154
- A bare string (`schedule: "0 8 * * 1"`) is shorthand for one enabled
155
- binding with no inputs. A list entry may set its own `enabled` (default
156
- `true`) and literal `inputs`; those literals are validated against the
153
+ A bare string (`schedule: "0 8 * * 1"`) is shorthand for one trigger with
154
+ no inputs. A list entry may set literal `inputs`; those literals are validated against the
157
155
  task's `inputs:` declarations both at parse time and again at
158
156
  `akm task sync` (once with declared defaults applied), and are
159
157
  **delivered** to the scheduled run: `akm task sync` compiles each entry's
@@ -163,18 +161,26 @@ fired run receives them exactly as `akm task run <id> --<name> <value>`
163
161
  would. Multiple schedule entries create deterministic scheduler bindings
164
162
  for the one source task.
165
163
 
166
- Task source v4 has **no document-level `enabled` flag** — enablement is
167
- per schedule binding. Disable one binding by setting its own
168
- `enabled: false`. `--schedule` is a required flag on every `akm task add`
169
- invocation, `--disabled` included — not a check specific to `--disabled` —
170
- so `akm task add --disabled` always has a schedule to write `enabled: false`
171
- onto and never needs to reject a schedule-less task with "nothing to
172
- disable."
164
+ Task source v4 has **no enablement flag**. A source describes what may run;
165
+ it cannot authorize its own host scheduling. Activation is an exact,
166
+ host-local allow-list in `config.json` under `scheduler.enabled`, keyed by
167
+ asset kind, fully qualified ref, and the approved source installation identity.
168
+ Absence means disabled. A removed, disabled, or replaced bundle cannot reuse a
169
+ grant written for an earlier source under the same name. Use `akm task
170
+ enable <bundle>//tasks/<id>` and `akm task disable <bundle>//tasks/<id>` to
171
+ change that list and immediately sync the affected bundle. `akm task add`
172
+ enables its new task by default; `--disabled` writes the same task source but
173
+ does not add the local activation.
173
174
 
174
175
  `akm task run <id>` executes a task immediately, including a disabled task.
175
- `akm task sync` validates the complete desired set before atomically
176
- reconciling scheduler state. Scheduled invocations re-read the guarded current
177
- task bytes; workflow targets then create a fresh durable workflow freeze.
176
+ `akm task sync` scans every enabled configured bundle, selects only locally
177
+ activated task/workflow refs, validates the complete desired set, and then
178
+ atomically reconciles scheduler state. `--bundle <name>` narrows that pass to
179
+ one active bundle. If every configured bundle is disabled, sync removes the
180
+ attributable native entries without reading task content. Scheduled task
181
+ invocations check both the local activation and current source identity again at
182
+ fire time before re-reading the guarded current task bytes; workflow targets
183
+ then create a fresh durable workflow freeze.
178
184
 
179
185
  ## Typed inputs and output
180
186
 
@@ -200,7 +206,6 @@ output:
200
206
  uses: commands/review
201
207
  schedule:
202
208
  - cron: "0 8 * * 1"
203
- enabled: true
204
209
  inputs: { scope: all, ticket: OPS-1234 }
205
210
  timeout: 45000
206
211
  engine: reviewer
@@ -229,9 +234,7 @@ redact: [TOKEN]
229
234
  field path (`schedule`, or `schedule[<i>]`), naming the unsatisfied
230
235
  input. The rule covers every entry: the `schedule: "<cron>"` string
231
236
  shorthand, a list entry with no `inputs:` key, and an entry whose
232
- `inputs:` mapping is present but incomplete — including one written
233
- `enabled: false`, so enabling it later can never turn a parsed document
234
- unrunnable. `akm task sync` keeps its own equivalent check over the
237
+ `inputs:` mapping is present but incomplete. `akm task sync` keeps its own equivalent check over the
235
238
  defaulted values and still rejects the whole desired set before touching
236
239
  any scheduler state. Give every schedule entry an explicit value for the
237
240
  input, or declare a `default` instead; manual runs are unaffected — a
@@ -343,7 +346,8 @@ Common v2 → v3 blocked reasons and what to do about each — these need a
343
346
  hand-authored replacement, not a re-run; see [the 0.9.1 to 0.9.2 migration
344
347
  guide](../migration/v0.9.1-to-v0.9.2.md#v2--v3-blocked-cases) for the full v2
345
348
  to v4 field mapping (`command:` array → `run:` + `shell:`, `timeoutMs:` →
346
- `timeout:`, document-level `enabled:` → per-`schedule:`-entry `enabled`):
349
+ `timeout:`). Source-owned `enabled` fields are removed; native bindings that
350
+ are provably enabled seed the host-local activation list:
347
351
 
348
352
  | Reason | Meaning | Fix |
349
353
  |---|---|---|
@@ -357,7 +361,6 @@ Common v3 → v4 blocked reasons and what to do about each:
357
361
  | `github-action-target-removed` | The task's `uses:` is a GitHub Action locator (`owner/repo[/path]@ref`); that spelling has no task source v4 equivalent. | Rewrite the target as `commands/`, `scripts/`, `workflows/`, or `akm/command` by hand. |
358
362
  | `with-on-non-command-target` | A `with:` block is authored on a target other than `uses: akm/command`. | Task-call inputs are declared and bound separately in v4 — author `inputs:` on the task and, if it is a workflow step's own composition, bind them with the step's `with:` instead. |
359
363
  | `ambiguous-scheduling-source` | The document declares both `akm.schedule` and `on:`. | Pick one; the migrator will not guess which one wins. |
360
- | `enabled-false-has-no-schedule-entry` | `akm.enabled: false` with no cron trigger to attach it to (the only trigger is `on.workflow_dispatch`). | Task source v4 has no document-level `enabled` flag — decide whether the task should be scheduled (add a cron) or left manual-only (drop `akm.enabled`), then re-run. |
361
364
  | `read-only-source` | The owning source or file is not writable. | Move or re-source the file somewhere writable, or edit it by hand. |
362
365
  | `invalid-v3-task` | The v3 document itself is structurally invalid (unknown fields, missing selector, malformed trigger, etc). | Fix the underlying v3 document first — the migrator translates structure, it does not repair it. |
363
366
  | `generated-v4-validation-failed` | The converted bytes fail the real task source v4 parser; the detail carries the parse error. | Read the detail — it names the offending field and why v4 refuses it — then fix that field in the v3 file and preview again. |
@@ -402,20 +405,20 @@ for full before/after examples and recovery guidance.
402
405
  anything — see [`akm task explain`](#akm-task-explain) above.
403
406
  - `akm task validate <path>` parses one task file by filesystem path (the
404
407
  file need not live in a configured bundle) and reports the same
405
- `valid`/`converts`/`blocked`/`invalid`/`not-a-task` diagnostic
408
+ `valid`/`blocked`/`invalid`/`not-a-task` diagnostic
406
409
  `akm task sync` would produce for it — including sync's own cron-dialect
407
410
  check and its per-schedule-entry input-contract check — without touching
408
411
  the scheduler and without requiring a configured engine, even for a
409
412
  command-kind task. The envelope's own `sourceVersion` field names the
410
- file's originally declared schema version (2, 3, or 4).
413
+ file's declared schema version. Version 2/3 files are `blocked` with an
414
+ `akm migrate apply` instruction; validation never migrates them in memory.
411
415
  - `akm task add` writes a task source v4 document and installs it after
412
416
  validation. `--params` renders typed `inputs:` declarations instead of a
413
- `with:` bag; `--schedule` is required on every invocation, and
414
- `--disabled` writes `schedule: [{cron: …, enabled: false}]` instead of a
415
- document-level flag.
417
+ `with:` bag; `--schedule` is required on every invocation. `--disabled`
418
+ leaves the new ref absent from local scheduler activation.
416
419
  - `akm task history` reads durable run history from `state.db`.
417
- - Disable a binding by editing the source and syncing: set that schedule
418
- entry's own `enabled: false`.
420
+ - `akm task enable <ref>` / `akm task disable <ref>` change only local
421
+ scheduler config, then reconcile that bundle.
419
422
  - Delete the `.yml` source and sync to remove its derived binding(s).
420
423
  - `akm task sync --dry-run` previews the reconcile (adds/updates/removes,
421
424
  removals annotated with their owning bundle) without writing to the
@@ -469,8 +472,10 @@ on:
469
472
  refs consumed it as run params; command/script refs rejected it outright).
470
473
  A GitHub Action locator (`owner/repo[/path]@ref`) was a recognized `uses:`
471
474
  shape that was always rejected before dispatch — remote action acquisition
472
- was never implemented in any akm release. `akm.enabled: false` disabled the
473
- whole document, not a specific schedule binding.
475
+ was never implemented in any akm release. `akm.enabled` was source-owned
476
+ scheduling state. `akm migrate apply` removes it; migration preserves actual
477
+ host activation only when the native scheduler proves that the corresponding
478
+ binding is enabled.
474
479
 
475
480
  See [Migrating to task source v4](#migrating-to-task-source-v4) above to
476
481
  convert a file out of this grammar.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akm-cli",
3
- "version": "0.9.16-alpha.1",
3
+ "version": "0.9.16",
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": [