Release 0.9.0: land reviewed & fixed 0.9.0 onto main - #84
Open
fwdslsh-dev wants to merge 27 commits into
Open
Conversation
akm 0.9.0 removed the 0.8 deprecation aliases and the vault asset type. Update the plugin's live references to the akm CLI surface: - feedback note flag renamed to reason in runtime invocations (claude hook, opencode index queue/tool/retrospective/memory-promote paths) and in agent/skill/command docs. - opencode akm_curate: route summary through shape summary (it is a shape, not a verbosity; detail summary is a hard error in 0.9.0). detail normal/full unchanged. - vault to env/secret: opencode README akm_vault tool row becomes akm_env, vault sections rewritten for env path/run; AGENTS.md type lists and destructive-verb list; claude/README deprecated permission aliases removed (canonical proposal/sync entries already present). - tests: feedback assertions note to reason; sensitive-ref skip case vault:prod to env:prod; pre-tool fixture flat verbs to proposal subcommands; doc/log fixtures aligned. Historical eval baselines/fixtures under evals/ and CHANGELOG entries left as-is. Plugin version, package names, and unrelated logic untouched. Gate: bun test tests/ pass=324 fail=0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The user-prompt-expansion hook special-cased /akm-proposal accept|reject|drain (and bare 'proposal drain') with a proposal-specific 'confirm before mutating' note. That guard was the last remnant of the proposal-approval gating; the hard PreToolUse block was already removed. Proposal commands now get the same generic /akm- slash-command note as everything else; the memory-promote/reject note is unchanged (message tightened to 'mutating memory flows'). Updated the four affected user-prompt-expansion tests to match (memory note text; proposal reject/drain now assert the generic guidance). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t + accept 0.9.x The required-version range lived in three places with three syntaxes — the Claude hook constant, the OpenCode constant string, and a hand-rolled `minor === 8` integer matcher in opencode that had drifted from both. Bumping the range meant editing all three. - Add claude/shared/akm-version.ts: exports AKM_VERSION_RANGE and satisfiesAkmVersionRange(), the latter routing through the vendored semver matcher (the Claude hook runs as a bare Bun script with no node_modules, so it can't use the npm `semver` package). - Move vendor-semver.ts into claude/shared/ so both the hook and the vendored OpenCode tarball share one matcher. - akm-hook.ts and opencode/index.ts now import the shared range; deleted the duplicate constant and the hardcoded minor===8 check. - Widen the range to accept 0.9.x including prereleases (^0.9.0-beta.0 || ^0.9.0) so 0.9.0-beta.6 satisfies the gate. OpenCode is now consistent with (and as strict as) the Claude hook: patch-level prereleases like 0.8.1-rc0 that the old integer matcher accepted are now rejected by real semver, matching the hook. All published versions (0.8.0-rc.N, 0.8.x, 0.9.0-beta.N, 0.9.x) match on both sides. prepack vendoring carries both new shared files into the standalone OpenCode tarball; postpack reverts cleanly. 326 tests pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…idle (#79) * feat(claude): event-driven extraction on SessionEnd Fire `akm extract --type claude-code --session-id <id>` for the just-ended session so its durable insights reach the proposal queue in seconds instead of waiting for the periodic extract cron. - akm-hook.ts: new `extract-session` dispatch — reads the session_id from the SessionEnd stdin payload, skips transient terminations (reason clear/resume), and spawns extract detached + unref'd (never blocks session close). - plugin.json: register `extract-session` as a second SessionEnd hook. Idempotent + safe by design: `--session-id` respects the content-hash ledger (akm #602 / beta.33), so a re-fire or the periodic cron is a cheap skip with zero LLM calls — no `--force`. The cron remains the backstop for crashes that fire no hook. (opencode session.idle extraction intentionally deferred — needs a debounce/dedupe strategy to avoid flooding extract on every turn.) Tests: plugin.json registration + dispatch (clean no-op without akm on PATH; clear-reason skipped). Full suite green (326 → 328). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(opencode): event-driven extraction on session.idle (min-interval gate) opencode has no true "session end" event and session.idle fires after every turn, so naive idle-hooking would re-extract each turn (each turn changes the content hash → not a cheap ledger skip). Option #3: min-interval gate. - On session.idle, extract the session at most once per AKM_EXTRACT_MIN_INTERVAL_MS (default 10 min) via detached `akm extract --type opencode --session-id <id>`. A turn-burst collapses to one periodic checkpoint; the content-hash ledger (akm-cli #602 / >=beta.33) further no-ops unchanged content for free. - Per-session `sessionLastExtractAt` Map (module-scope, long-lived plugin), cleared in the session.deleted cleanup. Configurable via env. - Only on session.idle (not compacted/deleted). Fire-and-forget so it never stalls a turn. The periodic extract cron remains the backstop for the final delta after the last turn (idle gives periodic checkpoints, not end-capture). Tradeoff vs the Claude SessionEnd one-shot: idle-gated extraction fires mid-session (more cost than a single end extract) but is the cleanest option opencode's event surface allows without a debounce timer — and is still a large improvement over cron-only latency. Tests: session.idle → one extract spawn; rapid second idle is gated. Full plugin suite green (328). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test: make hook sandboxes hermetic to inherited AKM_* env (CI-only failures) `runHookSandboxed` (akm-version-check) and `runHook` (claude-plugin) spread `...process.env` into the spawned hook, so ambient/CI env leaked in. CI runners set AKM_PLUGIN_NO_AUTO_DEFAULT=1, which flipped the first-run auto-default OFF — making the "auto-default-agent write" + "session-start injects curated context" tests pass locally but fail in CI (the tier2 red blocking PR #79). Strip inherited AKM_* vars before spawning so the sandbox depends only on what each test sets. Reproduced + verified: full suite is 328/0 both with and without AKM_PLUGIN_NO_AUTO_DEFAULT=1. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test: pin XDG base dirs in hook sandboxes (CI-only auto-default failure) getAkmConfigPath() reads XDG_CONFIG_HOME. CI runners set it to a config that already has defaults.agent, so the first-run auto-default never fires — green locally (XDG_CONFIG_HOME unset), red in CI. Strip XDG_* from the inherited env and pin every XDG base dir to the sandbox tempDir so config reads are hermetic regardless of the ambient environment. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The plugin version was never bumped during the 0.9.0 cycle, so Claude Code's `/plugin` update keyed on the unchanged "0.8.2" string and kept serving the stale cached copy (without the SessionEnd extract hook). Bump all four version sources (marketplace.json, claude plugin.json, claude+opencode package.json) so the marketplace recognizes a new release and refreshes the install. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…/30 cron) The extract-session / session.idle hook comments described a "*/30 extract cron" backstop, but the shipped task set has no raw extract cron — the backstop is the hourly `akm improve` extract pass (default-tasks `frequent` @ `0 * * * *`). Comment-only; no behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The OpenCode plugin's "fails on load" symptom was a 444-byte INVALID_CONFIG_FILE blob printed to OpenCode's console on every load. Root cause: the plugin probes akm candidates with `akm --version`, and some akm builds validate the user's config on EVERY invocation. A bundled akm-cli@0.8.x against a config written by 0.9.x (whose improve process keys — e.g. proactiveMaintenance, recombine — 0.8 hard-rejects but 0.9 tolerates via passthrough) makes `--version` exit 78 and print the config error to stderr. probeCommand ran the probe with the child's stderr inherited, so that blob leaked to the console even though resolution correctly fell through to a compatible akm and the plugin worked. Two changes: - probeCommand now pipes (does not inherit) the probe's stderr, so a failing candidate is silent; the structured resolution trail / consent banner still surface a genuine no-akm case. - Bump bundled akm-cli ^0.8.0 -> ^0.9.0-beta.0 so the bundled fallback matches the 0.9 plugin and can actually parse 0.9 configs (no 0.8.x can). 0.9 reads older configs too, so it serves 0.8-config users as well. Verified: clean load (0 bytes leaked), akm_search returns real hits, 328/328 tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KyesPa1556aPpE3TQcnSP4
Make the bundled akm-cli a last-resort fallback instead of the
first-tried candidate. Resolution precedence is now:
1. AKM_LOCAL_BUILD_CLI (explicit dev override)
2. PATH / user installs (the akm the user installed — wrote their
config, has native deps like embeddings built)
3. bundled akm-cli (fallback for users with no akm)
Previously the bundle was tried first, so once it became config-
compatible (bumped to 0.9 beta) the plugin routed every command through
the bundled copy even when the user had a complete PATH install — losing
the user's native embedding support and any newer akm that understands a
newer config. A config-incompatible candidate still fails its `--version`
probe (older akm validates config on every call and exits non-zero) and
is skipped silently, so the version probe doubles as a config gate; no
extra config-validation machinery is needed.
Verified: with a real PATH akm present the plugin resolves source=path
(not bundled); search returns hits; 328/328 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KyesPa1556aPpE3TQcnSP4
The akm_curate tool mapped detail='summary' to `--shape summary`, but in
0.9.0 the summary shape is valid ONLY on `akm show`; curate hard-rejects
it with INVALID_SHAPE_VALUE ("'--shape summary' is only valid on 'akm
show'"). `--detail summary` is likewise INVALID_DETAIL_VALUE (curate
detail is brief|normal|full). Map the tool's friendly "summary" level to
the most concise valid curate detail, `brief`.
The bug escaped because the plugin tests mock execFileSync and never hit
the real CLI's value validation. Added a regression test pinning the
contract (detail 'summary' -> --detail brief, never --shape summary).
End-to-end 0.9.0 audit (verified against akm-cli 0.9.0-beta.50):
- All 16 subcommands the plugin invokes still exist.
- All projection/enum flags (--shape, --detail, --source, --status,
--type, --format) send only valid values; curate was the only break.
- Unknown flags are silently ignored by the CLI, so no other stale flag
hard-errors.
- Read paths (search/show/curate/proposal/env/secret/wiki/workflow list)
validated live.
329/329 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KyesPa1556aPpE3TQcnSP4
… (03-R1/06-M1) (#80) * fix(hooks): harden SubagentStart workflow injection + tag recalled content Plugin-side companions to the akm review-07 hardening. 07 P1-B (item 20): the SubagentStart hook injected the raw `akm workflow list --active` JSON into subagent context — including workflowTitle (verbatim from workflow frontmatter) and params (arbitrary user input), both attacker-influenceable. summarizeActiveWorkflows() now emits only run id + ref + status + current step, dropping title/params. 07 hardening (item 21): recalled/curated stash content is written to a file the agent reads (both the UserPromptSubmit prompt-recall and SessionStart paths). tagRecalledContent() prepends a provenance banner framing the block as reference DATA, not trusted instructions — the interim mitigation for the captureMemory injection surface that does NOT delete the write (that deletion stays deferred behind the minting-shutdown measurement gate). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018YjU1mGiShdDP4qFW7p4mv * feat(hooks): delete the SessionEnd captureMemory session_checkpoint write (03-R1/06-M1) The Claude plugin's SessionEnd `captureMemory()` path wrote a `session_checkpoint` memory via `akm remember … --force` on every Stop/SubagentStop/PreCompact — a below-every-improve-gate direct stash write (no judge/confidence/schema gate) that floods the stash with write-only telemetry. Meta-review 03-R1/06-M1 retires it. This is the akm-plugin half; the akm-side recombine exclusion filter is DEFERRED (load-bearing — it excludes all session-capture memories, not just checkpoints) and the update-stashes cron is a separate akm PR. Deleted (claude/hooks/akm-hook.ts): `captureMemory()` + its 3 call sites, the `capture-memory` CLI subcommand, helpers used only by it, and the now-dead Stop/SubagentStop/PreCompact hook registrations (their only command was `capture-memory …`). `akm index` on session-end survives — relocated into `sessionEnd()` under the same AKM_INDEX_ON_SESSION_END/akmAvailable gates. PRESERVED (verified by code-review): the memory-CANDIDATE pipeline (extractCandidatesFromText/appendCandidates/CANDIDATE_LOG → /akm-memory-promote), the `akm extract` SessionEnd path, and `tagRecalledContent` (the injection- hardening banner — NOT captureMemory-specific; wraps all recalled/curated content). Reviewer fixes applied: dropped the now-unused `redactObject` import; corrected the stale "harvest session memories at stop/compact time" README line. Tests: removed ~13 captureMemory/session_checkpoint tests; added 3 covering the relocated sessionEnd→index (runs index, respects opt-out, asserts no `remember`). Evals: the tier-2 `memory` metric replayed session logs through the now-deleted `capture-memory session-end`, so it's removed (metric + fixtures + diff policy rules + docs) and the checked-in baseline regenerated via `baseline:update` (5 metrics, no `memory`). Latency drift in the regen is harmless — latency is opt-in (`--include-latency`), not gated by default. Gate: `bun test tests/` 319/0; `tier2/runner.ts --baseline` exit 0 (no regression). Follow-ups (out of scope): opencode/index.ts has its own parallel session_checkpoint write (sibling plugin); the recombine filter + live crontab removal + build/reinstall (~beta.59) remain. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018YjU1mGiShdDP4qFW7p4mv --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…eckpoint write (03-R1/06-M1) The opencode plugin's parallel session_checkpoint `remember --force` write — the sibling of the Claude-plugin write deleted in #80. It fired on every stop/idle/compacted/deleted event + per-turn (every N positive touches) + before improve/propose/evolve + a manual akm_memory action, flooding the stash with below-every-gate write-only telemetry. Meta-review 03-R1/06-M1 retires it. Deleted (opencode/index.ts): `captureSessionMemory` (the session_checkpoint body-builder + `remember --force` write), `maybeCheckpointSessionMemory`, `ensureFreshProposalCheckpoint`, and their helpers (formatEvidenceSummary, formatPathBullet, countByValue, uniqueRecent, sessionHasPendingCheckpointEvidence, getHarnessStatePaths) + dead state (AKM_MEMORY_CHECKPOINT_EVERY, sessionFinalMemoryCaptured, sessionSuccessfulAssetTouchCount). Removed all call sites: stop/idle handlers, the per-turn positive-feedback checkpoint, the akm_memory `checkpoint` action (dropped from the enum too), and the pre-improve/ pre-propose/pre-evolve checkpoints. `akm index` on session-end survives — `maybeIndexSessionMemory` now runs decoupled from the deleted write. PRESERVED: the candidate → /akm-memory-promote pipeline (extractCandidatesFromText/appendCandidates), the SessionEnd `akm extract` path, and `rememberTextAsMemory` (kept — the akm-curator (akm_evolve) output write at line ~3545 still uses it; that is a deliberate curator artifact, not the session_checkpoint telemetry, and is out of 03-R1's scope). Tests: deleted 5 that asserted the checkpoint/stop write + migrated 1 to assert `akm index` still runs on stop with NO `remember` call. Gate: `bun test tests/` 314/0, `tsc --noEmit` clean, `tier2/runner.ts --baseline` exit 0. Net −542 LOC. (Done directly, in Opus — the opencode/gpt-5.4 agent stalled on an OpenCode Zen monthly usage-limit; small requests trickled through but the deletion task hung.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018YjU1mGiShdDP4qFW7p4mv
… fable alias
Two fixes to the PreToolUse Agent-dispatch model-remap hook:
1. `preToolAgent()` returned `updatedInput: { model: resolved }`, which
REPLACES the entire Agent tool input with just the model — dropping
`prompt`, `subagent_type`, and every other param, so the dispatched Agent
call was malformed. Spread `...toolInput` so only `model` is overridden.
2. Add `fable` to `CC_VALID_MODEL_ALIASES` — Fable 5 (`claude-fable-5`) is a
real Claude Code model alias now, so it must pass through instead of being
remapped to `sonnet`.
Gate: tsc --noEmit 0 errors, bun test tests/ 314/0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018YjU1mGiShdDP4qFW7p4mv
…eted with 03-R1) The prior commit deleted `captureSessionMemory`, which did TWO things: the session_checkpoint `remember --force` write (correctly retired by 03-R1/06-M1) AND the memory-candidate extraction that feeds the owner-gated candidate -> /akm-memory-promote pipeline (a KEEP reference rung). The second went out with the first, so no candidates were harvested on session end. This passed `bun test tests/` locally only because three candidate tests read a persistent on-disk candidate log seeded by earlier runs under the same stable session IDs; CI's clean checkout had no such state and the tests failed (`expect(candidates.length).toBeGreaterThan(0)`). Fix: add `maybeExtractSessionCandidates(sessionID, reason)` — harvests explicit "remember ..." intents from the session buffer into the candidate log with NO stash write, wired into `stop` (the reliable terminal flush) and `session.deleted` (salvage before the buffer is discarded). Deleting the buffer after extraction is the de-dup that the removed `sessionFinalMemoryCaptured` Set used to provide. Candidate text is now sourced from memory-intent notes only (higher signal than the old full-checkpoint-body scan), which suits 03-R1's noise-reduction intent. Not wired into the recurring `session.idle`/`session.compacted` events — those fire per-turn and a per-turn buffer flush is exactly the churn 03-R1 retires; `session.idle` already runs the `akm extract` backstop. Gate (clean isolated HOME/XDG, CI-equivalent): tsc 0 errors, `bun test tests/` 314/0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018YjU1mGiShdDP4qFW7p4mv
…ememory feat(opencode): delete SessionEnd session_checkpoint write (03-R1/06-M1)
Full review of the claude/ and opencode/ plugins on release/0.9.0 (34c3871): code sharing, harness/akm integration, extensibility to new harnesses, stale docs, akm misalignments, bloat, and test/eval infrastructure, with prioritized release-blocker and structural recommendations. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015QQmSK1KRCYS4eyf8cCbm3
Brings the 0.9.0-beta.1 plugin code under the branch so the fixes from docs/reviews/release-0.9.0-plugin-review.md apply to the tree they were written against. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2xAm7LxvnJYQdPgvyAXWp
…t, remove stderr writes Addresses release blockers 4 and 5 plus two high/med findings from docs/reviews/release-0.9.0-plugin-review.md: - Delete the Agent-tool model remap (alias map, resolveModel, the PreToolUse rewrite and its permissionDecision:"allow" coupling, and the PreToolUse:Agent matcher in plugin.json). Model selection is the host platform's job; the remap floored unknown IDs to sonnet and bypassed user-configured ask rules. - Narrow AKM_VERSION_RANGE to ^0.9.0-beta.0 || ^0.9.0 and align AKM_PACKAGE_REF (akm-cli@^0.9.0-beta.0); the plugins already depend on 0.9-only CLI semantics (extract --session-id, --detail brief). - Remove the three process.stderr.write banners (AGENTS.md logging policy); equivalent info flows via additionalContext + state-dir logs. - Fix id-less session-file collision: sid ?? "unknown" -> sid || "unknown". Tests updated test-first; scoped suites green (84 pass). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2xAm7LxvnJYQdPgvyAXWp
… export, consent banner Addresses release blockers 1-3 plus the OpenCode side of blocker 4 from docs/reviews/release-0.9.0-plugin-review.md: - session.compacted no longer references the undeclared `captured` (leftover from the deleted checkpoint write); post_compact_summary events are written again with ref:null / status:skipped. - Delete the dead stop: hook (not part of @opencode-ai/plugin); the memory-candidate harvest now runs on session.idle, session.compacted, and session.deleted so it actually fires in practice. - Single plugin export: AkmPlugin only; server + default export removed so the loader cannot double-register hooks. - Consent banner routes through client.app.log instead of stderr and recommends akm-cli@^0.9.0-beta.0; dead semver dep dropped. - Test fixtures (opencode mocks, proposal-cache mocks, fake-akm shim) bumped from 0.8.x to 0.9.0 to match the narrowed AKM_VERSION_RANGE. Tests updated test-first; full suite green (325 pass). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2xAm7LxvnJYQdPgvyAXWp
…cycle events Review-gate follow-up to the harvest change in 351d437: harvesting on every session.idle wiped the session buffer even below the 2-entry noise floor, destroying lone cross-turn memory intents before a second entry could accumulate. Below-floor buffers now survive session.idle and session.compacted; only session.deleted clears them (the original discard-noise-at-end behavior). Test-first: new lifecycle test reproduces the cross-turn scenario and fails against the previous code. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2xAm7LxvnJYQdPgvyAXWp
…side of 4) Executes the documentation items from docs/reviews/release-0.9.0-plugin-review.md: - akm-setup.md inverted to the 0.9.x contract: detection keys on ^0.9.0-beta.0 || ^0.9.0, installs akm-cli@^0.9.0-beta.0; consent flow preserved. All live ^0.8.0 pins purged across root README, AGENTS.md, both plugin READMEs, SKILL.md, and command files (historical changelog-style notes kept). - SKILL.md dispatch recipe no longer uses bypassPermissions; enforcement goes through --allowedTools (spelling drift fixed); rotting hardcoded model IDs replaced with generic placeholders. - Removed-feature claims purged: session-summary memory writes (both curator agents + the OpenCode fallback prompt), phantom AKM_MEMORY_CHECKPOINT_EVERY, checkpoint-every-N-calls, phantom Stop/SubagentStop/PreCompact hooks, 'gate risky raw AKM Bash', experimental.session.compacting, phantom 'akm env show'; session-start auto-curate and CLI resolution order corrected to match code. - Parity tracker made truthful (#56 removed-in-0.8.0, #29/#31 not yet implemented) with its pinned tests updated; command/tool counts fixed; phantom 'save' verb -> sync; akm-curate.md aligned on --format json. - Session-start header prose made version-agnostic. - Stale docs/opencode-plugin-upgrade-plan.md archived under docs/archive/. - tier-3 README/comment no longer claim the removed prompt caching; tests/README points at the real hook path. Full suite green (326 pass). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2xAm7LxvnJYQdPgvyAXWp
Opus review of 0e2a3ed found three survivors: /akm-evolve still pointed the curator at never-written memory:claude-session-* memories (now the candidate log + prior curator reports), the root README and akm-help example still advertised the phantom 'save' verb (now sync), and SKILL.md still offered 'session summary' as an improvable asset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2xAm7LxvnJYQdPgvyAXWp
…ates atomic Executes item #13 from docs/reviews/release-0.9.0-plugin-review.md: - Claude hook: rotateLogIfOversized caps every append-file (session, feedback, memory logs, quality-cache, session buffers, events.jsonl, memory-candidates.jsonl) at AKM_PLUGIN_MAX_LOG_BYTES (1 MiB default), keeping the newest half via temp-file+rename. quality-cache entries now age out, so a proposed asset later promoted to curated gets re-probed instead of being misclassified forever. - OpenCode: clearSessionState() clears all 13 session-keyed maps on session.deleted (previously 10; retrospectiveState, sessionRecallAudit and pendingProposalSummaryCache leaked), deletes the session's curated tmp file, and a 7-day best-effort sweep prunes files from crashed sessions; sessionBuffer drop-oldest capped at 200 entries. - Shared: updateCandidateStatus() rewrites the candidates JSONL via temp-file+rename so concurrent hook processes cannot tear it. - Sync the fallback curator prompt's stale-memories wording with opencode/agent/akm-curator.md (docs-review follow-up). Test-first throughout; full suite green (333 pass). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2xAm7LxvnJYQdPgvyAXWp
…try-generated help tables Executes items #9 and #12 (plus the tsc half of #1) from docs/reviews/release-0.9.0-plugin-review.md: - tsconfig + @types for both plugins; the 5 execFileSync string|Buffer errors fixed at the root (options type now pins encoding: utf8); 'bun run typecheck' is zero-error on both and wired into CI. - New tests.yml workflow: frozen-lockfile installs, typechecks, help table --check, bun test. bun.lock committed for claude/, opencode/, evals/ (.gitignore un-ignores them); evals.yml no longer doubles as the unit-test lane. - release.yml: installs evals deps before tier-2, PR-comment step guarded against fork PRs, checkout uses the triggering ref so a release branch can actually be released. - docs/akm-help-registry.md is now the generated-from source of truth: new rows for extract/hints/help migrate/env (verified against the bundled akm-cli 0.9.0-rc.1), scripts/generate-help-tables.mjs regenerates the three consumer copies (akm-help.md, SKILL.md, the OpenCode embedded table - whose drifted rows this fixes) between markers; tests/help-registry-parity.test.ts checks all consumers and all columns, replacing the old command-cell-only test. - tests/fake-akm-contract.test.ts pins config/workflow/proposal/extract envelope shapes against the real bundled CLI (skips when absent); evals/lib/fake-akm.ts now answers those verbs with real-shaped envelopes instead of silently no-op'ing, and logs unhandled verbs. Full suite green (337 pass). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2xAm7LxvnJYQdPgvyAXWp
Closes the remaining confirmed findings from the Phase-3 Opus reviews: - refQuality now treats cache entries older than AKM_PLUGIN_QUALITY_TTL_MS (default 24h) as misses, so a proposed asset later promoted to curated is re-probed instead of staying misclassified on low-traffic installs; legacy timestamp-less lines re-probe rather than crash. - All three rotation/atomic-write helpers remove their temp file when renameSync fails, and keep the newest line instead of emptying a file whose single line exceeds the cap. - Registry command cells escape interior pipes so GitHub renders the generated tables correctly; the generator unescapes them when emitting the runtime TS table, whose content is unchanged. Test-first; full suite green (342 pass), both plugin typechecks clean, generator --check passes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2xAm7LxvnJYQdPgvyAXWp
The first CI run of tests.yml failed with 'Export named spawnSync not found in module node:child_process': tests/opencode-plugin.test.ts mock.module()s node:child_process without a spawnSync export, and bun:test module mocks leak across files in one process, so this test blew up whenever it loaded after the mock (file-order dependent — green locally, red in CI). Same root cause and same fix as the workaround already documented in tests/fake-akm-contract.test.ts. Verified by running the two files together in mock-first order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2xAm7LxvnJYQdPgvyAXWp
Incorporates fix/drop-proposal-prompt-guard so the fix is retained when this branch lands, rather than colliding with it later (both edit claude/hooks/akm-hook.ts). The user-prompt-expansion note no longer singles out /akm-proposal accept|reject|drain; proposal commands get the generic /akm- slash-command guidance, and the memory promote/reject note is scoped to memory flows. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A2xAm7LxvnJYQdPgvyAXWp
Lands the release/0.9.0 critical-review fixes: 7 release blockers (captured ReferenceError, dead OpenCode stop hook, triple export, 0.8.0 pin purge, model-remap deletion, bypassPermissions removal, stale-doc purge) plus structural items #9/#12/#13 (registry-generated help tables, CI typecheck + lockfiles + fake-akm contract test, state rotation/leak/atomicity), the CI help-registry test fix, and PR #77 (proposal prompt-note cleanup) folded in. Full suite 342 pass; both plugins typecheck clean.
Contributor
Eval diff
Metric deltas
Plugin surfaceNo surface changes. No regressions. |
There was a problem hiding this comment.
Pull request overview
This PR fast-forwards main to the fully reviewed release/0.9.0 branch, landing the 0.9.0 plugin/runtime contract updates, test/eval infrastructure hardening, and accompanying documentation cleanup for the AKM Claude + OpenCode plugins.
Changes:
- Centralizes the AKM CLI version contract for both harness plugins and updates version-dependent tests/docs accordingly.
- Strengthens CI correctness guarantees (typecheck in CI, generated help-table parity checks, fake-akm envelope contract pinning).
- Updates docs/evals to reflect the 0.9.0 behavior shifts (help registry as canonical source; removes tier-2 memory metric + related fixtures).
Reviewed changes
Copilot reviewed 57 out of 62 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/vendor-semver.test.ts | Updates vendored semver test coverage and import location. |
| tests/README.md | Updates test-suite documentation to match current plugin entrypoints and version contract. |
| tests/proposal-cache.test.ts | Updates mocked akm version output to 0.9.0. |
| tests/opencode-eval-harness.test.ts | Updates feedback CLI arg from --note to --reason. |
| tests/help-registry-parity.test.ts | Adds parity test that enforces generated help tables match the registry. |
| tests/fake-akm-contract.test.ts | Adds contract test that pins fake-akm JSON envelope shapes against a real akm binary. |
| tests/akm-version-check.test.ts | Expands version-contract tests; makes hook sandboxing hermetic; removes stderr expectations in favor of state-dir logging. |
| scripts/generate-help-tables.mjs | Adds generator to sync embedded help tables from the canonical registry doc (+ --check). |
| README.md | Updates repo-level docs for 0.9.0+ contract and updated feature/status notes. |
| opencode/tsconfig.json | Adds strict TS config for OpenCode plugin typechecking. |
| opencode/README.md | Updates OpenCode plugin docs for env/secret tooling, lifecycle behavior, and 0.9.0+ contract. |
| opencode/package.json | Bumps version to 0.9.0-beta.1; updates akm-cli dependency; adds typecheck tooling deps. |
| opencode/agent/akm-curator.md | Updates curator guidance to use memory candidates, and --reason for feedback. |
| evals/tier3/README.md | Updates tier-3 docs to reflect removal of prompt caching. |
| evals/tier3/judge/client.ts | Removes prompt-caching commentary/markers to match current judge behavior. |
| evals/tier2/runner.ts | Removes the memory metric wiring from tier-2 runner defaults and execution. |
| evals/tier2/metrics/memory.ts | Removes tier-2 memory metric implementation. |
| evals/tier2/baseline/tier2.md | Updates tier-2 baseline report to current plugin version and metric set (no memory metric). |
| evals/tier2/baseline/tier2.json | Updates tier-2 baseline JSON to current plugin version and metric set (no memory metric). |
| evals/README.md | Updates eval framework docs for the reduced tier-2 metric set and tier-3 run behavior. |
| evals/package.json | Updates description and scripts to remove tier2:memory. |
| evals/lib/fake-akm.ts | Extends fake-akm to model additional verbs/envelopes; logs unknown verbs to stderr for visibility. |
| evals/lib/diff.ts | Removes memory-metric keys from the default diff regression policy. |
| evals/fixtures/session-logs/vault-leak-attempt/sess-vault.md | Removes session-log fixture (memory metric removed). |
| evals/fixtures/session-logs/sparse-single-entry/sess-sparse.md | Removes session-log fixture (memory metric removed). |
| evals/fixtures/session-logs/rich-multi-asset/sess-rich.md | Removes session-log fixture (memory metric removed). |
| evals/fixtures/session-logs/README.md | Removes session-log fixture README (memory metric removed). |
| evals/fixtures/session-logs/memory-intent-only/sess-intent.md | Removes session-log fixture (memory metric removed). |
| evals/bun.lock | Adds evals lockfile for frozen installs. |
| docs/reviews/release-0.9.0-plugin-review.md | Adds the 0.9.0 critical review document (and references for fixes landed). |
| docs/archive/opencode-plugin-upgrade-plan.md | Marks the old OpenCode upgrade plan as archived and superseded. |
| docs/akm-help-registry.md | Reframes registry as canonical source; adds markers and documents generation workflow; adds new rows. |
| claude/tsconfig.json | Adds strict TS config for Claude hook/shared code typechecking. |
| claude/skills/akm/SKILL.md | Updates skill docs for 0.9.0+ and replaces embedded help table with generated region. |
| claude/shared/vendor-semver.ts | Moves/introduces the vendored semver implementation under shared for cross-plugin use. |
| claude/shared/memory-events.ts | Adds state-file rotation/capping for events.jsonl. |
| claude/shared/memory-candidates.ts | Adds atomic rewrites and rotation/capping for memory-candidates.jsonl. |
| claude/shared/akm-version.ts | Introduces shared single source of truth for AKM version contract. |
| claude/README.md | Updates Claude plugin docs for 0.9.0+ contract and revised hook behavior/output channels. |
| claude/package.json | Bumps version to 0.9.0-beta.1; adds typecheck script and dev deps. |
| claude/commands/akm-setup.md | Updates setup instructions for the 0.9.0-beta.0/0.9.0 version contract. |
| claude/commands/akm-proposal.md | Updates proposal command frontmatter to remove v0.8.0-specific phrasing. |
| claude/commands/akm-memory-promote.md | Updates feedback CLI arg from --note to --reason. |
| claude/commands/akm-improve.md | Updates improve command note to remove v0.8.0-specific phrasing. |
| claude/commands/akm-help.md | Updates /akm-help docs and replaces embedded help table with generated region. |
| claude/commands/akm-feedback.md | Updates feedback CLI arg from --note to --reason. |
| claude/commands/akm-evolve.md | Updates evolve command to reference memory candidates/prior curator reports (not session-summary memories). |
| claude/commands/akm-curate.md | Updates curate command to use JSON output consistently. |
| claude/bun.lock | Adds Claude lockfile for frozen installs. |
| claude/agents/akm-curator.md | Updates curator guidance to use memory candidates and --reason for feedback. |
| claude/.claude-plugin/plugin.json | Bumps plugin version; removes deprecated hooks/matchers; adds extract-session hook on SessionEnd. |
| AGENTS.md | Updates repo-wide agent guidance for 0.9.0+ and env/secrets terminology/verbs. |
| .gitignore | Stops ignoring bun.lock so lockfiles can be committed. |
| .github/workflows/tests.yml | Adds a dedicated Tests workflow with frozen installs, typecheck, help-table check, and unit tests. |
| .github/workflows/release.yml | Ensures workflows run on the triggering ref and adds frozen installs + typecheck. |
| .github/workflows/evals.yml | Uses frozen installs; avoids failing fork PRs on comment step; removes unit-test duplication from eval workflow. |
| .claude-plugin/marketplace.json | Bumps marketplace plugin version to 0.9.0-beta.1. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
38
to
+41
| describe("satisfies() — AKM_REQUIRED_RANGE behavior", () => { | ||
| // This is the exact range the Claude hook uses: see | ||
| // claude/hooks/akm-hook.ts:AKM_REQUIRED_RANGE. | ||
| const RANGE = "^0.8.0-rc.0 || ^0.8.0" | ||
| const RANGE = "^0.8.0-rc.0 || ^0.8.0 || ^0.9.0-beta.0 || ^0.9.0" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merges the fully reviewed and fixed
release/0.9.0intomain.mainis a clean fast-forward ancestor of this branch (27 commits), so there are no conflicts.What's in this branch
docs/reviews/release-0.9.0-plugin-review.md) and all its fixes, merged via Release 0.9.0-beta.1: Drop 0.8.x support, event-driven extraction #83:capturedReferenceError, dead OpenCodestophook → real lifecycle harvest, single plugin export,^0.8.0pin purge, model-remap deletion,bypassPermissionsrecipe removal, stale-doc purge.tsc --noEmitin CI + committed lockfiles + fake-akm contract test, state-file rotation / session-map leak fixes / atomic candidate writes.Consolidation note
This supersedes #82 (review doc — included here) and #77 (folded in); both were closed as subsumed.
release/0.9.0is now the single source carrying every open change.Verification
Full suite 342 pass / 0 fail; both plugins typecheck clean; help-registry parity
--checkpasses. CI on #83's head (e701d73) was green acrosstestandtier2(tier3skipped), with the eval diff reporting no metric changes and no regressions.🤖 Generated with Claude Code
Generated by Claude Code