> ## Documentation Index
> Fetch the complete documentation index at: https://powercontext.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenCode

> Inject exact-turn context through native hooks and gate classified mutations with context.ask.

> [!WARNING]
>
> **Version-gated:** OpenCode `>=1.18.21,<2`. Versions outside that range are **Unsupported**. The package also declares Node `>=20`. A conditional real-host E2E covers `opencode run`, with the limits below.

OpenCode uses an owned native plugin and an owned bundled `project-context` Skill. `chat.message` prepares and captures. `experimental.chat.messages.transform` injects context only when the current turn matches the cached message exactly.

## Maturity and installation

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
powercontext setup opencode --source oceanbase/powercontext --ref master
powercontext server run
powercontext doctor opencode
```

Setup checks `opencode --version`, locates the config directory through `opencode debug paths`, and requires the built plugin plus `skills/project-context/SKILL.md`. It installs them at `<config>/plugins/powercontext-opencode.js` and `<config>/skills/project-context/`, with separate ownership manifests.

Setup preflights both target paths and refuses a foreign same-name plugin or Skill. Each installer has its own recovery behavior, but there is no transaction spanning both artifacts. An I/O failure after the plugin install can still leave a partial setup.

Doctor checks the executable and version, the owned Skill, and plugin activation. For activation it starts a short-lived `opencode serve` on loopback, polls `GET /session`, waits for a nonce written by the plugin, and then stops the process. It creates no session, passes no model, and does not check Server readiness, prompt hooks, injection, permission UI, or Skill execution.

## Minimal usage

Start OpenCode after the Server:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
opencode

# Optional checks from another terminal
opencode --version
powercontext doctor opencode
```

Then submit a normal coding prompt. Automatic recall and eligible prompt capture need no command. Use the mounted `pc_*` tools for exact Memory, Handoff, Experience, Skill, or Candidate-read operations. The plugin does not start or embed the PowerContext Server.

## Execution flow

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
chat.message(sessionID, messageID)
→ collect non-synthetic text parts
→ resolve the session directory and derive Scope
→ prepare context
→ keep one prepared turn per session, tagged with messageID
→ capture the user prompt independently

