akm-cli 0.10.261016-beta → 0.10.261017-beta

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 (104) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/README.md +8 -10
  3. package/SECURITY.md +7 -99
  4. package/STABILITY.md +57 -98
  5. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +2 -2
  6. package/dist/assets/stash-skeleton/facts/conventions/organization.md +11 -17
  7. package/dist/cli.js +32 -41
  8. package/dist/commands/feedback-cli.js +5 -4
  9. package/dist/commands/health.js +15 -16
  10. package/dist/commands/proposal/proposal-cli.js +1 -1
  11. package/dist/commands/read/registry-search.js +4 -1
  12. package/dist/commands/read/search.js +6 -6
  13. package/dist/commands/sources/self-update.js +9 -5
  14. package/dist/commands/tasks/tasks.js +12 -13
  15. package/dist/core/adapter/adapters/agent-skills-adapter.js +7 -7
  16. package/dist/core/adapter/adapters/akm-task-adapter.js +1 -1
  17. package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
  18. package/dist/core/adapter/adapters/claude-adapter.js +1 -1
  19. package/dist/core/adapter/adapters/dotenv-adapter.js +1 -1
  20. package/dist/core/adapter/adapters/generic-files-adapter.js +1 -1
  21. package/dist/core/adapter/adapters/llm-wiki-adapter.js +1 -1
  22. package/dist/core/adapter/adapters/opencode-adapter.js +1 -1
  23. package/dist/core/adapter/adapters/website-snapshot-adapter.js +1 -1
  24. package/dist/core/bundle-rename.js +17 -7
  25. package/dist/indexer/bundle-identity-guard.js +6 -6
  26. package/dist/indexer/index-written-assets.js +3 -3
  27. package/dist/indexer/indexer.js +12 -8
  28. package/dist/indexer/materialize-embeddings.js +12 -2
  29. package/dist/indexer/passes/metadata.js +103 -46
  30. package/dist/indexer/search/ranking.js +7 -3
  31. package/dist/indexer/search/search-fields.js +1 -1
  32. package/dist/indexer/usage/usage-events.js +30 -8
  33. package/dist/indexer/walk/walker.js +1 -1
  34. package/dist/output/shapes/helpers.js +3 -3
  35. package/dist/output/text/command-format.js +5 -6
  36. package/dist/scripts/akm-migrate-node.js +31 -3
  37. package/dist/scripts/akm-migrate.js +31 -3
  38. package/dist/sources/providers/git-provider.js +2 -4
  39. package/dist/sources/providers/provider-utils.js +8 -13
  40. package/dist/sources/snapshot-fetchers/website-ingest.js +6 -7
  41. package/dist/storage/repositories/events-repository.js +15 -0
  42. package/dist/storage/repositories/improve-ledger-repository.js +13 -0
  43. package/dist/storage/repositories/index-entries-repository.js +43 -5
  44. package/dist/storage/repositories/outcome-repository.js +12 -0
  45. package/dist/storage/repositories/proposals-repository.js +5 -5
  46. package/dist/storage/repositories/salience-repository.js +13 -0
  47. package/dist/storage/repositories/task-history-repository.js +8 -7
  48. package/dist/storage/repositories/workflow-runs-repository.js +10 -8
  49. package/docs/README.md +24 -60
  50. package/docs/agents/README.md +3 -8
  51. package/docs/architecture/README.md +18 -20
  52. package/docs/architecture/adapters.md +40 -43
  53. package/docs/architecture/architecture.md +171 -151
  54. package/docs/architecture/improvement.md +95 -91
  55. package/docs/architecture/internals/classification.md +101 -119
  56. package/docs/architecture/internals/fresh-host-rebuild-runbook.md +33 -35
  57. package/docs/architecture/internals/health-advisories.md +59 -46
  58. package/docs/architecture/internals/improve-workflow.md +166 -693
  59. package/docs/architecture/internals/indexing.md +65 -465
  60. package/docs/architecture/internals/storage-locations.md +301 -848
  61. package/docs/architecture/persisted-data-compat.md +6 -6
  62. package/docs/architecture/specs/okf-support.md +67 -95
  63. package/docs/architecture/specs/ref.md +67 -125
  64. package/docs/architecture/testing/testing-workflow.md +107 -167
  65. package/docs/architecture/workflow-engine.md +34 -33
  66. package/docs/guides/README.md +5 -5
  67. package/docs/guides/author-bundles.md +72 -98
  68. package/docs/guides/author-workflows.md +11 -18
  69. package/docs/guides/bundles.md +91 -123
  70. package/docs/guides/capture-knowledge.md +10 -9
  71. package/docs/guides/concepts.md +45 -30
  72. package/docs/guides/discover-and-load.md +39 -32
  73. package/docs/guides/getting-started.md +24 -24
  74. package/docs/guides/improve-the-library.md +98 -80
  75. package/docs/guides/recipes/headless-install.md +4 -4
  76. package/docs/guides/recipes/website-source.md +9 -5
  77. package/docs/guides/run-workflows.md +10 -11
  78. package/docs/guides/scheduling.md +11 -17
  79. package/docs/guides/use-with-any-agent.md +15 -14
  80. package/docs/guides/wikis.md +6 -9
  81. package/docs/integration/bundling-akm.md +21 -26
  82. package/docs/maintainers/README.md +2 -2
  83. package/docs/maintainers/local-development.md +3 -16
  84. package/docs/migration/README.md +2 -1
  85. package/docs/migration/release-notes/0.10.0.md +167 -22
  86. package/docs/migration/release-notes/README.md +2 -2
  87. package/docs/migration/v0.9-to-v0.10.md +47 -7
  88. package/docs/product-surface.md +10 -8
  89. package/docs/reference/README.md +26 -15
  90. package/docs/reference/asset-types.md +11 -12
  91. package/docs/reference/bundle-types.md +6 -5
  92. package/docs/reference/cli.md +52 -28
  93. package/docs/reference/configuration.md +46 -60
  94. package/docs/reference/data-and-telemetry.md +204 -421
  95. package/docs/reference/env-and-secrets.md +80 -83
  96. package/docs/reference/memory.md +1 -1
  97. package/docs/reference/refs.md +23 -36
  98. package/docs/reference/registry.md +138 -348
  99. package/docs/reference/supported-formats.md +8 -8
  100. package/docs/reference/tasks.md +13 -19
  101. package/docs/reference/website-sources.md +23 -15
  102. package/docs/reference/workflow-schema.md +28 -47
  103. package/docs/reference/workflows.md +33 -37
  104. package/package.json +1 -1
