akm-opencode 0.9.202808220049 → 0.9.11202609031957
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.
- package/README.md +11 -7
- package/index.ts +1312 -115
- package/package.json +2 -2
- package/shared/akm-version.ts +40 -12
- package/shared/curate-render.ts +108 -0
- package/shared/memory-events.ts +4 -0
- package/shared/recall-policy.ts +7 -3
- package/shared/vendor-semver.ts +18 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# akm-opencode
|
|
2
2
|
|
|
3
|
-
OpenCode plugin for [AKM](https://github.com/itlackey/akm) `^0.9.
|
|
3
|
+
OpenCode plugin for [AKM](https://github.com/itlackey/akm) `^0.9.8`. It exposes exactly five public tools and uses lifecycle hooks to bring relevant AKM context into a session.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -18,13 +18,13 @@ Add the plugin to `opencode.json`:
|
|
|
18
18
|
| --- | --- |
|
|
19
19
|
| `akm_search` | Search configured bundles or registries. `source` accepts `local`, `registry`, `all`, or a configured bundle name. |
|
|
20
20
|
| `akm_show` | Show a concept by `[bundle//]conceptId[#fragment]`. A fragment selects a Markdown section. |
|
|
21
|
-
| `akm_curate` | Return ranked concepts for a task or topic. |
|
|
21
|
+
| `akm_curate` | Return ranked concepts for a task or topic. Optional `pack` is a token budget that returns the selected local assets' full content in one response; registry hits are omitted from packed items. |
|
|
22
22
|
| `akm_feedback` | Record positive or negative feedback for a concept. |
|
|
23
23
|
| `akm_remember` | Save durable knowledge as a searchable memory. |
|
|
24
24
|
|
|
25
25
|
`akm_search`, `akm_show`, and `akm_curate` call the bundled AKM read APIs in process. `akm_feedback` and `akm_remember` use the compatible AKM CLI because they mutate AKM state. Failures return structured results and are logged through OpenCode app logging.
|
|
26
26
|
|
|
27
|
-
Use the `ref` returned by search or curate directly with show or feedback. Concept IDs look like `skills/code-review`, `memories/release-retro`, or `team-playbook//knowledge/deploy#Rollback`.
|
|
27
|
+
Use the `ref` returned by search or curate directly with show or feedback. When `akm_curate.pack` is set, the response already includes packed local content, so a separate show call is only needed for omitted or registry-only hits. Concept IDs look like `skills/code-review`, `memories/release-retro`, or `team-playbook//knowledge/deploy#Rollback`.
|
|
28
28
|
|
|
29
29
|
## Lifecycle Hooks
|
|
30
30
|
|
|
@@ -36,11 +36,12 @@ The plugin subscribes to OpenCode lifecycle events. Hook failures are logged thr
|
|
|
36
36
|
| `session.updated` | Backfills hints and the workflow summary for a session the plugin has not prepared yet. It does not re-run session-created work. |
|
|
37
37
|
| `chat.message` | Records feedback or memory intent and can schedule non-blocking curation for a substantive prompt. The curate is fire-and-forget: its result is injected on a later turn rather than delaying this one. |
|
|
38
38
|
| `experimental.chat.system.transform` | Injects the AKM guidance and cached curated context into the system prompt. The host rebuilds the system prompt on every request, so these blocks are re-injected each turn — including after a compaction — rather than once per session. |
|
|
39
|
-
| `tool.execute.
|
|
39
|
+
| `tool.execute.before` | The format-declaration write gate (`AKM_WRITE_GATE`, `observe` by default). Blocks the first `edit`/`write` to an existing file that declares a format your bundle documents and hands the model the ref to read. Once per file per session, released unconditionally on the retry. |
|
|
40
|
+
| `tool.execute.after` | Tracks concepts used by AKM tools, records deduplicated feedback, and checkpoints session observations. It also records what a file the session `read` declares about its own format, which is what the write gate above keys on. `write` is deliberately not a source: a file the session created is not one it needs the bundle to explain. The create itself is recorded on the write's `tool.execute.before` pass, so a later read-back of that file cannot re-arm the gate. |
|
|
40
41
|
| `shell.env` | Exposes `AKM_PROJECT`, `AKM_PLUGIN_VERSION`, and the resolved `AKM_BUNDLE_DIR` to shell tools. |
|
|
41
42
|
| `session.idle` | Runs interval-gated memory extraction (`AKM_AUTO_MEMORY=0` disables it). Fires after every turn, so it is rate-limited. |
|
|
42
43
|
| `session.compacted` | Records a post-compaction event. |
|
|
43
|
-
| `session.deleted` | Refreshes the local AKM index, then drops all per-session state and the temporary curation file. |
|
|
44
|
+
| `session.deleted` | Refreshes the local AKM index, warns once if the write gate saw write-path tool calls but never acted on any, then drops all per-session state and the temporary curation file. |
|
|
44
45
|
|
|
45
46
|
The session observation buffer that retrospective feedback reads from survives every non-terminal event: it is bounded by `AKM_SESSION_BUFFER_MAX_ENTRIES` and dropped only on `session.deleted`. Discarding it at `session.idle` would empty it between turns, so "thanks, that worked" would credit nothing in exactly the sessions that used the most assets.
|
|
46
47
|
|
|
@@ -67,9 +68,10 @@ Every kill switch below is opt-out and reads the same way: only the literal `0`
|
|
|
67
68
|
| `AKM_OPENCODE_IGNORE_BUNDLED_CLI` | unset (off) | Set to `1` to drop the bundled AKM CLI from resolution so only an `akm` on `PATH` is considered. Used by the eval harness; also an escape hatch when the bundled dependency is broken. |
|
|
68
69
|
| `AKM_AUTO_CURATE` | `1` | Set to `0` to disable automatic prompt curation. |
|
|
69
70
|
| `AKM_AUTO_FEEDBACK` | `1` | Set to `0` to disable automatic outcome feedback. |
|
|
70
|
-
| `AKM_AUTO_HINTS` | `1` | Set to `0` to skip the per-session `akm hints` call. The missing-bundle warning is deliberately not gated on this: it explains why the
|
|
71
|
+
| `AKM_AUTO_HINTS` | `1` | Set to `0` to skip the per-session `akm hints` call. The missing-bundle warning is deliberately not gated on this: it explains why the bundle is empty in the first place. |
|
|
71
72
|
| `AKM_AUTO_MEMORY` | `1` | Set to `0` to disable automatic memory harvesting — the interval-gated `akm proposal extract` on `session.idle`, which is the whole of that harvest here. The Claude plugin honours the same variable for its `SessionEnd` extract, so one setting covers both harnesses. |
|
|
72
73
|
| `AKM_INDEX_ON_SESSION_END` | `1` | Set to `0` to skip the `akm index` refresh. It runs only on `session.deleted` — never on `session.idle`, which fires after every turn. |
|
|
74
|
+
| `AKM_WRITE_GATE` | `observe` | The format-declaration write gate (#99). When a file the session **read** declares a format your bundle documents — an `apiVersion:` namespace, a `yaml-language-server` pragma, a `$schema` key, an XML root namespace — and that asset has not been opened this session, the FIRST `edit`/`write` to that file is blocked once and the model is told which ref to read. It ships in `observe`: everything runs and the would-fire count lands in the ledger, but nothing is blocked. Set `enforce` to block, or `off`/`0` to disable it entirely. An unrecognized value is a configuration error — it logs one error per process and the gate refuses to run rather than guessing a default. It never fires on a file this session created: the create is recorded when it happens — a `write` to a path this session has not read, or an `edit` with an empty `oldString` — and that path stays insulated for the rest of the session, so reading back the model's own output does not re-arm it (ledger reason `session-created`). It self-disables when the AKM CLI does not resolve, and it is inert on `apply_patch` (which carries no file path) — that case logs one warning per process rather than failing quietly. |
|
|
73
75
|
|
|
74
76
|
### Scope
|
|
75
77
|
|
|
@@ -90,6 +92,8 @@ The `agent`, `run`, and `project` dimensions come from OpenCode itself (the acti
|
|
|
90
92
|
| `AKM_CURATE_LIMIT` | `5` | Maximum curated results injected per prompt. |
|
|
91
93
|
| `AKM_CURATE_MIN_CHARS` | `16` | Minimum prompt length for automatic curation. |
|
|
92
94
|
| `AKM_CURATE_TIMEOUT` | `8` | Timeout in seconds for AKM calls made by hooks. |
|
|
95
|
+
| `AKM_CURATE_MIN_SCORE` | `0` (disabled) | Minimum per-item relevance score to keep a curated result. `0` preserves the long-standing behavior. Set it above `0` and items below the floor are dropped (no curated block at all when none survive), and the survivors are reordered so locally authored assets (lesson, memory, knowledge, skill, command, agent, instruction, fact, workflow, task, env, secret) come before imported website/wiki snapshots. Same contract as the Claude plugin's `AKM_CURATE_MIN_SCORE` — see `claude/README.md` for the full explanation, including why there is no universal default value. |
|
|
96
|
+
| `AKM_CURATE_TYPE` | unset | Passthrough for `akm curate --type`. |
|
|
93
97
|
| `AKM_CONTEXT_BUDGET_CHARS` | `4000` | Maximum length of the AKM text injected into the system prompt on one turn. Past it the block is truncated with a marker. |
|
|
94
98
|
| `AKM_PENDING_PROPOSAL_TIMEOUT` | `2` | Timeout in seconds for the pending-proposal count. Floored at 0.5s. |
|
|
95
99
|
| `AKM_SESSION_BUFFER_MAX_ENTRIES` | `200` | Per-session cap on buffered observations. Oldest entries are dropped first. |
|
|
@@ -111,7 +115,7 @@ These three are read once, when the plugin module is imported, so they must be s
|
|
|
111
115
|
|
|
112
116
|
## Usage
|
|
113
117
|
|
|
114
|
-
1. Start with `akm_curate` for task-oriented discovery.
|
|
118
|
+
1. Start with `akm_curate` for task-oriented discovery; set `pack` when you want the selected local content immediately.
|
|
115
119
|
2. Use `akm_search` when you know the concept name and need its exact ID.
|
|
116
120
|
3. Fetch the full concept with `akm_show` before relying on it.
|
|
117
121
|
4. Record the outcome with `akm_feedback`.
|