experimental.chat.messages.transform
→ find the latest user turn
→ require the same sessionID and exact messageID
→ skip if context is absent or already injected
→ append one synthetic untrusted part for that turn
```

Prepare runs before capture, but each has separate fail-open handling. A prepare failure does not normally suppress capture. A capture failure does not erase valid prepared content. Both calls still share the turn's HTTP budget and resolved session context.

`experimental.chat.system.transform` adds general usage guidance only. It is not the PreparedContext injection path.

## Scope and session cleanup

Scope resolution uses this order:

1. Use `POWERCONTEXT_OPENCODE_SCOPE_ID`; hash it to a bounded ID if needed.
2. Otherwise use the session directory as the derivation input. Explicit tools use `context.worktree || context.directory`.
3. Resolve the Git top-level and normalize `remote.origin.url` to a `git:` Scope when possible.
4. If no usable remote exists, hash the resolved project root to a stable `local:` Scope.

The directory or worktree is an input to derivation, not a Scope that takes precedence over Git identity.

`session.created` and `session.updated` refresh the directory cache. If no entry exists, the plugin calls `client.session.get`. `session.deleted` removes both that entry and the session's prepared turn. The runtime keeps at most one prepared turn per session, rather than a map containing every `(sessionID, messageID)` pair.

Exact matching prevents an older result from entering the wrong turn. There is still an out-of-order race: an older prepare can finish last and replace the newer cache entry. The newer turn then misses injection instead of receiving stale context. Concurrent-turn behavior is **Not validated**.

## Injection

PreparedContext must satisfy `powercontext.prepared-context.v1`, including matching `content_bytes`. The configured prepared-content bound defaults to 8,000 bytes and accepts 512–32,768 bytes. The HTTP client separately caps a response body at 1 MiB.

The transform labels recalled content as host-supplied, untrusted historical evidence, marks the part synthetic, and preserves the session and message IDs. A second transform is idempotent.

`chat.message` does not rewrite the incoming part, and the plugin performs no explicit transcript write. Real-host transcript non-persistence is **Not validated**; the current unit evidence covers only the synthetic transform path.

## Capture and flush

Capture excludes synthetic parts. It writes a deterministic prompt Source with `origin`, event, cwd, session, and message metadata. Automatic capture is on by default. It skips capture when disabled, when a prompt looks like a private key or credential, or when its UTF-8 size exceeds 200,000 bytes.

Prepare receives the prompt before the capture filter runs. A secret-looking prompt may therefore be sent to the configured Server as a recall query even though it is not persisted as a Source. Recall transmission and Source capture are separate privacy decisions.

Automatic flush is optional and off by default. When enabled, a positive capture position starts a bounded `flush_memory` cursor loop. Success requires `current_cursor >= position`; error or call-budget exhaustion fails open and does not prove that a Memory exists. OpenCode has no pending boundary flusher, and its optional flush path has no OpenCode-specific test, so the flush E2E is **Not validated**.

The automatic path captures neither the final assistant response nor a Task Outcome.

## Owned plugin and bundled Skill

Setup may refresh an owned install but preserves foreign paths. The Skill conflict path is directly tested; the equivalent foreign-plugin conflict follows the same implementation but lacks its own direct test.

The installed `project-context` directory is a bundled OpenCode Skill. It teaches the host when to use native plugin tools. It is not a managed Skill export. OpenCode is not a current managed export target, and real-host Skill discovery remains **Not validated**.

## Native tools and permission

The plugin mounts 19 curated HTTP tools. They cover Memory reads and mutations, manual prepare/capture, Handoff activate/prepare/finalize/commit/continue, Experience and Skill generate/get, and read-only Candidate Review list/get.

It does not mount Candidate approve/reject/revise, Work Contract creation, Handoff acknowledgement, Task Outcome recording, external-Skill registry, or Handoff-report operations. Human Candidate mutation remains outside the model surface through the Dashboard or a direct human-controlled API client.

Before one of eight classified mutations, the tool calls host `context.ask()` with permission `powercontext` and the operation ID. Those mutations are: remember, capture Source, revise or retire Memory, activate or commit Handoff, generate Experience, and generate Skill. This boundary is **Host-gated**. `pc_remember` has a tested ask-and-success path. A rejected ask stops before HTTP by control flow, but real UI allow/deny and a direct denial test are **Not validated**.

Explicit mutation payloads also reject secret-looking nested strings before transport. This check occurs after `context.ask()`, so the host can ask before returning `secret_rejected`.

## Failure behavior

Automatic prepare, capture, injection, and optional flush fail open. Server unavailability or missing session context must not block normal OpenCode work. Explicit tool errors remain model-visible. A configuration error disables the plugin hooks with a warning instead of crashing the host.

## Negative experiments

Run these when changing setup or the plugin. Treat them as a deployment checklist, not as a claim that every item has an automated test:

* Report `1.18.20` or `2.0.0` from `opencode --version`; setup must refuse before installation.
* Put an unowned target at either artifact path; setup must preserve it and refuse the install.
* Stop the Server, submit a prompt, and confirm OpenCode continues without recalled context.
* Prepare one message, then transform a different session or message ID; nothing should be injected.
* Complete two prepares out of order; stale context must not enter the newer turn, though the newer injection may be missed.
* Transform the matching turn twice; only one synthetic part should exist.
* Delete the session, reuse its old IDs, and confirm both caches are empty.
* Submit a secret-looking or over-200,000-byte prompt; recall may run, but capture must not.
* Deny a classified mutation and confirm no HTTP operation runs.
* Enable flush, keep the cursor behind the captured position, and confirm the bounded loop does not claim Memory exists.
* Inspect model tools and confirm Candidate mutation, Work Contract, acknowledgement, and Task Outcome operations are absent.

## Unsupported vs Not validated

| State | Current boundary |
| - | - |
| **Supported** | Declared OpenCode gate `>=1.18.21,<2`; owned plugin and bundled-Skill setup; automatic prepare and eligible prompt capture; exact-turn transform logic; curated 19-tool surface; ask-before-classified-mutation control flow; conditional real-host `opencode run` prepare/capture smoke. |
| **Unsupported** | OpenCode `<1.18.21` or `>=2`; overwriting foreign same-name paths; managed Skill export to OpenCode; automatic final-response capture or Task Outcome; model-driven Candidate mutation; the unmounted Work Contract, acknowledgement, Outcome, external-Skill registry, and Handoff-report operations; transactional rollback spanning both installed artifacts. |
| **Not validated** | Compatibility across every accepted release; real-host model dispatch, injection, transcript non-persistence, permission UI, bundled-Skill discovery, cache cleanup, and optional flush; direct upper-version and foreign-plugin tests; reordered concurrent turns; real-host secret and size filtering. |

The conditional real-host E2E launches a real `opencode run`, uses an invalid model and empty PreparedContext, and observes prepare/capture HTTP requests. It proves neither model dispatch nor transform injection. Doctor's nonce probe is a separate activation check.

## Configuration defaults

The plugin reads connection settings from the environment. These defaults control automatic recall and capture:

| Key | Default | Meaning |
| - | - | - |
| `POWERCONTEXT_OPENCODE_BASE_URL` | `http://127.0.0.1:8000` | Running PowerContext Server |
| `POWERCONTEXT_OPENCODE_SCOPE_ID` | unset | Explicit Scope; otherwise derived from the repo |
| `POWERCONTEXT_OPENCODE_AUTHORIZATION` | unset | Complete Authorization header; secret-bearing |
| `POWERCONTEXT_OPENCODE_CAPTURE_PROMPTS` | `true` | Capture the current user prompt as Source |
| `POWERCONTEXT_OPENCODE_MAX_BYTES` | `8000` | Recall budget, clamped to `512–32768` |
| `POWERCONTEXT_OPENCODE_REQUEST_TIMEOUT_MS` | `1000` | Per-request HTTP timeout |
| `POWERCONTEXT_OPENCODE_HTTP_BUDGET_MS` | `4000` | Total prepare/capture budget for one turn |
| `POWERCONTEXT_OPENCODE_FLUSH_ON_CAPTURE` | `false` | Test-only: wait for flush after capture |

