pantheon-opencode 1.6.0-beta.1 → 1.6.0-beta.10
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/AGENTS.global.md +182 -0
- package/AGENTS.md +10 -891
- package/CHANGELOG.md +326 -0
- package/README.md +496 -32
- package/README.pt-BR.md +285 -20
- package/bin/pantheon-init.mjs +26 -3
- package/commands/pantheon-audit.md +7 -1
- package/commands/pantheon-consolidate.md +1 -1
- package/commands/pantheon-deepwork.md +14 -3
- package/commands/pantheon-focus.md +17 -0
- package/commands/pantheon-vision.md +61 -12
- package/package.json +21 -14
- package/plugin.json +2 -2
- package/pyproject.toml +8 -6
- package/scripts/build-agents-md.mjs +374 -56
- package/scripts/changelog-merge.mjs +161 -0
- package/scripts/{code_mode_server.py → code_mode.py} +3 -3
- package/scripts/cost.mjs +244 -41
- package/scripts/doctor.mjs +151 -1
- package/scripts/install/agents-md.mjs +4 -4
- package/scripts/install/config-migration.mjs +317 -4
- package/scripts/install/health-check.mjs +21 -19
- package/scripts/install/interactive.mjs +1 -1
- package/scripts/install/opencode-version.mjs +246 -4
- package/scripts/install/opencode.mjs +627 -179
- package/scripts/install/plugin.mjs +43 -9
- package/scripts/install/shared.mjs +120 -12
- package/scripts/install/vision-prompt.mjs +161 -0
- package/scripts/install-mcp.mjs +28 -9
- package/scripts/{mcp_persistence_server.py → mcp_persistence.py} +2 -2
- package/{src/mcp/mcp_resources_server.py → scripts/mcp_resources.py} +2 -2
- package/scripts/{memory_mcp_server.py → memory_mcp.py} +2 -2
- package/scripts/probe-context-rehydrate.mjs +8 -2
- package/scripts/probe-pantheon-cost.mjs +71 -15
- package/scripts/run-node-tests.mjs +189 -0
- package/scripts/sync-artifacts.mjs +26 -13
- package/scripts/sync-tui.mjs +24 -3
- package/scripts/test-opencode-v2-sandbox.sh +180 -26
- package/scripts/validate-routing.mjs +3 -3
- package/scripts/validate-sandbox-install.mjs +138 -0
- package/scripts/versioning.mjs +13 -1
- package/scripts/vision-status.mjs +682 -0
- package/skills-lock.json +8 -8
- package/src/agents/aphrodite.md +20 -37
- package/src/agents/apollo.md +7 -3
- package/src/agents/athena.md +63 -35
- package/src/agents/demeter.md +8 -28
- package/src/agents/gaia.md +1 -1
- package/src/agents/hephaestus.md +10 -21
- package/src/agents/hermes.md +15 -38
- package/src/agents/iris.md +1 -1
- package/src/agents/mnemosyne.md +18 -54
- package/src/agents/nyx.md +1 -1
- package/src/agents/prometheus.md +16 -20
- package/src/agents/talos.md +10 -2
- package/src/agents/themis.md +5 -5
- package/src/agents/zeus.md +99 -129
- package/src/instructions/agent-return-format.instructions.md +18 -3
- package/src/instructions/backend-standards.instructions.md +2 -0
- package/src/instructions/frontend-standards.instructions.md +3 -1
- package/src/instructions/memory-protocol.instructions.md +11 -110
- package/src/instructions/zeus-anti-stall.instructions.md +14 -61
- package/src/instructions/zeus-communication-rules.instructions.md +0 -1
- package/src/instructions/zeus-council-synthesis.instructions.md +32 -260
- package/src/instructions/zeus-memory-operations.instructions.md +26 -0
- package/src/instructions/zeus-timeout-retry.instructions.md +40 -87
- package/src/mcp/{code_mode_server.py → code_mode.py} +3 -3
- package/src/mcp/eval_store.py +2 -2
- package/src/mcp/{mcp_persistence_server.py → mcp_persistence.py} +2 -2
- package/{scripts/mcp_resources_server.py → src/mcp/mcp_resources.py} +2 -2
- package/src/mcp/{memory_mcp_server.py → memory_mcp.py} +2 -2
- package/src/mcp/{pantheon_vision_server.py → pantheon_vision.py} +286 -42
- package/src/mcp/requirements-mcp.txt +6 -4
- package/src/mcp/requirements-vision.txt +2 -2
- package/src/pantheon/cost-command.ts +399 -101
- package/src/pantheon/delegation-enforce.ts +10 -1
- package/src/pantheon/presets.d.mts +0 -8
- package/src/pantheon/presets.mjs +5 -32
- package/src/pantheon/v2-bounded-read.ts +640 -0
- package/src/pantheon/v2-delegation-enforce.ts +214 -0
- package/src/pantheon/v2-execute-after.ts +186 -0
- package/src/pantheon/v2-tools.ts +429 -0
- package/src/pantheon/v2-unsupported.d.mts +11 -0
- package/src/pantheon/v2-unsupported.mjs +90 -0
- package/src/pantheon/v2-vision.ts +622 -0
- package/src/pantheon/vision-local.ts +531 -0
- package/src/pantheon/vision.ts +1160 -115
- package/src/plugin-v2.ts +1145 -219
- package/src/plugin.ts +12 -9
- package/src/plugins/tui/dist/server.d.ts +1 -2
- package/src/plugins/tui/dist/server.d.ts.map +1 -1
- package/src/plugins/tui/dist/tui-v2.d.ts +154 -0
- package/src/plugins/tui/dist/tui-v2.d.ts.map +1 -0
- package/src/plugins/tui/dist/tui-v2.js +659 -0
- package/src/plugins/tui/dist/tui-v2.js.map +1 -0
- package/src/plugins/tui/dist/tui.d.ts +85 -82
- package/src/plugins/tui/dist/tui.d.ts.map +1 -1
- package/src/plugins/tui/dist/tui.js +72 -59
- package/src/plugins/tui/index-v2.ts +6 -0
- package/src/plugins/tui/package-lock.json +5516 -1353
- package/src/plugins/tui/package.json +22 -12
- package/src/plugins/tui/src/index-v2.tsx +734 -0
- package/src/plugins/tui/src/index.tsx +106 -85
- package/src/plugins/tui/src/opencode-v2.d.ts +13 -0
- package/src/plugins/tui/tsconfig.build.json +5 -0
- package/src/plugins/tui/tsconfig.typecheck.json +5 -0
- package/src/plugins/tui/tsdown.config.ts +22 -2
- package/src/plugins/tui/tui-v2.ts +2 -0
- package/src/plugins/tui/tui.ts +3 -0
- package/src/routing.yml +11 -21
- package/src/skills/README.md +3 -3
- package/src/skills/agent-coordination/SKILL.md +7 -2
- package/src/skills/artifact-management/SKILL.md +12 -5
- package/src/skills/auto-continue/SKILL.md +39 -30
- package/src/skills/code-review-checklist/SKILL.md +5 -5
- package/src/skills/context-compression/SKILL.md +26 -879
- package/src/skills/session-goal/SKILL.md +14 -5
- package/src/skills/spec-driven-development/SKILL.md +3 -1
- package/src/skills/tdd-with-agents/SKILL.md +18 -10
- package/opencode.json +0 -58
package/README.md
CHANGED
|
@@ -31,7 +31,9 @@ way to plan work, make progress, check results, and keep useful project context.
|
|
|
31
31
|
## Start in 2 minutes
|
|
32
32
|
|
|
33
33
|
Requirements: [OpenCode 1.18.4+](https://opencode.ai/docs/) and Node.js
|
|
34
|
-
22.22.2+ (or 24.15.0+ / 26+).
|
|
34
|
+
22.22.2+ (or 24.15.0+ / 26+). For which OpenCode generation each Pantheon
|
|
35
|
+
release line supports, see
|
|
36
|
+
[Compatibility and support policy](#compatibility-and-support-policy).
|
|
35
37
|
|
|
36
38
|
Pantheon declares `engines.node` as `^22.22.2 || ^24.15.0 || >=26.0.0`. The
|
|
37
39
|
floor reflects what the dependency tree actually needs — the transitive
|
|
@@ -50,6 +52,11 @@ opencode
|
|
|
50
52
|
The installer guides you through the available setup. For optional MCP servers,
|
|
51
53
|
project-local installation, or non-interactive setup, see the
|
|
52
54
|
[installation guide](docs/INSTALLATION.md).
|
|
55
|
+
The bundled Python MCP servers use the pinned MCP SDK 2.2.0 and standalone
|
|
56
|
+
FastMCP 4.0.10 runtime; see the [MCP guide](docs/MCP.md).
|
|
57
|
+
The installer also turns each agent's `mcp_tools` allowlist into native
|
|
58
|
+
per-agent permissions for OpenCode V1 and V2; see the
|
|
59
|
+
[agent MCP reference](docs/AGENT-MCP.md).
|
|
53
60
|
|
|
54
61
|
## A simple example
|
|
55
62
|
|
|
@@ -60,6 +67,10 @@ Once OpenCode is running, describe the outcome you want:
|
|
|
60
67
|
```
|
|
61
68
|
|
|
62
69
|
Pantheon helps turn that request into a plan and a sequence of reviewed steps.
|
|
70
|
+
When you ask for a plan or start `/pantheon-deepwork`, Athena returns the full
|
|
71
|
+
plan to Zeus, who displays it in the main conversation before asking for
|
|
72
|
+
approval. The approval prompt will not point to a plan hidden in a child-agent
|
|
73
|
+
conversation.
|
|
63
74
|
|
|
64
75
|
## Who is it for?
|
|
65
76
|
|
|
@@ -76,13 +87,100 @@ clear handoff between stages of work.
|
|
|
76
87
|
- Project memory that helps preserve relevant context between sessions.
|
|
77
88
|
- Optional integrations for common development tasks.
|
|
78
89
|
|
|
90
|
+
Memory is used selectively: the coordinator searches once only when project
|
|
91
|
+
history could affect a task, then passes relevant results to specialists. Store
|
|
92
|
+
one concise, reusable outcome at task completion when it will matter later;
|
|
93
|
+
routine child summaries and phase updates stay in the current handoff. The
|
|
94
|
+
session-checkpoint tools are separate, optional persistence APIs and are not
|
|
95
|
+
called automatically by compaction hooks. See [Memory usage](docs/MEMORY.md).
|
|
96
|
+
|
|
79
97
|
## Status
|
|
80
98
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
and
|
|
99
|
+
Candidate version: the manifests in this checkout express the version being
|
|
100
|
+
prepared, not a confirmed publication. A beta is published only after the
|
|
101
|
+
Release workflow completes successfully. To check which version is actually
|
|
102
|
+
published, consult the npm `beta` dist-tag. Pantheon is designed for OpenCode
|
|
103
|
+
and depends on the availability and configuration of OpenCode and any optional
|
|
104
|
+
services you choose to use. Check the
|
|
105
|
+
[releases](https://github.com/ils15/pantheon-opencode/releases) and
|
|
106
|
+
[changelog](CHANGELOG.md) for the latest published changes.
|
|
107
|
+
|
|
108
|
+
## Compatibility and support policy
|
|
109
|
+
|
|
110
|
+
> ### ⚠️ 1.6.x is the LAST line that supports OpenCode 1.X
|
|
111
|
+
>
|
|
112
|
+
> **OpenCode 1.X support ends after the 1.6 line.** From **1.7 onward, every
|
|
113
|
+
> release is a breaking change targeting OpenCode 2.** A 1.6.x install is the
|
|
114
|
+
> last one that runs on an OpenCode 1.X host; do not plan an upgrade across the
|
|
115
|
+
> 1.6 → 1.7 boundary while your host is still on OpenCode 1.X.
|
|
116
|
+
|
|
117
|
+
| Pantheon line | OpenCode 1.X host | OpenCode 2 host |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| **1.6.x** (current line) | **Supported.** V1 plugin contract | Supported, reduced surface — V2 contract |
|
|
120
|
+
| **1.7 and later** | **Not supported.** Breaking change | Target of the 1.7+ work |
|
|
121
|
+
|
|
122
|
+
Both columns of the 1.6.x row are real, and they are not the same claim. Read
|
|
123
|
+
[the plugin contract](#opencode-v1v2--dual-version-160-beta1) for what each
|
|
124
|
+
generation actually registers.
|
|
125
|
+
|
|
126
|
+
### What "supported on OpenCode 1.X" concretely means
|
|
127
|
+
|
|
128
|
+
On the 1.6 line, an OpenCode 1.X host gets the **V1 plugin**:
|
|
129
|
+
`src/plugin.ts` plus `src/plugins/pantheon-hooks.ts`, registered under the
|
|
130
|
+
singular `plugin` config key. That surface registers 6 tools
|
|
131
|
+
(`hashline_edit`, the 3 `pantheon_goal_*` tools, `pantheon_cost`,
|
|
132
|
+
`pantheon_model`), the BackgroundJobBoard lifecycle, the V1 event/tool hooks and
|
|
133
|
+
the V1 compaction path. It is selected automatically: the generation gate
|
|
134
|
+
(`--opencode-version`, else `OPENCODE_VERSION`, else a `OPENCODE_BIN` basename of
|
|
135
|
+
`opencode2`, else a `--version` probe where major ≥ 2 selects V2) resolves a 1.X
|
|
136
|
+
host to V1.
|
|
137
|
+
|
|
138
|
+
The two generations are exclusive. The installer strips Pantheon references from
|
|
139
|
+
both config shapes and registers only the selected one, so a 1.X host never
|
|
140
|
+
loads the V2 plugin and a V2 host never loads the V1 plugin. Forcing V2 on a 1.X
|
|
141
|
+
host is an unsupported mixed/wrong-generation configuration, not a supported mode.
|
|
142
|
+
|
|
143
|
+
### What the OpenCode 2 path is — and is not
|
|
144
|
+
|
|
145
|
+
**Not inert.** The V2 path (`src/plugin-v2`, registered as a directory because
|
|
146
|
+
the V2 loader rejects bare file paths) registers real tools with real
|
|
147
|
+
`input`/`output` schemas via `ctx.tool.transform()`, 5 event subscriptions,
|
|
148
|
+
session hooks and tool/permission hooks that enforce read-only sessions and the
|
|
149
|
+
caller→target delegation matrix. The matrix applies only to Pantheon-managed
|
|
150
|
+
targets: Zeus may delegate to any registered agent; Athena and Hermes may target
|
|
151
|
+
Apollo only; other Pantheon callers and unknown callers are denied. Child
|
|
152
|
+
sessions cannot delegate to Pantheon agents. Calls between native/custom agents
|
|
153
|
+
remain under host permissions. The V2 path never adds an allow grant or
|
|
154
|
+
overrides an explicit host deny; missing or mismatched identity fails closed
|
|
155
|
+
for the attempted Pantheon delegation. The 3 goal tools remain unsupported and
|
|
156
|
+
are reported as `goal-tools`.
|
|
157
|
+
|
|
158
|
+
When the host successfully registers V2's permission hook, Pantheon does not
|
|
159
|
+
trust `permission.evaluate.agent` by itself for a Pantheon target. It matches
|
|
160
|
+
the permission source's session, message and tool-call IDs to a short-lived
|
|
161
|
+
record from the host's `tool.execute.before` event, then requires the host
|
|
162
|
+
session to have no `parentID` before applying the matrix. This admits valid
|
|
163
|
+
root dispatches and denies child-session dispatches; missing, stale, replayed
|
|
164
|
+
or mismatched origins are denied. OpenCode v2.0.29 runtime evidence is in
|
|
165
|
+
[`bench/results/f4a-v229-admission-identity-2026-10-14.md`](bench/results/f4a-v229-admission-identity-2026-10-14.md).
|
|
166
|
+
|
|
167
|
+
**Partial, with the exercised host version made explicit.** The V2 tool canary
|
|
168
|
+
started against `opencode 2.0.22`, a version that no npm channel publishes.
|
|
169
|
+
The current F4A rerun now uses the installable **OpenCode v2.0.29** binary and
|
|
170
|
+
passes 18/18 checks with permission probes: the real plugin registers and runs
|
|
171
|
+
its tools, admits the valid Zeus→Apollo root dispatch, rejects an invalid edge
|
|
172
|
+
before child creation, and rejects a matrix-valid dispatch from a child. The
|
|
173
|
+
remaining V2 surface still has unsupported goal tools and registration-only
|
|
174
|
+
session/compaction hooks, so the 1.6 line is not full V2 feature parity.
|
|
175
|
+
|
|
176
|
+
### Verified against which OpenCode versions
|
|
177
|
+
|
|
178
|
+
| What | Verified against | How |
|
|
179
|
+
|---|---|---|
|
|
180
|
+
| V1 plugin + generation gate | The OpenCode 1.18.x line. This package pins `@opencode-ai/plugin` and `@opencode-ai/sdk` to `1.18.33`; the highest published `opencode-ai` host package (the one shipping the `opencode` binary) is `1.18.34` | Dependency pin (`package.json`); generation-gate unit tests over injected host banners; installer end-to-end tests asserting the emitted `opencode.json` shape |
|
|
181
|
+
| V2 plugin tool surface | OpenCode v2.0.29 | `tests/canary/plugin-v2-tool-canary.test.mjs`, driving the real plugin through `opencode serve`; F4A permission canary passes 18/18 |
|
|
182
|
+
| V2 native subagent admission | OpenCode v2.0.29 | `tests/canary/run-v2-permission-proof.sh`; identity, root/child checks and permission-before-child ordering are recorded in [`bench/results/f4a-v229-admission-identity-2026-10-14.md`](bench/results/f4a-v229-admission-identity-2026-10-14.md) |
|
|
183
|
+
| Exact 1.X host version the 1.6 line is exercised against end-to-end | **Unverified.** No V1 host leg exists: the sandbox runner is V2-only and `--run v1` is rejected | — |
|
|
86
184
|
|
|
87
185
|
## Delegation (native `task()`)
|
|
88
186
|
|
|
@@ -93,6 +191,28 @@ there is no Pantheon-specific delegation tool surface to configure. See
|
|
|
93
191
|
[ADR-0011](.pantheon/memory-bank/adr/0011-delegation-engine-contract.md) for the
|
|
94
192
|
historical engine contract.
|
|
95
193
|
|
|
194
|
+
This beta.8 candidate combines native per-agent MCP permissions for OpenCode V1
|
|
195
|
+
and V2, V2 delegation-permission alignment, simpler memory/compression
|
|
196
|
+
instructions, and a sandbox check that proves the installed package matches
|
|
197
|
+
this checkout instead of silently accepting stale npm-cached code. The isolated
|
|
198
|
+
sandbox launcher also pins the OpenCode background service to its dedicated
|
|
199
|
+
loopback port, rather than colliding with another OpenCode installation. The Zeus
|
|
200
|
+
prompt reuses one task-start memory-search result for context and routing;
|
|
201
|
+
runtime call counts and latency have not been measured. A beta.7 V2 dispatch
|
|
202
|
+
failed because the permission hook passed a bare string to `ctx.session.get`
|
|
203
|
+
instead of the V2 input object `{ sessionID }`; beta.8 corrects the call and
|
|
204
|
+
adds contract tests for the success and failure cases. The user subsequently
|
|
205
|
+
reported a successful Hermes liveness delegation in the active session, but
|
|
206
|
+
freshly restarting and testing the beta.8 sandbox remains the end-to-end gate.
|
|
207
|
+
The original report also included a separate `GET /api/session/{id}/permission`
|
|
208
|
+
404; the session ID exists in the beta7-candidate database but not the default
|
|
209
|
+
global database. Both OpenCode services were running, so the 404 in the global
|
|
210
|
+
log may come from the other instance; this remains an end-to-end verification
|
|
211
|
+
item.
|
|
212
|
+
|
|
213
|
+
Delegated tasks get at most one retry after an initial timeout or failure. If
|
|
214
|
+
that retry fails, the configured fallback or escalation chain applies.
|
|
215
|
+
|
|
96
216
|
## Cost tool backend
|
|
97
217
|
|
|
98
218
|
`pantheon_cost` prefers a read-only `node:sqlite` backend against the selected
|
|
@@ -183,16 +303,128 @@ per installation; V1 and V2 Pantheon plugins must never be registered together.
|
|
|
183
303
|
|---|---|---|
|
|
184
304
|
| OpenCode config key | singular `plugin` | plural `plugins` |
|
|
185
305
|
| Pantheon registration | `src/plugin.ts` plus `src/plugins/pantheon-hooks.ts` | `<installed>/src/plugin-v2` directory (`index.ts` re-exports `src/plugin-v2.ts`) |
|
|
186
|
-
| Runtime contract | Pantheon V1 plugin: 6 tools (`hashline_edit`, the 3 goal tools, `pantheon_cost`, `pantheon_model`), event/tool hooks and V1 compaction handling | Full V2 plugin:
|
|
306
|
+
| Runtime contract | Pantheon V1 plugin: 6 tools (`hashline_edit`, the 3 goal tools, `pantheon_cost`, `pantheon_model`), event/tool hooks and V1 compaction handling | Full V2 plugin: 3 orchestration tools plus `vision_describe` when the model catalog is available, 5 event subscriptions, session hooks (`prompt`, `context`), a read-only-enforcing tool `execute.before` hook, plus configuration transforms |
|
|
187
307
|
| V1 APIs | Registered | Own tool definitions via `ctx.tool.transform()` — not the V1 plugin path |
|
|
188
308
|
|
|
189
|
-
The V2 plugin provides
|
|
190
|
-
`
|
|
191
|
-
`
|
|
192
|
-
`
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
`
|
|
309
|
+
The V2 plugin provides 3 orchestration tools (`hashline_edit`, `pantheon_cost`,
|
|
310
|
+
`pantheon_model`), 5 event subscriptions (`session.created`, `session.idle`,
|
|
311
|
+
`session.deleted`, `session.error`, `session.compacted`), session hooks
|
|
312
|
+
(`prompt`, `context`),
|
|
313
|
+
and a tool `execute.before` hook that enforces read-only sessions. The 3 goal
|
|
314
|
+
tools are **not**
|
|
315
|
+
registered on V2: the goal loop needs a `GoalStore`, a `GoalLoopClient` and a
|
|
316
|
+
`BackgroundJobBoard`, none of which the V2 `PluginContext` exposes, so the gap
|
|
317
|
+
is reported as the `goal-tools` unsupported-feature marker. Use the V1
|
|
318
|
+
contract if you need the goal loop.
|
|
319
|
+
|
|
320
|
+
V2 also registers `vision_describe` when `ctx.model.list()` is available. It
|
|
321
|
+
checks the live catalog for image input, prefers the paid OpenCode Go
|
|
322
|
+
`opencode-go/mimo-v2.6-flash` model (free-tier models are excluded from automatic
|
|
323
|
+
selection — the direct gateway rejects them with HTTP 403, they only work from
|
|
324
|
+
inside OpenCode; an explicit `PANTHEON_VISION_MODEL`/config/preset pin is still
|
|
325
|
+
honored, so its 403 surfaces as an actionable error rather than a silent
|
|
326
|
+
substitution), and
|
|
327
|
+
sends the image directly to the authenticated OpenCode Zen endpoint. The request
|
|
328
|
+
carries the live session id as the Zen-only `x-opencode-session` header the
|
|
329
|
+
gateway requires (never sent to a non-Zen provider, and never logged). OpenCode
|
|
330
|
+
credentials come from
|
|
331
|
+
`opencode auth login` or `PANTHEON_OPENCODE_API_KEY`; if no supported model or
|
|
332
|
+
credentials are available, the tool returns an explicit error instead of a
|
|
333
|
+
fabricated description. This path works without the optional V1 bridge.
|
|
334
|
+
The V2 prompt hook also preserves image attachment references and tells Zeus
|
|
335
|
+
to inspect relevant visual context and pass the reference plus concise findings
|
|
336
|
+
to Aphrodite. Inline image bytes are not copied into persisted prompt text, and
|
|
337
|
+
an image does not authorize deleting or reverting unrelated work.
|
|
338
|
+
|
|
339
|
+
The chat-turn native path picks its vision model in a fixed precedence: the
|
|
340
|
+
`PANTHEON_VISION_MODEL` env var, then `visionModel` in `opencode-vision.json`,
|
|
341
|
+
then the active preset's `vision.model`, then automatic discovery in the host
|
|
342
|
+
provider catalog (`GET /config/providers`), then the built-in default. Discovery
|
|
343
|
+
is conservative and paid-only: it keeps only image-capable entries
|
|
344
|
+
(`capabilities.input.image`) whose provider is a trusted Zen provider or whose
|
|
345
|
+
`npm` package is OpenAI-compatible (`@ai-sdk/openai-compatible` /
|
|
346
|
+
`@ai-sdk/openai`), EXCLUDES free-tier entries (`-free` id or `cost.input <= 0`
|
|
347
|
+
— the direct gateway rejects them with HTTP 403), picks the cheapest remaining
|
|
348
|
+
entry, and caches the catalog for 60
|
|
349
|
+
seconds per process; an incompatible model simply falls through to the vision
|
|
350
|
+
MCP tool. The base URL comes from the catalog entry's `api.url`, and the legacy
|
|
351
|
+
Zen endpoints remain the no-catalog fallback. Credentials follow the endpoint:
|
|
352
|
+
for a Zen endpoint the shared `PANTHEON_OPENCODE_API_KEY` / `OPENCODE_API_KEY`
|
|
353
|
+
env keys are tried first, then the OpenCode auth store (the resolved provider
|
|
354
|
+
first, then the legacy `opencode-go` / `opencode` entries); for a non-Zen
|
|
355
|
+
endpoint only that provider's own auth-store entry is used — the shared env keys
|
|
356
|
+
and the legacy Zen entries are never attached to a non-Zen base URL. An
|
|
357
|
+
explicitly configured, qualifying vision model always wins over discovery — a
|
|
358
|
+
pin that does not qualify (non-Zen, text-only, or absent from the catalog) is
|
|
359
|
+
discarded and the automatic selection takes over. `pantheon-opencode init`
|
|
360
|
+
offers an optional vision step in interactive TTY sessions — automatic discovery
|
|
361
|
+
is the default and writes nothing; pinning merges `visionModel` into the global
|
|
362
|
+
`opencode-vision.json`; non-interactive runs never prompt and never write.
|
|
363
|
+
The `/pantheon-vision` command adds a model picker: `vision-status.mjs --list`
|
|
364
|
+
enumerates image-capable candidates — labelling whether the source is the live
|
|
365
|
+
host catalog or an offline `opencode models` heuristic, plus `free`/`paid` and
|
|
366
|
+
credential presence per provider (never the token) — and `--set` pins the chosen
|
|
367
|
+
`provider/model` with the same atomic merge.
|
|
368
|
+
|
|
369
|
+
The user's question is injected into the vision prompt on both the native and V2
|
|
370
|
+
paths, trimmed and capped at 2000 characters; the same image asked a different
|
|
371
|
+
question gets a fresh description, while an identical re-ask inside the cache
|
|
372
|
+
TTL reuses the stored text. Native describes are robust by design: the timeout
|
|
373
|
+
scales from a 20-second base at roughly 10 seconds per MB of payload up to a
|
|
374
|
+
300-second ceiling, and a zero-dependency EXIF-orientation check (JPEG) adds a
|
|
375
|
+
textual hint so the vision model describes a rotated or mirrored image upright —
|
|
376
|
+
detection only, pixels are never rewritten, and the orientation is folded into
|
|
377
|
+
the cache key.
|
|
378
|
+
|
|
379
|
+
Vision degrades through an explicit chain — native → vision MCP tool → local.
|
|
380
|
+
When native is unavailable and the vision MCP tool is absent, the image is
|
|
381
|
+
replaced by deterministic local extraction: dimensions, format and size from the
|
|
382
|
+
PNG/JPEG/GIF/WebP header, dominant colors for RGB/RGBA PNG, and OCR only when a
|
|
383
|
+
`tesseract` binary is on `PATH`. It never fabricates content — the degradation is
|
|
384
|
+
stated explicitly. The `vision_describe` and `vision_ocr` MCP tools degrade to
|
|
385
|
+
that local mode when no gateway credential is configured, with no new
|
|
386
|
+
dependencies. (`vision_analyze` requires a gateway credential and returns an
|
|
387
|
+
explicit error instead.)
|
|
388
|
+
Deliberate trade-offs, recorded so they are not reversed by accident: Pantheon
|
|
389
|
+
describes each image once and keeps the text in history (council 2026-08-03)
|
|
390
|
+
rather than preserving the original image for per-turn re-observation;
|
|
391
|
+
describe-always favors zero added latency over an on-demand `describe_image`
|
|
392
|
+
tool. Multi-turn sanitization (`experimental.chat.messages.transform`) is a
|
|
393
|
+
mandatory invariant — it guarantees `image_url` / `FilePart` payloads never
|
|
394
|
+
reach a text-only provider and is not configurable. Bifrost stays opt-in and
|
|
395
|
+
never the default, per the credential incident in [SECURITY.md](SECURITY.md).
|
|
396
|
+
|
|
397
|
+
The V2 `execute.before` hook is the read-only enforcement point for that
|
|
398
|
+
surface: the host includes the active agent on the event, a read-only agent
|
|
399
|
+
(`apollo`, `gaia`) registers its session, and the shared
|
|
400
|
+
`createEnforcementGuard` throws to deny `edit`, `write`, `bash`, `task`,
|
|
401
|
+
`hashline_edit` and `pantheon_model`. It does **not** rely on the V1
|
|
402
|
+
`tool.execute.before` hook, which lives in `src/plugin.ts` and is not loaded
|
|
403
|
+
when only `plugin-v2` is configured. When the host registers the
|
|
404
|
+
`permission.evaluate` hook, it enforces the V2 caller/target matrix for
|
|
405
|
+
Pantheon-managed native `subagent` requests. If hook registration is
|
|
406
|
+
unavailable, the matrix is unavailable and the host remains in control.
|
|
407
|
+
Native-only resources pass through unchanged to OpenCode's permission policy;
|
|
408
|
+
mixed native/Pantheon and multi-target requests are denied. Pantheon matches
|
|
409
|
+
the permission source's session, message and tool-call IDs to a short-lived
|
|
410
|
+
record from `tool.execute.before`, cross-checks the captured host caller against
|
|
411
|
+
`permission.evaluate.agent`, and confirms the session has no `parentID`.
|
|
412
|
+
`permission.evaluate.agent` alone is not trusted because
|
|
413
|
+
`ctx.permission.assert` accepts a caller-supplied agent. Missing, stale,
|
|
414
|
+
replayed or mismatched origins fail closed, and explicit host denies remain
|
|
415
|
+
final. On OpenCode v2.0.29, a runtime canary admits Zeus→Apollo from a root,
|
|
416
|
+
denies a matrix-valid Athena→Apollo call from a child and rejects an invalid
|
|
417
|
+
edge before child creation; see the
|
|
418
|
+
[`F4A evidence`](bench/results/f4a-v229-admission-identity-2026-10-14.md).
|
|
419
|
+
V2 `execute.after` runs the completed-result chain:
|
|
420
|
+
`task-result-guard` → `context-sandbox` → `read-enhancer`.
|
|
421
|
+
|
|
422
|
+
Every V2 tool declares an `output` schema. OpenCode 2.0.x requires the
|
|
423
|
+
declaration and the resolved result to agree in both directions, so an
|
|
424
|
+
undeclared tool — or one that returns `output` without declaring it — fails on
|
|
425
|
+
every call. Unsupported V2 features are `legacy-hooks` (the V1-specific hook
|
|
426
|
+
surface), `catalog-transform`, `integration-transform`, `skill-transform` and
|
|
427
|
+
`goal-tools`.
|
|
196
428
|
|
|
197
429
|
The package exposes both contracts as importable exports: `pantheon-opencode/plugin`
|
|
198
430
|
(V1), `pantheon-opencode/plugin-v2` (V2) and `pantheon-opencode/v2-bridge`
|
|
@@ -211,28 +443,75 @@ npx pantheon-opencode init --opencode-version v2
|
|
|
211
443
|
npx pantheon-opencode init --opencode-version auto
|
|
212
444
|
```
|
|
213
445
|
|
|
214
|
-
`--version v1|v2|auto` is accepted as the older
|
|
215
|
-
after `init`. `auto`
|
|
216
|
-
`OPENCODE_VERSION=v1|v2` wins; otherwise an
|
|
217
|
-
`
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
446
|
+
`auto` is the default. `--version v1|v2|auto` is accepted as the older
|
|
447
|
+
selector spelling when used after `init`. `auto` resolves the generation from
|
|
448
|
+
the host in this order: an explicit `OPENCODE_VERSION=v1|v2` wins; otherwise an
|
|
449
|
+
`OPENCODE_BIN` path ending in `opencode2` selects V2; otherwise the host
|
|
450
|
+
binary is asked for its `--version` and a major of 2 or more selects V2. Every
|
|
451
|
+
other case — an unreadable probe, an unparseable banner, or a banner whose
|
|
452
|
+
version-like tokens contradict each other with no tool name to break the tie —
|
|
453
|
+
warns once and falls back to V1, because a plural `plugins` directory entry on
|
|
454
|
+
an unknown 1.x host loses the plugin entirely.
|
|
455
|
+
|
|
456
|
+
The probe prefers the token that follows the tool name, so a runtime token
|
|
457
|
+
ahead of it (`node v22.1.0 (opencode 1.18.33)`) or a trailing build date
|
|
458
|
+
(`opencode v1.18.33 built 2026.10.04`) cannot flip the generation. The
|
|
459
|
+
installer removes Pantheon references from both config shapes before writing
|
|
460
|
+
only the selected Pantheon registration. Third-party entries are not converted
|
|
461
|
+
or claimed by this rule.
|
|
462
|
+
|
|
463
|
+
The `pantheon_cost` report resolves its database by PATH, in this order: an
|
|
464
|
+
explicit `dbPath` supplied by the tool caller, then
|
|
465
|
+
`PANTHEON_COST_DB=/absolute/path/to/opencode.db`, then `OPENCODE_DB`, then the
|
|
466
|
+
XDG default `opencode.db`. There is no per-version filename in that chain:
|
|
467
|
+
`opencode-v2.db` is not a host 2.x database — it is the name a sandbox gives
|
|
468
|
+
its own state database through `OPENCODE_DB`.
|
|
469
|
+
|
|
470
|
+
The v1/v2 distinction is the DETECTED SCHEMA, not the file name. The report
|
|
471
|
+
looks for the `message` and `session_message` tables and reads whichever the
|
|
472
|
+
open database actually holds, because a migrated database carries both
|
|
473
|
+
families at once. `PANTHEON_OPENCODE_VERSION=v1|v2` selects no file: it only
|
|
474
|
+
narrows an already-detected set to one table family, and fails fast when the
|
|
475
|
+
value is neither `v1` nor `v2` or when the requested family is not there. Left
|
|
476
|
+
unset, every detected family is read. A database carrying neither table comes
|
|
477
|
+
back as an actionable error (`CORRUPT_DATA`), and a ledger that exists but
|
|
478
|
+
yields no readable tokens as `UNSUPPORTED` — never as a successful empty
|
|
479
|
+
report.
|
|
229
480
|
|
|
230
481
|
The installer still writes the compatibility settings required by the selected
|
|
231
482
|
OpenCode host, such as `experimental.subagent_depth`; this does not convert a
|
|
232
483
|
V1 plugin into V2 or provide V2 with V1 hooks.
|
|
233
484
|
|
|
485
|
+
Pantheon does not set a step ceiling on agents. On OpenCode 2 the `steps`
|
|
486
|
+
field is optional and has no default: absent means the host applies no native
|
|
487
|
+
limit. A config written before this change still carries the old value, and the
|
|
488
|
+
V2 install path strips it from every agent Pantheon manages — an agent you
|
|
489
|
+
define yourself is never touched, and the retiring V1 singular `agent` block
|
|
490
|
+
is left alone. Run the installer once to clear a stale value from an existing
|
|
491
|
+
config:
|
|
492
|
+
|
|
493
|
+
```bash
|
|
494
|
+
npx pantheon-opencode init --opencode-version=v2
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
Context control is not a Pantheon setting. Whatever budget an agent runs
|
|
498
|
+
against comes from the compaction settings of the OpenCode host you are
|
|
499
|
+
running, and Pantheon does not define them.
|
|
500
|
+
|
|
501
|
+
When a V1 `agent` block and a V2 `agents` block are both present — which is
|
|
502
|
+
what an installed `opencode.json` carries — the V1→V2 conversion merges them
|
|
503
|
+
instead of letting one replace the other. The V2 block is the base, the
|
|
504
|
+
framework-managed fields from the V1 block overwrite, and your own fields are
|
|
505
|
+
preserved, matching the precedence the installer already applies elsewhere.
|
|
506
|
+
Key order does not matter.
|
|
507
|
+
|
|
234
508
|
## Updating between releases (beta.5+)
|
|
235
509
|
|
|
510
|
+
> **Read [Compatibility and support policy](#compatibility-and-support-policy)
|
|
511
|
+
> before upgrading across a line boundary.** 1.6.x is the last line that
|
|
512
|
+
> supports an OpenCode 1.X host; 1.7+ is breaking-change territory targeting
|
|
513
|
+
> OpenCode 2. Within the 1.6 line, `update` is the supported path.
|
|
514
|
+
|
|
236
515
|
One command keeps an existing installation current:
|
|
237
516
|
|
|
238
517
|
```bash
|
|
@@ -253,7 +532,14 @@ Two freshness guarantees back it up:
|
|
|
253
532
|
- **Postinstall artifact sync** — after any `npm install`, copy-only artifacts
|
|
254
533
|
(agents, skills, AGENTS.md, commands, MCP scripts, code-mode payload) are
|
|
255
534
|
refreshed into the existing config dir automatically; you never have to
|
|
256
|
-
re-run `init` just for file copies.
|
|
535
|
+
re-run `init` just for file copies. The global config dir receives the
|
|
536
|
+
repo-agnostic **global artifact** (`AGENTS.global.md`: agent table + shared
|
|
537
|
+
rules), while each project's own `AGENTS.md` carries only project-specific
|
|
538
|
+
setup — the two are carved to be disjoint (beta-10 latency work), so no rule
|
|
539
|
+
is paid for twice per session. Installs are conservative: content outside
|
|
540
|
+
the generated managed region (user house rules) is preserved verbatim, a
|
|
541
|
+
legacy fully-generated `AGENTS.md` upgrades in place, and any merge is
|
|
542
|
+
reported with a warning.
|
|
257
543
|
- **Drift detection** — the installer stamps the installed version in
|
|
258
544
|
`.pantheon/install-state.json` and `doctor` warns when the package is newer
|
|
259
545
|
than the last sync, pointing at `update`. `doctor` also detects **plugin
|
|
@@ -315,6 +601,10 @@ pushes, merges, and tags never publish anything, and every validation gate is
|
|
|
315
601
|
fail-closed: only an explicit PASS authorizes release evidence. See
|
|
316
602
|
[docs/RELEASING.md](docs/RELEASING.md) for validation and recovery details.
|
|
317
603
|
|
|
604
|
+
For a candidate whose release section already exists, maintain its notes with
|
|
605
|
+
`node scripts/versioning.mjs changelog <version>`; this merges `[Unreleased]`
|
|
606
|
+
into that version without advancing the package version.
|
|
607
|
+
|
|
318
608
|
Release validation keeps each manifest with its lockfile: the root
|
|
319
609
|
`package.json` + `package-lock.json` and the TUI
|
|
320
610
|
`src/plugins/tui/package.json` + `src/plugins/tui/package-lock.json`. Both use
|
|
@@ -323,6 +613,12 @@ Release validation keeps each manifest with its lockfile: the root
|
|
|
323
613
|
SHA-256 of that same artifact, and binds the tarball and GitHub release to the
|
|
324
614
|
full `TARGET_SHA`; a second pack is not interchangeable.
|
|
325
615
|
|
|
616
|
+
CI also rebuilds the TUI with `npm run build --prefix src/plugins/tui` and
|
|
617
|
+
checks every packaged `dist` artifact byte-for-byte against its checked-in
|
|
618
|
+
version, including final newlines. The build includes separate V1 and native
|
|
619
|
+
OpenCode V2 TUI entrypoints; `init` selects the entrypoint and sidebar slot API
|
|
620
|
+
for the host generation in use.
|
|
621
|
+
|
|
326
622
|
## Sandbox validation (V2)
|
|
327
623
|
|
|
328
624
|
`scripts/test-opencode-v2-sandbox.sh` validates the globally installed
|
|
@@ -334,6 +630,11 @@ agent delegation. The gate is fail-closed: every required check must return an
|
|
|
334
630
|
explicit PASS; timeouts, auth/network/provider failures and missing
|
|
335
631
|
prerequisites block the run.
|
|
336
632
|
|
|
633
|
+
The runner defaults to the current stable `@opencode/cli` package and its
|
|
634
|
+
`opencode2` alias; set `OPENCODE_V2_SPEC` only when a test needs a different
|
|
635
|
+
host build. This keeps Pantheon beta testing separate from the OpenCode CLI
|
|
636
|
+
release channel.
|
|
637
|
+
|
|
337
638
|
"V2" here refers only to the hook canary observed against an OpenCode v2.0.18
|
|
338
639
|
host, where at least one tested hook callback fired; it does not establish
|
|
339
640
|
compatibility with the stable `@opencode/plugin@2.0.18` SDK or full 2.x
|
|
@@ -345,6 +646,7 @@ single leg.
|
|
|
345
646
|
|
|
346
647
|
```bash
|
|
347
648
|
scripts/test-opencode-v2-sandbox.sh --prepare # tarball + install + init in the sandbox
|
|
649
|
+
~/pantheon-sandbox/start-pantheon.sh # interactive TUI in that isolated beta sandbox
|
|
348
650
|
scripts/test-opencode-v2-sandbox.sh --run v2 # base validation only
|
|
349
651
|
scripts/test-opencode-v2-sandbox.sh --prompts # base validation + prompt battery
|
|
350
652
|
scripts/test-opencode-v2-sandbox.sh --rehydrate # offline context rehydration/session-summary probe
|
|
@@ -369,6 +671,142 @@ repository from a sibling directory.
|
|
|
369
671
|
This validates the prepared isolated sandbox only. A PASS is not proof of
|
|
370
672
|
support for every real host or for host configurations that were not exercised.
|
|
371
673
|
|
|
674
|
+
## Latency benchmark (bench/)
|
|
675
|
+
|
|
676
|
+
`bench/` measures end-to-end session latency of the installed `opencode` CLI
|
|
677
|
+
with the repo's V2 plugin — the baseline every performance change in a release
|
|
678
|
+
must be compared against. It runs two scenarios N times each, interleaved
|
|
679
|
+
(non-interactive, one fresh sandbox directory per run), collects per-run
|
|
680
|
+
metrics from `opencode.db` in READ-ONLY mode (tokens root + child sessions
|
|
681
|
+
without double counting, tool calls per name, child-session count) and hook
|
|
682
|
+
timings from the `[bench]` lines the plugin appends to `hooks.log`:
|
|
683
|
+
|
|
684
|
+
```bash
|
|
685
|
+
node bench/bin/bench.mjs # 5 runs per scenario (A and B), ~1h
|
|
686
|
+
BENCH_MODEL=opencode-go/glm-5.3-flash node bench/bin/bench.mjs # pin a model
|
|
687
|
+
node bench/bin/bench.mjs --runs 1 # smoke: one run per scenario
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
Results land in `bench/results/<label>-<git-sha>.json` (median + p80 +
|
|
691
|
+
failures per scenario); the label defaults to `baseline` and the harness
|
|
692
|
+
refuses to overwrite an existing result, so the run identity lives in the file
|
|
693
|
+
name. Scenario A performs real web research, so its variance is
|
|
694
|
+
network-dependent and recorded per run.
|
|
695
|
+
|
|
696
|
+
### Measurement profiles (explicit, never inferred)
|
|
697
|
+
|
|
698
|
+
Instructions are injected from two surfaces: the global config dir and the
|
|
699
|
+
project directory. The harness states which one it exercises, because a
|
|
700
|
+
result only means anything in the profile where the change acts:
|
|
701
|
+
|
|
702
|
+
| `--profile` | Global `AGENTS.md` | Project `AGENTS.md` | Use |
|
|
703
|
+
|---|---|---|---|
|
|
704
|
+
| `host` (default) | host config dir (or `--global-agents`) | none — run dirs stay empty | the host's real, unmodified injection |
|
|
705
|
+
| `double-injection` | host config dir (or `--global-agents`) | `--project-agents`, written into every run dir | the in-repo profile where global+project overlap |
|
|
706
|
+
|
|
707
|
+
The default measures scenarios A and B. Use `--scenarios B` to isolate the F1
|
|
708
|
+
one-shot claim; the selected scenario still runs N times (`--runs 5` by
|
|
709
|
+
default).
|
|
710
|
+
|
|
711
|
+
```bash
|
|
712
|
+
# candidate arm: the carved global artifact + the carved project artifact
|
|
713
|
+
node bench/bin/bench.mjs --runs 5 --scenarios B --profile double-injection \
|
|
714
|
+
--global-agents AGENTS.global.md --project-agents AGENTS.md --label f1-candidate
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
Each arm records, per run and read from the db, the identity (path, bytes,
|
|
718
|
+
sha256) of every instruction file the session actually loaded
|
|
719
|
+
(`instruction_state` + `instruction_blob`) — the fidelity proof that what was
|
|
720
|
+
measured is what was generated. A claim may only rest on a run whose
|
|
721
|
+
provenance shows the intended global **and** project artifacts were loaded.
|
|
722
|
+
|
|
723
|
+
### Signal vs noise
|
|
724
|
+
|
|
725
|
+
Wall time is a lead, not a criterion: same-day spread reaches ~8× in scenario
|
|
726
|
+
A and ~13× in B. An effect is **confirmed** only when it exceeds the same-day
|
|
727
|
+
spread (or demands a larger N); otherwise it is recorded as **inconclusive**.
|
|
728
|
+
Prefer token medians, which are far more stable. Scenario A's wall is not a
|
|
729
|
+
claim metric — it performs real web research, so network variance dominates.
|
|
730
|
+
|
|
731
|
+
### First-request proxy and F1 evidence
|
|
732
|
+
|
|
733
|
+
The injected instruction payload only lands on the first request, so the
|
|
734
|
+
tree-total `tokens.input` (summed over every turn) is dominated by
|
|
735
|
+
session-length variance. Each run also records `firstRequest` — the first
|
|
736
|
+
assistant row's `tokens.input` + `tokens.cache.read` — the proxy that isolates
|
|
737
|
+
the payload.
|
|
738
|
+
|
|
739
|
+
An interleaved OpenCode v2.0.29 run (C1/K1…C5/K5, N=5/arm) measured
|
|
740
|
+
first-request context at 17555 tokens for control and 15489 for candidate
|
|
741
|
+
(**−2066, −11.8%**; within-arm spread 14 tokens in each arm). D4 confirmed
|
|
742
|
+
22350 B loaded for control and 13400 B for candidate (−8950 B, −40.0%); the
|
|
743
|
+
pre-registered correctness oracle passed 5/5 in both arms. Themis accepted F1
|
|
744
|
+
with **PASS_WITH_NOTES**. The first-request effect is confirmed against
|
|
745
|
+
within-arm spread. Tree-total input fell from a median 47594 to 38253
|
|
746
|
+
tokens, but ranges overlap and the ≤30k hypothesis was not met. Wall medians
|
|
747
|
+
were 30.078 s and 24.130 s, with high spread; tree-total input and wall remain
|
|
748
|
+
**inconclusive**. No wall-time or monetary-cost gain is claimed. Details and
|
|
749
|
+
per-run records: `bench/results/f1-di-v229-interleaved-2026-10-14.md`.
|
|
750
|
+
The earlier sequential pair remains supporting-only in
|
|
751
|
+
`bench/results/f1-di-v229-clean-2026-10-14.md`. Earlier exploratory runs are
|
|
752
|
+
retained separately in `bench/results/f1-double-injection.md` and
|
|
753
|
+
`bench/results/f1-di-v229-preliminary-2026-10-14.md`.
|
|
754
|
+
|
|
755
|
+
### Explicit root specialist result (F3a)
|
|
756
|
+
|
|
757
|
+
For the bounded one-shot scenario B, explicitly starting Talos as the root
|
|
758
|
+
produced the oracle-passing artifact in 5/5 runs with no child session or
|
|
759
|
+
`subagent` call. In the same-day paired sample, Talos used 16,171 median input
|
|
760
|
+
tokens per run versus 33,301 for Zeus (−51.4%); this is a descriptive result
|
|
761
|
+
for this task, model, and configuration, not a general routing or monetary
|
|
762
|
+
savings claim. Wall time is inconclusive: medians were 30.347 s and 31.893 s,
|
|
763
|
+
the ranges overlap widely, and Talos had the higher p80. No automatic
|
|
764
|
+
LLM-selected root routing is introduced by this result.
|
|
765
|
+
|
|
766
|
+
A final integration check after F4A/F3b initially completed 4/5 Talos artifacts.
|
|
767
|
+
Talos's prompt now says to finish named files with native `write`/`edit` tools
|
|
768
|
+
and not confuse MCP tool discovery with the host's native tool catalog. The
|
|
769
|
+
failure remains recorded in
|
|
770
|
+
[`beta10-final-integration-2026-10-15.md`](bench/results/beta10-final-integration-2026-10-15.md).
|
|
771
|
+
A new pre-registered cohort on that prompt passed the artifact oracle in 5/5
|
|
772
|
+
Talos runs with zero children or `subagent` calls. Its first-request context
|
|
773
|
+
proxy was 9,675 tokens versus 13,009 for Zeus (−25.6%, confirmed against the
|
|
774
|
+
same-arm spread). Tree-total input is descriptive, and wall time remains
|
|
775
|
+
inconclusive. See the [follow-up report](bench/results/beta10-final-integration-followup-2026-10-15.md)
|
|
776
|
+
and [raw run record](bench/results/beta10-final-integration-followup-20261015.json).
|
|
777
|
+
|
|
778
|
+
The v2.0.29 harness requires explicit agent and fixture selection, and proves
|
|
779
|
+
global plus project instruction provenance for each run:
|
|
780
|
+
|
|
781
|
+
```bash
|
|
782
|
+
BENCH_MODEL=opencode-go/glm-5.3-flash node bench/bin/bench.mjs \
|
|
783
|
+
--scenario B --runs 5 --profile double-injection \
|
|
784
|
+
--global-agents AGENTS.global.md --project-agents AGENTS.md \
|
|
785
|
+
--agents-dir src/agents --skills-dir src/skills \
|
|
786
|
+
--root-agent talos --control-root-agent zeus --paired \
|
|
787
|
+
--out bench/results/phase3-root-paired-20261014.json
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
Themis reviewed the harness and evidence (**PASS_WITH_NOTES**). Full method,
|
|
791
|
+
oracle audit, limitations, and per-run data are in
|
|
792
|
+
`bench/results/f3a-root-paired-2026-10-14.md` and
|
|
793
|
+
`bench/results/phase3-root-paired-20261014.json`.
|
|
794
|
+
|
|
795
|
+
### Bounded workspace reads (F3b)
|
|
796
|
+
|
|
797
|
+
On OpenCode v2.0.29, the V2 plugin can expose `pantheon_bounded_read` when the
|
|
798
|
+
host provides its native permission and session APIs. Only a root Zeus session
|
|
799
|
+
can use it. Each call asks the host for `read` permission to one exact
|
|
800
|
+
workspace-relative file, with an empty save scope; content is read only after
|
|
801
|
+
approval and is scanned by the existing fail-closed secret scanner. Limits are
|
|
802
|
+
two calls and two distinct files, 400 lines and 32 KiB per assistant message.
|
|
803
|
+
Traversal, symlinks, directories, sensitive scopes, recognized binary/media
|
|
804
|
+
formats, and scanner failures are rejected. This is scoped to a local workspace
|
|
805
|
+
without concurrent writers; it does not claim adversarial filesystem isolation
|
|
806
|
+
or whole-file binary classification. The host-backed evidence is in
|
|
807
|
+
[`bench/results/f3b-v229-bounded-read-2026-10-15.md`](bench/results/f3b-v229-bounded-read-2026-10-15.md).
|
|
808
|
+
|
|
809
|
+
|
|
372
810
|
## Plugin V2 TypeScript coverage
|
|
373
811
|
|
|
374
812
|
`npm run coverage:plugin-v2` runs the `tests/pantheon/*.test.ts` suite with
|
|
@@ -383,7 +821,7 @@ Env overrides:
|
|
|
383
821
|
|----------|---------|---------|
|
|
384
822
|
| `PANTHEON_SANDBOX_ROOT` | `~/pantheon-sandbox` | Sandbox root (refused if unsafe for `--reset`) |
|
|
385
823
|
| `OPENCODE_V1_SPEC` | `opencode-ai@1.18.18` | Configures the V1 plugin only; the V2-only sandbox runner does not consume or support it |
|
|
386
|
-
| `OPENCODE_V2_SPEC` | `@opencode
|
|
824
|
+
| `OPENCODE_V2_SPEC` | `@opencode/cli@latest` | npm spec providing the `opencode2` binary |
|
|
387
825
|
| `PANTHEON_SANDBOX_MODEL` | `opencode-go/mimo-v2.5` | Model used by init and prompts |
|
|
388
826
|
| `PANTHEON_PROMPT_TIMEOUT` | `300` | Per-prompt timeout in seconds |
|
|
389
827
|
|
|
@@ -392,7 +830,7 @@ in the sandbox root) · `2` usage error · `3` sandbox not prepared.
|
|
|
392
830
|
|
|
393
831
|
### Intentional memory MCP divergence
|
|
394
832
|
|
|
395
|
-
`scripts/
|
|
833
|
+
`scripts/memory_mcp.py` and `src/mcp/memory_mcp.py` are
|
|
396
834
|
intentionally different. The standalone `scripts/` copy keeps the lightweight
|
|
397
835
|
`memory_*` contract; the installed `src/mcp/` copy additionally exposes the
|
|
398
836
|
optional codemap schema and `code_index`, `code_query`, and `code_neighbors`.
|
|
@@ -441,6 +879,32 @@ Ideas, bug reports, documentation improvements, and code contributions are
|
|
|
441
879
|
welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) before opening an issue
|
|
442
880
|
or pull request.
|
|
443
881
|
|
|
882
|
+
### Reproducible benchmark evidence
|
|
883
|
+
|
|
884
|
+
The beta2 benchmark records reported token usage separately from its
|
|
885
|
+
character-based fallback estimate; source bytes and logical line counts remain
|
|
886
|
+
provenance data and are never converted into tokens. Cross-report comparisons
|
|
887
|
+
require matching model/config provenance and reported OpenCode usage. Offline
|
|
888
|
+
fixture responses are mocked: their reported values are labeled separately,
|
|
889
|
+
excluded from `actual` usage, and blocked from comparative metrics and GEPA.
|
|
890
|
+
Fixture quality outcomes test the offline contract; they are not evaluation
|
|
891
|
+
evidence.
|
|
892
|
+
Reproduce the
|
|
893
|
+
checked-in AGENTS.md history manifest with
|
|
894
|
+
`python3 -m benchmarks.beta2.provenance --output benchmarks/beta2/fixtures/agent-baseline-provenance.json`.
|
|
895
|
+
For OpenCode benchmark runs, provide `--model` and `--config-sha256` so reports
|
|
896
|
+
can be compared safely.
|
|
897
|
+
|
|
898
|
+
### Project-level `opencode.json`
|
|
899
|
+
|
|
900
|
+
The published package carries no `opencode.json` template. `init` still writes
|
|
901
|
+
your project's `opencode.json` itself, and the few product defaults an install
|
|
902
|
+
seeds — `default_agent: zeus` and `permission.skill` — come from the installer
|
|
903
|
+
code, not from a packaged file. Contributors who keep a project-level
|
|
904
|
+
`opencode.json` for their own OpenCode sessions should leave it untracked —
|
|
905
|
+
`.git/info/exclude` per clone, or a shared `.gitignore` decision — rather than
|
|
906
|
+
versioning it.
|
|
907
|
+
|
|
444
908
|
## Citation and DOI
|
|
445
909
|
|
|
446
910
|
Pantheon is released under the [MIT License](LICENSE). Cite the
|