@@ -24,11 +24,28 @@ what runs, what the autonomy gate does and does not allow, how sync happens
24
24
  at the end of a run, and how session extraction fits in.
25
25
 
26
26
  **Boundary:** `akm improve` (and its subprocesses — reflect, distill,
27
- consolidate) never write asset files directly. The only durable artifact they
28
- produce is a proposal row in `state.db`. The narrow set of writes that *are*
29
- allowed to happen without review is enumerated below, under
30
- [The autonomy gate](#the-autonomy-gate);
31
- everything else routes through `akm proposal accept`.
27
+ consolidate) do not write asset files directly. The durable artifact they
28
+ produce is a proposal row in `state.db`, and everything else routes through
29
+ `akm proposal accept`. The writes that happen without a person reviewing the
30
+ diff are these:
31
+
32
+ - **Gated lanes**, off unless `experimental.improveAutonomy` is `true` (see
33
+ [The autonomy gate](#the-autonomy-gate)): memory inference, memory cleanup,
34
+ and a triage promote that runs the judgment tier.
35
+ - **Ungated writes:** a triage promote through the deterministic gates alone
36
+ (see [The autonomy gate](#the-autonomy-gate)); session assets under
37
+ `sessions/**` (see [Session extraction](#session-extraction)); the salience
38
+ score distill writes into the frontmatter of the asset it reads; the graced
39
+ archive purge at the start of every improve run (see
40
+ [Archive purge](#archive-purge)); the local commit that follows each
41
+ `akm proposal accept` in a git repository; and the pre-run sync and the
42
+ end-of-run auto-sync commit and push for git-backed bundles (see
43
+ [Auto-sync](#auto-sync)).
44
+
45
+ `akm improve` and the proposal commands other than `akm proposal list` (Stable)
46
+ are Evolving, and the
47
+ `improve.strategies.*` tuning keys can change between releases; see
48
+ [STABILITY.md](../../STABILITY.md#akm-improve-autonomy).
32
49
 
33
50
  ## Components
34
51
 
@@ -69,7 +86,8 @@ everything else routes through `akm proposal accept`.
69
86
  not trigger a rewrite.
70
87
  2. The feedback event is appended to `state.db`. `akm search` and `akm curate`
71
88
  count a user's recorded positives and negatives per asset and scale the
72
- fused score by them (logarithmic in each count, the same for every asset),
89
+ fused score by them (logarithmic in each count, the same for every asset;
90
+ a negative whose exact fix has been accepted no longer counts),
73
91
  so ranking moves at once with no reindex. The asset's utility score, which
74
92
  improve and metrics read, is recomputed immediately by the same formula
75
93
  `akm index` uses (below).
@@ -81,8 +99,7 @@ everything else routes through `akm proposal accept`.
81
99
  since: a negative feedback in the window judged the body it still has (or,
82
100
  recorded without that body's hash, is newer than its file's last write). It
83
101
  also skips a memory whose only feedback in the window is positive with no
84
- reason or note, which gives the writer nothing to distil (10 of the 11
85
- lessons made from such memories were rejected). Unless
102
+ reason or note, which gives the writer nothing to distil. Unless
86
103
  `--require-feedback-signal` is set, the
87
104
  proactive-maintenance lane (where the strategy enables it, as `default`
88
105
  does) adds the stable assets due for a revisit that the retrieval scope below
@@ -114,7 +131,11 @@ everything else routes through `akm proposal accept`.
114
131
  drain policy (`akm proposal drain`) reviews and resolves each proposal. A
115
132
  rejection is not final: `akm proposal reopen` puts a rejected proposal back
116
133
  to `pending`.
117
- 7. `akm proposal accept` promotes the proposal into the bundle; `akm proposal
134
+ 7. `akm proposal accept` promotes the proposal into the bundle. A proposal
135
+ records the content hash of the file it was generated against, and accept
136
+ refuses to overwrite a target that has changed since (the comparison ignores
137
+ akm's own bookkeeping frontmatter); a proposal that creates a file likewise
138
+ refuses when the file now exists. `akm proposal
118
139
  revert` restores the prior content from the backup captured at promotion
119
140
  time, if the proposal overwrote an existing asset. When the bundle is a git
120
141
  repository (a `.git` directory, whatever its source kind), an accept is
@@ -131,7 +152,7 @@ everything else routes through `akm proposal accept`.
131
152
  began with the same sync, so it started from what other hosts had pushed.
132
153
 
133
154
 
134
- ## Current decisions
155
+ ## How it works
135
156
 
136
157
  ### Utility scoring
137
158
 
@@ -160,7 +181,7 @@ for the storage-level summary.
160
181
  Improve presets live under `improve.strategies` (config) and the built-in
161
182
  set: `default` and `consolidate` (`src/assets/improve-strategies/*.json`). The removed `quick`, `thorough`,
162
183
  `catchup`, `reflect-distill` and `proactive-maintenance` still work as user-defined strategies. Selection
163
- order is `--strategy`, then `defaults.improveStrategy`, then `default`.
184
+ order is `--strategy`, then `improve.strategy`, then `default`.
164
185
 
165
186
  Resolution is a two-step deep merge (`resolveImproveStrategy`): a named
166
187
  built-in strategy is first merged onto the built-in `default` strategy, then
@@ -175,7 +196,7 @@ of the retired built-in) resolves the same way, merged onto `default`.
175
196
 
176
197
  ### Retrieval scope
177
198
 
178
- Improve reworks only what gets read (#986). Fresh feedback and an explicit ref
199
+ Improve reworks only what gets read. Fresh feedback and an explicit ref
179
200
  scope (`akm improve skills/x`) are usage evidence of their own. Every other
180
201
  pick — the proactive-maintenance lane, and the memories consolidation judges — must be in the retrieval
181
202
  scope (`src/commands/improve/retrieval-scope.ts`):
@@ -200,9 +221,10 @@ processed each once.
200
221
 
201
222
  Every reflect revision and every distilled lesson is scored by a judge before it
202
223
  is queued (`runQualityJudge`, `src/commands/improve/stage.ts`): one call at
203
- temperature 0, each criterion scored 1 to 5, failing closed (no runner, a
204
- timeout, or an unparseable or incomplete reply never passes content and goes to
205
- review). A reflect revision is scored on three criteria:
224
+ temperature 0, each criterion scored 1 to 5. Content passes only on a complete
225
+ verdict: with no runner, or when the call times out or returns an unparseable or
226
+ incomplete reply, it does not pass and goes to review. A reflect revision is
227
+ scored on three criteria:
206
228
 
207
229
  - **need**: does it fix a concrete problem in the source: something the
208
230
  feedback reports as wrong or missing, a factual error, or broken, garbled,
@@ -214,19 +236,19 @@ review). A reflect revision is scored on three criteria:
214
236
  - **quality**: is it coherent and accurate, with nothing the source or the
215
237
  feedback does not support?
216
238
 
217
- Content passes only when **every** criterion scores 4 or more (a lesson's
218
- grounding is judged apart, see
219
- [distill](internals/improve-workflow.md#distill-akmdistill)); a mean of 3.5
220
- passed it before. A verdict that does not pass is a review when its mean is 2.5
221
- or more and a rejection below that. Reflect narrows that band: a revision whose
239
+ Content passes only when **every** criterion scores 4 or more. A verdict that
240
+ does not pass is a review when its mean is 2.5 or more and a rejection below
241
+ that. Reflect narrows that band: a revision whose
222
242
  mean is 3.5 or more is queued for a person (reason `judge-uncertain`, with the
223
243
  `scores` and `judgeReason`) and records no rejection window, and a lower mean is
224
244
  refused. On 113 reviewed frontmatter-only proposals (lab 27B Q2, the shipped
225
245
  judge) the non-passing ones at 3.5 or more were 17 good and 9 bad, the rest 1
226
246
  good and 2 bad; on 396 labelled body rewrites a mean below 3.5 was good 6 times
227
- in 291 (the constant and its sources are in `src/commands/improve/reflect.ts`). The rubric and the rule were chosen on 90
228
- labelled real rewrites, where judging on the mean let rewrites that only
229
- reworded a correct asset through.
247
+ in 291 (the constant and its sources are in `src/commands/improve/reflect.ts`).
248
+ A lesson is scored on `reusable`, `nonRedundancy`, and `grounding`;
249
+ `grounding` is left out of the mean, and any lesson criterion at 2 or lower
250
+ rejects whatever the mean is (see
251
+ [distill](internals/improve-workflow.md#distill-akmdistill)).
230
252
 
231
253
  A reflect pass is stamped on the proposal as a `staged` decision from the
232
254
  `quality-gate` with the per-criterion `scores` and the judge's `judgeReason`;
@@ -237,14 +259,9 @@ the lesson or promotion is minted `deferred` for a person (reason
237
259
  triage drain and its judgment tier leave it alone. A lesson that repeats an existing
238
260
  lesson may instead be proposed as an update of that lesson (reason
239
261
  `distill-update`, same gate), with only what the memory adds; the drain leaves
240
- it for a person too. On 2026-10-05 the gate had
241
- staged 12 lessons and 10 were bad (they restated the memory, claimed what it
242
- does not say, or filed a dated status as a lesson), and no score separated them
243
- from the two good ones. Reflect revises only an asset's
262
+ it for a person too. Reflect revises only an asset's
244
263
  `description`, `when_to_use` and title, and edits the body only to add a missing level-1
245
- heading; the rest of the body stays byte for byte. On 396 labelled edits,
246
- those that fixed a frontmatter defect and left the body alone were good 24
247
- times in 26, and those that also rewrote the body were bad 175 times in 224.
264
+ heading; the rest of the body stays byte for byte.
248
265
 
249
266
  ### Judgment tier: promotions only
250
267
 
@@ -270,50 +287,37 @@ it. An empty diff is still rejected. Proposals driven by feedback (`signal-delta
270
287
 
271
288
  ### Retirement continuity
272
289
 
273
- Before the consolidate pair pass mints a `retire` proposal (rule R3,
274
- `src/commands/improve/consolidate/continuity-check.ts`), it replays up to five
290
+ Before the consolidate pair pass mints a `retire` proposal
291
+ (`src/commands/improve/consolidate/continuity-check.ts`), it replays up to five
275
292
  of the retired asset's own past `search`/`curate` queries
276
293
  (`loadRetrievalQueries`, `../retrieval-queries.ts` — boilerplate, harness/tool envelopes,
277
- pastes and near-duplicates dropped before replay, S3a) through akm's own
294
+ pastes and near-duplicates dropped before replay) through akm's own
278
295
  search, in-process — the ranking a user actually gets, no LLM. For every
279
- query where the retired asset ranked in the top 10, the successor must too
280
- (N2: compared directly — search itself returns at most the top 10 hits, so
281
- "ranked" and "absent from those hits" are the only two states there are, no
282
- generic rank-change-report abstraction needed). An asset with no recorded
283
- queries is not checked at all, and neither is a pair whose two bodies are
284
- content-identical once whitespace is collapsed (S3b) — search's own
285
- content-dedupe already hides the successor behind the retired asset for
286
- every such query, so a "successor missing" finding there would not be a
287
- real risk.
288
-
289
- A failing pair still mints — the check flags, it never blocks — but the
296
+ query where the retired asset ranked in the top 10, the successor must too.
297
+ An asset with no recorded queries is not checked, and neither is a pair whose
298
+ two bodies are content-identical once whitespace is collapsed — search's own
299
+ content dedupe already hides the successor behind the retired asset for every
300
+ such query.
301
+
302
+ A failing pair still mints — the check flags, it does not block — but the
290
303
  proposal carries `continuityRisk` in its retirement metadata: the failing
291
304
  query count and the rank pairs, visible in `akm proposal show`/`list`/`diff`. A
292
305
  flagged proposal is excluded from every bulk accept path (`accept
293
306
  --generator …`, with or without `--yes`); a person can still accept it by id.
294
- Bulk *reject* is unaffected, since declining a flagged proposal is always the
295
- safe direction.
307
+ Bulk reject is unaffected.
296
308
 
297
309
  A query that never ran (the search call threw) or that fell back to
298
310
  keyword-only ranking instead of the real one (`mode: "fts-fallback"` — most
299
311
  often a down or unreachable embedding endpoint) is "unverified": it is never
300
312
  compared for rank at all, and on its own it is enough to set
301
313
  `continuityRisk` (`unverifiedQueries` alongside the usual `ranks`), so an
302
- endpoint outage reads as "risk unknown," never as the silent "no risk
303
- found" a search that quietly used a degraded ranking would otherwise
304
- produce. Once any query in a pair-pass run falls back, every later query in
305
- that same run skips the semantic attempt entirely and goes straight to
306
- keyword-only — a dead endpoint costs one failed attempt for the whole run,
307
- not one per remaining query.
308
-
309
- This check replaces the old per-run forgetting-safety lane (a one-time WS-1
310
- cutover guard that compared improve's own salience ranking before and after
311
- each run). The 30-day event window showed it made no pick the signal-delta
312
- lane or the retrieval scope would not also have made, and it protected
313
- `asset_salience.rank_score`, which only improve itself ever read — a rank drop
314
- could not hide anything from search. `forgetting-safety` stays a valid
315
- `eligibilitySource`/event-type value so old proposals and events still decode,
316
- but nothing assigns or emits it any more.
314
+ endpoint outage reads as "risk unknown" rather than "no risk found". Once any
315
+ query in a pair-pass run falls back, every later query in that same run skips
316
+ the semantic attempt and goes straight to keyword-only — a dead endpoint costs
317
+ one failed attempt for the whole run, not one per remaining query.
318
+
319
+ `forgetting-safety` remains a valid `eligibilitySource` and event-type value so
320
+ old proposals and events still decode; nothing assigns or emits it any more.
317
321
 
318
322
  ### Dry-run planning boundary
319
323
 
@@ -337,9 +341,7 @@ The dry path stops at that projection boundary. It may read indexed assets,
337
341
  the filesystem, and an existing `state.db`, but opens state read-only and does
338
342
  not create it when absent. It does not acquire the improve lock or write the
339
343
  index, state, events, proposals, assets, cache, sync journal, or persisted run
340
- result, and it never dispatches an LLM. SQLite inputs are inspected through
341
- disposable main/WAL copies so even a held source SHM file is not touched.
342
- Consolidation pool inspection and the extract `minNewSessions` gate use shared
344
+ result, and it does not dispatch an LLM. Consolidation pool inspection and the extract `minNewSessions` gate use shared
343
345
  zero-LLM selectors, while live execution re-inspects mutable inputs immediately
344
346
  before dispatch. A missing index or one without the current `entries` table
345
347
  yields an explicit empty `plan.snapshot` (`missing` or `incompatible`) rather
@@ -381,13 +383,16 @@ opt-in warns `[improve] memoryInference skipped` and names
381
383
  a silent no-op (`applyAutonomyGate` in `src/commands/improve/autonomy-gate.ts`,
382
384
  the warning in `runImproveStageSequence` in `src/commands/improve/improve.ts`).
383
385
  Consolidation stays enabled with
384
- autonomy off: both its passes only ever emit a reviewable proposal. The one
386
+ autonomy off: both its passes emit only reviewable proposals. The one
385
387
  pair-pass `retire` proposal `triage` `applyMode: "promote"` accepts is a
386
388
  retirement the pair pass staged (nothing unique to the retired side, confirmed
387
- by a second look, no continuity risk); every other one waits for `akm proposal accept`. An absent `experimental`
388
- section, an absent key, and an explicit `false` all read identically as off —
389
- autonomy is never inferred. `akm proposal drain --promote` is a second,
390
- explicit promote surface independent of this gate.
389
+ by a second look, no continuity risk); every other one waits for `akm proposal accept`. Triage runs as a
390
+ pre-pass at the start of an improve run, over the backlog already queued, so a proposal
391
+ a run queues is first eligible for `applyMode: "promote"` on the next run (a run scoped
392
+ to a single ref skips the pre-pass). An absent `experimental`
393
+ section, an absent key, and an explicit `false` all read as off.
394
+ `akm proposal drain --promote` is a second, explicit promote surface
395
+ independent of this gate.
391
396
 
392
397
  ### Auto-sync
393
398
 
@@ -433,7 +438,7 @@ then rewritten by the run IS committed. Deletions are journaled like writes, so
433
438
  the final on-disk state is what lands — a path written and then reverted or
434
439
  purged produces no commit at all. The run reports its journal as
435
440
  `writtenPaths` on the improve result. Callers that supply no explicit path list
436
- (`akm sync`, `akm push`) keep the managed-pathspec fallback in `saveGitStash`.
441
+ (`akm sync`) keep the managed-pathspec fallback in `saveGitStash`.
437
442
 
438
443
  ### Archive purge
439
444
 
@@ -446,15 +451,15 @@ before index bootstrap or triage. For a git-backed bundle, it deletes the
446
451
  archived asset file(s) — never `cleanup.md` — of every retirement whose
447
452
  tombstone `retiredAt` is more than 30 days old (`RETIRE_GRACE_DAYS`) AND
448
453
  whose archive directory is entirely git-tracked and clean (`git ls-files`
449
- plus `git status --porcelain -uall`, both checked once per sweep, not once
450
- per directory). `.git` presence alone does not guarantee a retirement was
451
- ever committed: an accept commits its own paths, once per process (`commitAcceptedPaths` in
454
+ plus `git status --porcelain -uall`, checked once per sweep, not once per
455
+ directory). A `.git` directory alone does not mean a retirement was committed:
456
+ an accept commits its own paths, once per process (`commitAcceptedPaths` in
452
457
  `src/core/write-source.ts`), on a `kind: "filesystem"` source with a `.git`
453
- directory too, but a commit that failed only warned, and a retirement accepted
454
- by an older akm left archived bytes sitting on disk with no commit behind them
455
- at all. A directory with even one untracked or modified file (the tombstone
456
- included) is left whole for a later sweep, so the purge only ever removes
457
- bytes git can already recover. Every deleted path is journaled individually,
458
+ directory too, but a commit that failed only warns. A directory with even one
459
+ untracked or modified file (the tombstone included) is left whole for a later
460
+ sweep, so the purge removes only bytes git can recover. If git cannot report
461
+ the archive's state, the sweep removes nothing and warns. Every deleted path is
462
+ journaled individually,
458
463
  so the end-of-run auto-sync commits the removal the same way it commits the
459
464
  archive move itself. A bundle with no `.git` of its own has no history to
460
465
  fall back on, so its archive is left untouched — `akm health` reports its
@@ -463,17 +468,16 @@ size and file count instead (`memory-cleanup-archive` advisory,
463
468
 
464
469
  ### Session extraction
465
470
 
466
- `akm proposal extract` is the standalone entry point for mining coding-agent
467
- session transcripts (`--type claude`, `--type codex`, `--type opencode`, or
468
- `--auto` to iterate every harness with a detectable session-log location) into
469
- proposals.
470
- It replaced the legacy session-checkpoint hook and runs independently of
471
- whether a strategy's own `processes.extract` stage is enabled — no shipped
472
- strategy turns that improve-stage extraction on, and a direct
473
- `akm proposal extract --type <harness>` or `--auto` invocation is never gated
474
- by that toggle. Session indexing writes are additive
475
- (`sessions/**`), which is why they are one of the writes left deliberately
476
- ungated by the autonomy gate above.
471
+ `akm proposal extract` is the standalone entry point for mining
472
+ coding-agent session transcripts (`--type claude`, `--type codex`,
473
+ `--type opencode`, or `--auto` to iterate every harness with a detectable
474
+ session-log location) into proposals. It runs independently of whether a
475
+ strategy's own `processes.extract` stage is enabled — no shipped strategy turns
476
+ that improve-stage extraction on, and a direct
477
+ `akm proposal extract --type <harness>` or `--auto` invocation does not depend
478
+ on that toggle. Session indexing writes `sessions/**` assets
479
+ (`processes.extract.indexSessions`, default on); these writes are additive and
480
+ are not behind the autonomy gate.
477
481
 
478
482
  `--dry-run` keeps eligible candidate refs in `sessions[].previewRefs`. It leaves
479
483
  proposal rows, seen-session tracking, the improve ledger and assets unchanged;
@@ -508,5 +512,5 @@ actual proposal rows, and health uses live seen-session outcomes.
508
512
  including the Utility Scoring and Writing to Sources sections
509
513
  - [Configuration Reference — Strategies](../reference/configuration.md#strategies)
510
514
  and [Experimental opt-ins](../reference/configuration.md#experimental-opt-ins)
511
- - [STABILITY.md](../../STABILITY.md#akm-improve-autonomy--opt-in-in-090) — the
512
- normative autonomy-gate contract
515
+ - [STABILITY.md](../../STABILITY.md#akm-improve-autonomy) — the stability status of
516
+ `akm improve` and the opt-in for `experimental.improveAutonomy`
@@ -1,152 +1,134 @@
1
- # Classification System
1
+ # Classification
2
2
 
3
- akm recognizes files through **bundle adapters**. Each adapter owns a bundle
4
- format and exposes a `recognize()` primitive that inspects a single file (path +
5
- frontmatter + content) and returns an `IndexDocument` — the item's
6
- subdir-qualified `conceptId`, type, renderer, and metadata — or `null` if the
7
- adapter does not claim the file. There is no longer a global matcher registry;
8
- the per-format adapter is the unit of recognition.
3
+ akm recognizes files through **bundle adapters**. An adapter owns one bundle
4
+ format. Its `recognize()` method inspects one file (path, frontmatter, content)
5
+ and returns an `IndexDocument` (the item's subdirectory-qualified `conceptId`,
6
+ type, renderer, and metadata) or `null` when the adapter does not claim the
7
+ file. The indexer calls it for every file the walker finds (see
8
+ [Indexing](indexing.md)).
9
9
 
10
10
  ## Built-in adapters
11
11
 
12
- The registry is a **static frozen list** (`BUILTIN_ADAPTERS` in
13
- `src/core/adapter/adapters/index.ts`, exposed through
14
- `src/core/adapter/registry.ts`) — always populated at module load, no
15
- registration call required. Eleven built-ins, in probe order:
12
+ `BUILTIN_ADAPTERS` in `src/core/adapter/adapters/index.ts` is a frozen list,
13
+ exposed through `src/core/adapter/registry.ts`. Its order is the install-time
14
+ probe order, and `ADAPTER_ID_TABLE` (`src/core/adapter/adapter-ids.ts`) mirrors
15
+ it. There are eleven:
16
16
 
17
17
  | Adapter id | Format | Recognizes |
18
18
  | --- | --- | --- |
19
- | `website-snapshot` | Crawled website snapshot bundle (read-only) | snapshot pages |
20
- | `agent-skills` | Agent-skills package (root `SKILL.md`) | skills |
21
- | `claude` | A `.claude/` tool directory | commands, agents, skills, settings-adjacent files |
22
- | `opencode` | An `.opencode/` tool directory | commands, agents, skills |
23
- | `dotenv` | Env-file bundle | env/secret whole-file assets (values never indexed) |
24
- | `akm-workflow` | Workflow-dir component | workflow programs |
25
- | `akm-task` | Task-dir component | scheduled task definitions |
26
- | `llm-wiki` | LLM Wiki bundle | a wiki root (`schema.md` + `pages/`) and its pages, raw, xrefs, citations |
27
- | `akm` | The classic AKM bundle layout | scripts, skills, commands, agents, knowledge, instructions, workflows, memories, lessons, env, secrets, facts, tasks, sessions |
28
- | `okf` | Open Knowledge Format bundle | OKF concept documents of any open type |
29
- | `generic-files` | Catch-all file mount | explicit configuration only — never auto-probed |
30
-
31
- `looksLikeRoot` probes run most-specific-first in the list order above; the
32
- first match wins and the winner is recorded per component. A root matching no
33
- probe falls back to `akm` (see `FALLBACK_ADAPTER_ID` in
34
- `src/indexer/installations.ts`).
35
- `generic-files` never participates in probing.
36
-
37
- Configured adapter ownership wins over probing. `akm add` records the detected
38
- adapter so later indexing does not reinterpret a bundle. The broad OKF probe
39
- also recognizes index-less typed Markdown, but strong AKM layout evidence runs
40
- first because AKM Markdown is an OKF-compatible superset.
41
-
42
- See [Bundle Types](../../reference/bundle-types.md) for the user-facing detail
43
- per adapter — conceptId/ref shape, what's indexed, `validate()` checks, and
44
- read/write status in 0.9.0.
19
+ | `website-snapshot` | Crawled website snapshot (read-only) | pages under `stash/knowledge/` that carry the `website` tag or a `sourceUrl`, typed `website` |
20
+ | `agent-skills` | Collection of `<name>/SKILL.md` packages | one `skill` per package directory; bundled resources belong to the skill |
21
+ | `claude` | A `.claude/` tool directory | root `CLAUDE.md` (`instruction`), `commands/`, `agents/`, `skills/<name>/SKILL.md`; skips `settings.json` and `.mcp.json` |
22
+ | `opencode` | An `.opencode/` tool directory | root `AGENTS.md` (`instruction`), `commands/`, `agents/`, `skills/<name>/SKILL.md`; skips `opencode.json` |
23
+ | `dotenv` | Env-file bundle | `env/*.env` as `env` (key names only) and any file under `secrets/` as `secret` (name only) |
24
+ | `akm-workflow` | Workflow bundle | `.md` workflow sources |
25
+ | `akm-task` | Task bundle | `.yml` task sources as `task`; `.yaml` is not recognized |
26
+ | `llm-wiki` | LLM Wiki bundle | a root with `schema.md` and `pages/`: pages (type from frontmatter `pageKind`, default `note`) and `raw/` sources (`wiki-source`) |
27
+ | `akm` | The AKM bundle layout | the types listed under "Item types" below |
28
+ | `okf` | Open Knowledge Format bundle | any `.md` except `index.md` and `log.md`; `type` comes from frontmatter, default `knowledge`; the directory does not change it |
29
+ | `generic-files` | Catch-all mount | scripts as `script`, `.md`/`.txt` as `document`, everything else as `file` |
30
+
31
+ The first adapter whose `looksLikeRoot` probe matches a root claims it, and the
32
+ winner is recorded per component. A root matching no probe falls back to `akm`
33
+ (`FALLBACK_ADAPTER_ID`, `src/indexer/installations.ts`). `generic-files` is not
34
+ probed. An adapter set in a bundle's config entry (`components.<name>.adapter`,
35
+ validated against the ids above) wins over probing. The probe order puts
36
+ `claude`, `opencode`, and `dotenv` ahead of `akm`, and `akm` ahead of `okf`,
37
+ because AKM Markdown is an OKF-compatible superset.
38
+
39
+ [Bundle Types](../../reference/bundle-types.md) has the user-facing detail per
40
+ adapter: conceptId shape, what is indexed, `validate()` checks, and whether the
41
+ adapter can write.
45
42
 
46
43
  ## Item types
47
44
 
48
- `type` is an open descriptive string. The core accepts every non-empty value;
49
- the owning adapter decides whether a value receives specialized behavior. The
50
- `akm` adapter emits its fourteen defined native types (`script`, `skill`,
51
- `command`, `agent`, `knowledge`, `instruction`, `workflow`, `memory`,
52
- `lesson`, `env`, `secret`, `fact`, `task`, `session`) — see
53
- [Bundle Types](../../reference/bundle-types.md) for the full
54
- purpose / agent-output table per type.
45
+ `type` is an open string. The core accepts every non-empty value, and the owning
46
+ adapter decides whether a value gets specialized behavior. The `akm` adapter
47
+ emits fourteen types (`KNOWN_TYPES`, `src/core/recognition-util.ts`): `skill`,
48
+ `command`, `agent`, `knowledge`, `workflow`, `script`, `memory`, `env`, `secret`,
49
+ `lesson`, `task`, `session`, `fact`, `instruction`. See
50
+ [Asset Types](../../reference/asset-types.md).
55
51
 
56
- `wiki` is **no longer an item type**. Multi-page wikis are a bundle *format* owned
57
- by the `llm-wiki` adapter, not a per-file type stamped by the classifier.
52
+ `wiki` is not an item type; multi-page wikis are a bundle format owned by the
53
+ `llm-wiki` adapter.
58
54
 
59
- ## Reserved structural files
55
+ ## Reserved and skipped files
60
56
 
61
- `index.md` and `log.md` are reserved structural files for the `akm`, `okf`, and
62
- `llm-wiki` adapters. OKF defines their meaning in OKF bundles; AKM and LLM Wiki
63
- reserve the same names under their own format contracts. Other adapters own
64
- their reserved-name rules.
57
+ The `akm`, `okf`, `claude`, `opencode` and `generic-files` adapters reserve
58
+ `index.md` and `log.md` at every depth, and neither is an item (`RESERVED_FILES`,
59
+ `src/core/adapter/adapters/shared.ts`). `llm-wiki` reserves `schema.md`,
60
+ `index.md` and `log.md` only at the wiki root. The `akm` adapter also
61
+ skips, using path and `stat` checks (`akmStashAbstains`,
62
+ `src/core/adapter/adapters/akm-adapter.ts`):
65
63
 
66
- ## Adapter-owned filtering (AKM sensitive/infra abstention)
64
+ - the bundle's root `README.md`;
65
+ - an `env/` `.env` file with a sibling `.sensitive` marker;
66
+ - a `secrets/` file that is a `.sensitive` or `.lock` marker, or that has a sibling `<name>.sensitive` marker;
67
+ - the root-level `schema.md`, `index.md`, and `log.md` of a `wikis/<name>/` directory.
67
68
 
68
- Each adapter decides which walked files it claims and which it abstains on — the
69
- core always excludes VCS internals and symlink escapes. An OKF walk includes
70
- ordinary dot directories and `bin/` because those paths can identify conformant
71
- concepts; AKM keeps its existing cache/dot-directory hygiene. The `akm`
72
- adapter's `recognize` abstains (returns `null`) on its own bundle's
73
- non-content files, using **path/stat checks only** so the bytes of sensitive files
74
- are never read to make the decision:
69
+ The walker itself skips VCS internals. It indexes a symlink to a file like any other file and never descends a symlinked directory.
75
70
 
76
- - an `env/…` `.env` file that has a sibling `.sensitive` marker;
77
- - anything under the frozen legacy `vaults/` directory (the `vault` type was
78
- removed in 0.9.0);
79
- - a `secrets/` `.sensitive`/`.lock` marker, or a secret with a sibling
80
- `<name>.sensitive` marker;
81
- - a `wikis/<name>/` root-level infrastructure file (`schema.md`/`index.md`/`log.md`).
71
+ ## How the akm adapter picks a type
82
72
 
83
- This policy previously lived in the indexer's `shouldIndexStashFile` pre-filter; it
84
- now lives in the adapter (`akmStashAbstains` in
85
- `src/core/adapter/adapters/akm-adapter.ts`), so each adapter owns its own bundle's
86
- filtering (owner ruling 2026-07-21).
73
+ The `akm` adapter runs four matchers from `src/indexer/walk/matchers.ts`
74
+ (`extensionMatcher`, `directoryMatcher`, `parentDirHintMatcher`,
75
+ `smartMdMatcher`). `recognizeMatch` (`src/core/adapter/recognize-match.ts`)
76
+ collects their results and picks the highest specificity. On a tie the matcher
77
+ registered later wins, in the order listed.
87
78
 
88
- ## The akm adapter's recognition signals
89
-
90
- Inside the `akm` adapter, recognition picks a winner by **specificity descending**,
91
- ties broken by registration order (later wins). The signals:
92
-
93
- | Specificity | Signal | Result |
79
+ | Specificity | Signal | Type |
94
80
  | --- | --- | --- |
95
- | 25 | `SKILL.md` (skill directory) | `skill` |
96
- | 19 | workflow markdown structure | `workflow` |
97
- | 18 | command frontmatter / `$ARGUMENTS` body placeholders | `command` |
98
- | 15 | immediate parent dir hint | directory-specific type |
99
- | 10 | ancestor dir hint | directory-specific type |
100
- | 8 | `model` frontmatter only | weak `agent` signal |
101
- | 5 | fallback markdown | `knowledge` |
81
+ | 25 | file named `SKILL.md` | `skill` |
82
+ | 19 | `type: workflow` in frontmatter | `workflow` |
83
+ | 18 | `agent` in frontmatter, or `$ARGUMENTS` in the body | `command` |
84
+ | 18 | `$1`, `$2`, or `$3` in the body, only when no ancestor directory declares a type | `command` |
85
+ | 15 | immediate parent directory declares a type | that type |
86
+ | 10 | an ancestor directory declares a type | that type |
87
+ | 8 | `model` in frontmatter, nothing stronger | `agent` |
88
+ | 5 | any other `.md` | `knowledge` |
102
89
  | 3 | known script extension | `script` |
103
90
 
104
- ### Directory signals
105
-
106
- - `scripts/` → `script`
107
- - `skills/` → `skill`
108
- - `commands/` → `command`
109
- - `agents/` → `agent`
110
- - `knowledge/` → `knowledge`
111
- - `workflows/` → `workflow`
112
- - `memories/` → `memory`
113
- - `lessons/` → `lesson`
114
- - `env/` → `env`
115
- - `secrets/` → `secret`
116
- - `tasks/` → `task`
91
+ Directories that declare a type (`DIR_TYPE_MAP`) and the files they accept:
117
92
 
118
- ### Markdown signals
119
-
120
- | Signal | Type | Specificity |
93
+ | Directory | Type | Files |
121
94
  | --- | --- | --- |
122
- | workflow heading/step structure | `workflow` | 19 |
123
- | `agent` in frontmatter | `command` | 18 |
124
- | `$ARGUMENTS` or `$1`-`$3` in body | `command` | 18 |
125
- | `model` in frontmatter only | `agent` | 8 |
126
- | any other `.md` | `knowledge` | 5 |
95
+ | `scripts/` | `script` | script extensions |
96
+ | `skills/` | `skill` | `SKILL.md` (other files under a skill are resources, not skills) |
97
+ | `commands/`, `agents/`, `knowledge/`, `instructions/`, `memories/`, `lessons/`, `facts/`, `sessions/` | `command`, `agent`, `knowledge`, `instruction`, `memory`, `lesson`, `fact`, `session` | `.md` |
98
+ | `workflows/` | `workflow` | `.md` (a `.yml` is typed `workflow`, then skipped at index time with a warning that it must use `.md`) |
99
+ | `tasks/` | `task` | `.yml` |
100
+ | `env/` | `env` | `.env` and `*.env` |
101
+ | `secrets/` | `secret` | any file except `.lock` and `.sensitive` |
102
+
103
+ A `README.md` in a typed directory is not the directory's type; it is indexed
104
+ as `knowledge`. `$ARGUMENTS` and `agent` frontmatter beat a directory hint, so a
105
+ `knowledge/` file containing `$ARGUMENTS` is a `command`. Files under `secrets/`
106
+ are not read for frontmatter.
127
107
 
128
- ## Asset quality values
108
+ ## The `quality` field
129
109
 
130
- The `quality` field marks how an item was produced. Four values are well-known:
110
+ `quality` marks how an item was produced (`KNOWN_QUALITY_VALUES`,
111
+ `src/indexer/passes/metadata.ts`). The default is `generated`; a frontmatter
112
+ `quality` overrides it.
131
113
 
132
114
  | Value | Meaning |
133
115
  | --- | --- |
134
- | `"generated"` | Heuristically indexed; included in default search |
135
- | `"curated"` | Human-authored; included in default search |
136
- | `"enriched"` | Retired LLM enrichment pass (0.9.17-alpha.9) ran for this item; included in default search |
137
- | `"proposed"` | Pending review; excluded from default search, opt-in via `--include-proposed` |
116
+ | `generated` | Derived automatically from the file; in default search |
117
+ | `curated` | Human-authored; in default search |
118
+ | `enriched` | Accepted on entries an earlier release enriched; nothing sets it now; in default search |
119
+ | `proposed` | Pending review; left out of search unless `--include-proposed` |
138
120
 
139
- Unknown string values warn once at runtime and remain searchable.
121
+ An unknown value warns once and stays searchable.
140
122
 
141
123
  ## Examples
142
124
 
143
- | File | Winning signal | conceptId |
125
+ | File in the bundle | Winning signal | conceptId |
144
126
  | --- | --- | --- |
145
- | `scripts/deploy.sh` | parent dir (15) → `script` | `scripts/deploy.sh` |
146
- | `skills/review/SKILL.md` | `SKILL.md` (25) → `skill` | `skills/review` |
147
- | `commands/release.md` with `agent: coder` | command frontmatter (18) | `commands/release` |
148
- | `agents/reviewer.md` | parent dir (15) → `agent` | `agents/reviewer` |
149
- | `workflows/release.md` with workflow structure | structure (19) → `workflow` | `workflows/release` |
150
- | `env/prod.env` | parent dir (15) → `env` | `env/prod` |
151
- | `secrets/deploy-token` | parent dir (15) → `secret` | `secrets/deploy-token` |
152
- | `docs/guide.md` | fallback (5) → `knowledge` | `knowledge/guide` |
127
+ | `scripts/deploy.sh` | parent directory (15) | `scripts/deploy.sh` |
128
+ | `skills/review/SKILL.md` | `SKILL.md` (25) | `skills/review` |
129
+ | `commands/release.md` with `agent: coder` | frontmatter (18) | `commands/release` |
130
+ | `agents/reviewer.md` | parent directory (15) | `agents/reviewer` |
131
+ | `workflows/release.md` | parent directory (15) | `workflows/release` |
132
+ | `env/prod.env` | parent directory (15) | `env/prod` |
133
+ | `secrets/deploy-token` | parent directory (15) | `secrets/deploy-token` |
134
+ | `docs/guide.md` | fallback (5) | `knowledge/docs/guide` |