Do not put Authorization in a URL, prompt, or committed example. Use HTTPS outside loopback. Disable capture before launch when the current work must not become Source evidence:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
export POWERCONTEXT_OPENCODE_CAPTURE_PROMPTS=false
opencode
```

## Finish the shared check on this host

> What should happen after the OpenAPI contract changes?

1. Store the answer in a stable Scope with `pc_remember`. Pass `context.ask` first, then confirm the Citation.
2. Open a new session and ask the same question.
3. The recall must include a Citation and appear only as an exact-turn synthetic part on the current user turn. It must not enter the OpenCode transcript.
4. Stop the Server and ask again. Automatic recall may fail. Ordinary coding should continue. After you delete the old session, stale context must not be injected.
5. Run `pc_remember` again. The tool should return a failure such as `unavailable` and must not pretend the write succeeded.

## Completion checklist

Treat the integration as complete only when these results are observable:

* OpenCode is `>=1.18.21,<2`, and Node satisfies the package's `>=20` declaration.
* Setup installs both owned paths and documents the lack of cross-artifact rollback.
* Foreign plugin and Skill targets are preserved rather than overwritten.
* `powercontext doctor opencode` is treated as activation evidence, not a Server or model-turn test.
* Scope uses an explicit override, otherwise Git identity derived from the session/worktree directory, then a local-root hash.
* `chat.message` excludes synthetic text, prepares first, and captures with separate fail-open handling.
* Transform injection requires exact session and message IDs and remains idempotent.
* Concurrent out-of-order prepare is classified **Not validated** and can cause a missed, not wrong-turn, injection.
* `session.deleted` clears session context and the current prepared turn.
* Secret and byte-limit filtering applies to capture, while recall transmission is assessed separately.
* Optional flush is off by default, bounded by cursor position and calls, and never stands in for Memory verification.
* The 19-tool surface and eight `context.ask()`-gated mutations match the plugin.
* Candidate Review stays read-only on the model surface.
* Automatic assistant capture and Task Outcome stay **Unsupported**.
* Bundled Skill and managed Skill export remain distinct.
* Conditional real-host E2E limits remain visible.

Continue with [Pi](https://powercontext.mintlify.site/en/coding-agents/pi.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.