feat: OpenCode context plugin (phase 2B) — pointer injection and attribution #2
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/shared-context"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What this is
Phase 2B of shared knowledge: the OpenCode plugin that makes a lesson learned in one project available to an agent working in another, without the agent having to ask.
Per prompt the plugin builds a query (prompt + project + working set), asks the hub once via
POST /matchunder a hard timeout, dedupes the returned lesson ids per session, renders a byte-stable block of pointers, and appends it as the last system part of the model request. Attribution (inject) is reported fire-and-forget. Every failure path is fail-open.Phase 2A — the hub-side matcher — is already on
main; this branch adds the client half and no Python.Runtime probe first
Spec §11 required the injection point be verified before anything was built, because two reference implementations disagreed. It was:
@opencode/plugin(not the stale@opencode-ai/pluginpinned in the global config).ctx.session.hook("context", …)exists, with the shape{ sessionID, model, system, messages, options, agent, tools }.event.system.push({ type: "text", text })reaches the outgoing request. No fallback path is needed.contextcovers the agent loop only; auxiliary flows have their own hook kinds.Design notes
@opencode/pluginis a type-only import. Tests arenode --testwith no install step./matchis bounded byREFLECT_MATCH_TIMEOUT_MS(150 ms default) and never rejects; a dead, slow, 5xx or garbage hub injects nothing and the session proceeds. The hook body is wrapped so any throw leaves the request untouched.src/config.ts,src/query.ts,src/block.ts,src/hub.ts,src/working-set.ts,src/plugin.ts,src/index.ts, with the package-rootindex.tsOpenCode actually resolves.~/.config/opencode/opencode.jsonc'spluginsarray.Testing
cd plugin/opencode && node --test), fixtures captured by the probe rather than hand-built.Deferred
Deferred minors and every ruling are in the branch's SDD ledger under
.superpowers/sdd/2026-10-15-shared-context/progress.md(git-ignored, present in the worktree). One parked item: the hanging-attribution test is self-fulfilling (it passes against the pre-fix code) — the implementation is correct by inspection, and a discriminating test is a small follow-up.Two robustness gaps in the hook/setup path: - The project label was env-only, so with REFLECT_PROJECT unset (the documented default) every inject row carried project: null even though SetupContext declares location.project.{id, canonical}. Resolve the fixed chain REFLECT_PROJECT -> ctx.location.project.canonical -> ctx.location.project.id -> null, log one line at setup naming the source, and pin the chain with a test. A blank value counts as absent at every step. - The hook body guarded matchLessons but nothing else, so a throw from noteToolCalls, buildQuery, consider or event.system.push would reject the promise OpenCode awaits. Wrap the whole body in try/catch that logs and fails open; a test freezes the system array so the push throws and asserts the event is left untouched.