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.pt-BR.md
CHANGED
|
@@ -53,6 +53,10 @@ Com o OpenCode em execução, descreva o resultado que você quer:
|
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
O Pantheon ajuda a transformar esse pedido em um plano e em etapas revisadas.
|
|
56
|
+
Quando você pede um plano ou inicia `/pantheon-deepwork`, Athena devolve o plano
|
|
57
|
+
completo para Zeus, que o apresenta na conversa principal antes de pedir
|
|
58
|
+
aprovação. O pedido de aprovação não ficará separado de um plano escondido na
|
|
59
|
+
conversa de um subagente.
|
|
56
60
|
|
|
57
61
|
## Para quem é?
|
|
58
62
|
|
|
@@ -122,16 +126,137 @@ registrados juntos.
|
|
|
122
126
|
|---|---|---|
|
|
123
127
|
| Chave de config do OpenCode | `plugin` singular | `plugins` plural |
|
|
124
128
|
| Registro Pantheon | `src/plugin.ts` mais `src/plugins/pantheon-hooks.ts` | `pantheon-opencode/plugin-v2` (`src/plugin-v2.ts`) |
|
|
125
|
-
| Contrato de runtime | Plugin Pantheon V1: 6 ferramentas (`hashline_edit`, as 3 ferramentas de goal, `pantheon_cost`, `pantheon_model`), hooks de evento/ferramenta e tratamento de compactação V1 | Plugin V2 completo:
|
|
129
|
+
| Contrato de runtime | Plugin Pantheon V1: 6 ferramentas (`hashline_edit`, as 3 ferramentas de goal, `pantheon_cost`, `pantheon_model`), hooks de evento/ferramenta e tratamento de compactação V1 | Plugin V2 completo: 3 ferramentas de orquestração mais `vision_describe` quando o catálogo de modelos está disponível, 5 assinaturas de eventos, session hooks (`prompt`, `context`), um hook `execute.before` que impõe sessões somente-leitura, além de transforms de configuração |
|
|
126
130
|
| APIs V1 | Registradas | Definições próprias de ferramentas via `ctx.tool.transform()` — não pelo caminho do plugin V1 |
|
|
127
131
|
|
|
128
|
-
O plugin V2 fornece
|
|
129
|
-
`pantheon_goal_create`, `pantheon_goal_get`, `pantheon_goal_update`,
|
|
132
|
+
O plugin V2 fornece 3 ferramentas de orquestração (`hashline_edit`,
|
|
130
133
|
`pantheon_cost`, `pantheon_model`), 4 assinaturas de eventos (`session.created`,
|
|
131
134
|
`session.idle`, `session.error`, `session.compacted`), session hooks (`prompt`,
|
|
132
|
-
`context`) e
|
|
133
|
-
|
|
134
|
-
`
|
|
135
|
+
`context`) e um hook de ferramenta `execute.before` que impõe sessões
|
|
136
|
+
somente-leitura. As 3 ferramentas de goal **não** são
|
|
137
|
+
registradas no V2: o goal loop precisa de um `GoalStore`, de um
|
|
138
|
+
`GoalLoopClient` e de um `BackgroundJobBoard`, nenhum dos quais o
|
|
139
|
+
`PluginContext` do V2 expõe, então a lacuna é reportada como o marcador de
|
|
140
|
+
recurso sem suporte `goal-tools`. Use o contrato V1 se precisar do goal loop.
|
|
141
|
+
|
|
142
|
+
O V2 também registra `vision_describe` quando `ctx.model.list()` está
|
|
143
|
+
disponível. A ferramenta verifica a entrada de imagem no catálogo atual,
|
|
144
|
+
prioriza o modelo pago `opencode-go/mimo-v2.6-flash` (modelos free-tier são
|
|
145
|
+
excluídos da seleção automática — o gateway direto os rejeita com HTTP 403, só
|
|
146
|
+
funcionam de dentro do OpenCode; um pin explícito em
|
|
147
|
+
`PANTHEON_VISION_MODEL`/config/preset continua sendo honrado, então seu 403 vira
|
|
148
|
+
um erro acionável em vez de uma troca silenciosa) e envia a imagem
|
|
149
|
+
diretamente ao endpoint autenticado do OpenCode Zen. A requisição carrega o
|
|
150
|
+
session id vivo no header Zen-only `x-opencode-session` exigido pelo gateway
|
|
151
|
+
(nunca enviado a um provider não-Zen, e nunca logado). As credenciais vêm de
|
|
152
|
+
`opencode auth login` ou `PANTHEON_OPENCODE_API_KEY`; sem modelo compatível ou
|
|
153
|
+
credenciais, a ferramenta retorna um erro explícito em vez de inventar uma
|
|
154
|
+
descrição. Esse caminho funciona sem a ponte V1 opcional.
|
|
155
|
+
O hook de prompt V2 também preserva as referências dos anexos e orienta Zeus a
|
|
156
|
+
inspecionar imagens relevantes e repassar a referência e observações concisas a
|
|
157
|
+
Aphrodite. Bytes inline não são copiados para o texto persistido do prompt, e a
|
|
158
|
+
imagem não autoriza apagar nem reverter alterações fora do escopo.
|
|
159
|
+
|
|
160
|
+
O caminho nativo do turno de chat escolhe o modelo de visão numa precedência
|
|
161
|
+
fixa: a variável `PANTHEON_VISION_MODEL`, depois `visionModel` em
|
|
162
|
+
`opencode-vision.json`, depois `vision.model` do preset ativo, depois descoberta
|
|
163
|
+
automática no catálogo de providers do host (`GET /config/providers`) e, por
|
|
164
|
+
fim, o padrão embutido. A descoberta é conservadora e somente paga: mantém
|
|
165
|
+
apenas entradas com imagem (`capabilities.input.image`) cujo provider é Zen
|
|
166
|
+
confiável ou cujo pacote `npm` é OpenAI-compatível (`@ai-sdk/openai-compatible` /
|
|
167
|
+
`@ai-sdk/openai`), EXCLUI entradas free-tier (`-free` ou `cost.input <= 0` — o
|
|
168
|
+
gateway direto as rejeita com HTTP 403), escolhe a entrada mais barata restante
|
|
169
|
+
e faz cache do catálogo por 60
|
|
170
|
+
segundos por processo; um modelo incompatível simplesmente cai no fallback da
|
|
171
|
+
tool MCP de visão. A base URL vem do `api.url` da entrada do catálogo, e os
|
|
172
|
+
endpoints Zen legados permanecem como fallback quando não há catálogo. As
|
|
173
|
+
credenciais seguem o endpoint: para um endpoint Zen, as variáveis compartilhadas
|
|
174
|
+
`PANTHEON_OPENCODE_API_KEY` / `OPENCODE_API_KEY` são tentadas primeiro e depois o
|
|
175
|
+
auth store do OpenCode (o provider resolvido primeiro, depois as entradas legadas
|
|
176
|
+
`opencode-go` / `opencode`); para um endpoint não-Zen, apenas a entrada do próprio
|
|
177
|
+
provider no auth store é usada — as variáveis compartilhadas e as entradas Zen
|
|
178
|
+
legadas nunca são anexadas a uma base URL não-Zen. Um modelo de visão
|
|
179
|
+
configurado explicitamente e qualificado sempre vence a descoberta — um pin que
|
|
180
|
+
não qualifica (não-Zen, text-only ou fora do catálogo) é descartado e a seleção
|
|
181
|
+
automática assume. O `pantheon-opencode init` oferece um
|
|
182
|
+
passo opcional de vision em sessões TTY interativas — a descoberta automática é
|
|
183
|
+
o default e não grava nada; pinar faz merge de `visionModel` no
|
|
184
|
+
`opencode-vision.json` global; fluxos não-interativos nunca perguntam nem gravam.
|
|
185
|
+
|
|
186
|
+
A pergunta do usuário é injetada no prompt de visão nos caminhos nativo e V2,
|
|
187
|
+
aparada e limitada a 2000 caracteres; a mesma imagem com uma pergunta diferente
|
|
188
|
+
gera nova descrição, enquanto uma repetição idêntica dentro do TTL de cache
|
|
189
|
+
reutiliza o texto guardado. O describe nativo é robusto por construção: o
|
|
190
|
+
timeout escala de uma base de 20 segundos a cerca de 10 segundos por MB de
|
|
191
|
+
payload até um teto de 300 segundos, e uma checagem de orientação EXIF sem
|
|
192
|
+
dependências (JPEG) adiciona uma dica textual para o vision model descrever a
|
|
193
|
+
imagem rotacionada ou espelhada na posição correta — só detecção, os pixels
|
|
194
|
+
nunca são reescritos, e a orientação entra na chave do cache.
|
|
195
|
+
|
|
196
|
+
A visão degrada numa cadeia explícita — nativa → tool MCP de visão → local.
|
|
197
|
+
Quando a nativa está indisponível e a tool MCP de visão não está presente, a
|
|
198
|
+
imagem é substituída por extração local determinística: dimensões, formato e
|
|
199
|
+
tamanho do header PNG/JPEG/GIF/WebP, cores dominantes para PNG RGB/RGBA e OCR
|
|
200
|
+
somente quando o binário `tesseract` está no `PATH`. Nunca fabrica conteúdo — a
|
|
201
|
+
degradação é declarada explicitamente. As tools `vision_describe` e `vision_ocr`
|
|
202
|
+
do MCP degradam para esse modo local quando não há credencial de gateway, sem
|
|
203
|
+
dependências novas. (A `vision_analyze` exige credencial de gateway e retorna um
|
|
204
|
+
erro explícito.) Trade-offs deliberados, registrados para não serem
|
|
205
|
+
revertidos por acidente: o Pantheon descreve cada imagem uma vez e mantém o
|
|
206
|
+
texto no histórico (council 2026-08-03) em vez de preservar a imagem original
|
|
207
|
+
para re-observação a cada turno; o describe-always prioriza latência zero em vez
|
|
208
|
+
de uma tool `describe_image` sob demanda. A sanitização multi-turno
|
|
209
|
+
(`experimental.chat.messages.transform`) é invariante obrigatória — garante que
|
|
210
|
+
`image_url` / `FilePart` nunca cheguem a um provider textual e não é
|
|
211
|
+
configurável. O Bifrost permanece opt-in, nunca padrão, conforme o incidente de
|
|
212
|
+
credencial em [SECURITY.md](SECURITY.md).
|
|
213
|
+
|
|
214
|
+
O hook `execute.before` do V2 é o ponto de imposição de sessões somente-leitura
|
|
215
|
+
dessa superfície: o host inclui o agente ativo no evento, um agente somente-leitura
|
|
216
|
+
(`apollo`, `gaia`) registra sua sessão, e o `createEnforcementGuard`
|
|
217
|
+
compartilhado lança para negar `edit`, `write`, `bash`, `task`,
|
|
218
|
+
`hashline_edit` e `pantheon_model`. Ele **não** depende do hook
|
|
219
|
+
`tool.execute.before` do V1, que vive em `src/plugin.ts` e não é carregado
|
|
220
|
+
quando apenas `plugin-v2` está configurado. Quando o host registra o hook
|
|
221
|
+
`permission.evaluate`, ele aplica no V2 a matriz caller/target a todos os itens
|
|
222
|
+
do array `resources` do host para destinos gerenciados pelo Pantheon. Sem o
|
|
223
|
+
registro do hook, a matriz não fica disponível e o host mantém o controle.
|
|
224
|
+
Recursos exclusivamente nativos são repassados sem alteração à política de
|
|
225
|
+
permissões do OpenCode; pedidos mistos (nativos/Pantheon) ou com vários destinos
|
|
226
|
+
são negados.
|
|
227
|
+
Para destinos Pantheon, a política exige uma chamada nativa `subagent` cujo
|
|
228
|
+
session ID, message ID e tool-call ID no `source` coincidam com o evento do host
|
|
229
|
+
`tool.execute.before`; também confirma que a sessão não tem `parentID`. O campo
|
|
230
|
+
`permission.evaluate.agent`, sozinho, não identifica o chamador. Origins
|
|
231
|
+
ausentes, expirados, repetidos ou incompatíveis são negados. A canary no
|
|
232
|
+
OpenCode v2.0.29 admite Zeus→Apollo na raiz e nega dispatches inválidos ou
|
|
233
|
+
originados em uma filha; veja o [relatório de F4A](bench/results/f4a-v229-admission-identity-2026-10-14.md).
|
|
234
|
+
Uma negação explícita do host é final, e dados de recursos ausentes ou
|
|
235
|
+
desconhecidos são negados por padrão. O `execute.after` do
|
|
236
|
+
V2 executa a cadeia de resultados concluídos `task-result-guard` →
|
|
237
|
+
`context-sandbox` → `read-enhancer`; eventos de erro permanecem inalterados.
|
|
238
|
+
|
|
239
|
+
#### Leitura bounded do workspace (F3b)
|
|
240
|
+
|
|
241
|
+
No OpenCode v2.0.29, o plugin V2 pode registrar `pantheon_bounded_read` quando
|
|
242
|
+
o host oferece as APIs nativas de permissão e sessão. Só uma sessão root do
|
|
243
|
+
Zeus pode usá-la. Cada chamada pede ao host permissão `read` para um arquivo
|
|
244
|
+
relativo exato do workspace, com escopo de persistência vazio; o conteúdo só é
|
|
245
|
+
lido após aprovação e passa pelo scanner de segredos fail-closed existente.
|
|
246
|
+
Os limites são duas chamadas e dois arquivos distintos, 400 linhas e 32 KiB
|
|
247
|
+
por mensagem do assistant. Travessia de diretórios, symlinks, diretórios,
|
|
248
|
+
escopos sensíveis, formatos binários/mídia reconhecidos e falhas do scanner são
|
|
249
|
+
negados. O escopo suportado é um workspace local sem escritores concorrentes;
|
|
250
|
+
isso não promete isolamento contra filesystem adversarial nem classificação
|
|
251
|
+
binária do arquivo inteiro. Evidência host-backed:
|
|
252
|
+
[`bench/results/f3b-v229-bounded-read-2026-10-15.md`](bench/results/f3b-v229-bounded-read-2026-10-15.md).
|
|
253
|
+
|
|
254
|
+
Toda ferramenta V2 declara um schema `output`. O OpenCode 2.0.x exige que a
|
|
255
|
+
declaração e o resultado resolvido concordem nos dois sentidos, então uma
|
|
256
|
+
ferramenta sem declaração — ou que retorne `output` sem declará-lo — falha em
|
|
257
|
+
toda chamada. Os recursos V2 sem suporte são `legacy-hooks` (a superfície de
|
|
258
|
+
hooks específica do V1), `catalog-transform`, `integration-transform`,
|
|
259
|
+
`skill-transform` e `goal-tools`.
|
|
135
260
|
|
|
136
261
|
O pacote expõe os dois contratos como exports importáveis:
|
|
137
262
|
`pantheon-opencode/plugin` (V1), `pantheon-opencode/plugin-v2` (V2) e
|
|
@@ -151,26 +276,68 @@ npx pantheon-opencode init --opencode-version v2
|
|
|
151
276
|
npx pantheon-opencode init --opencode-version auto
|
|
152
277
|
```
|
|
153
278
|
|
|
154
|
-
`--version v1|v2|auto` é aceito como a grafia antiga do seletor
|
|
155
|
-
depois de `init`. `auto`
|
|
156
|
-
|
|
157
|
-
terminando em `opencode2` seleciona V2;
|
|
158
|
-
|
|
279
|
+
`auto` é o padrão. `--version v1|v2|auto` é aceito como a grafia antiga do seletor
|
|
280
|
+
quando usado depois de `init`. `auto` resolve a geração a partir do host nesta
|
|
281
|
+
ordem: um `OPENCODE_VERSION=v1|v2` explícito vence; caso contrário, um
|
|
282
|
+
`OPENCODE_BIN` terminando em `opencode2` seleciona V2; caso contrário o binário
|
|
283
|
+
do host é consultado com `--version` e uma major >= 2 seleciona V2. Qualquer
|
|
284
|
+
outro caso — uma sonda ilegível, um banner não interpretável, ou um banner
|
|
285
|
+
cujos tokens de versão se contradizem sem um nome de ferramenta que desfaça o
|
|
286
|
+
empate — avisa uma vez e volta para V1, porque uma entrada de diretório em
|
|
287
|
+
`plugins` plural em um host 1.x desconhecido perde o plugin inteiro.
|
|
288
|
+
|
|
289
|
+
A sonda prefere o token que vem logo após o nome da ferramenta, então um token
|
|
290
|
+
de runtime antes dele (`node v22.1.0 (opencode 1.18.33)`) ou uma data de build
|
|
291
|
+
no final (`opencode v1.18.33 built 2026.10.04`) não conseguem virar a geração.
|
|
292
|
+
O instalador remove referências Pantheon das duas formas de config antes de
|
|
159
293
|
gravar apenas o registro Pantheon selecionado. Entradas de terceiros não são
|
|
160
294
|
convertidas nem reivindicadas por essa regra.
|
|
161
295
|
|
|
162
|
-
O relatório `pantheon_cost`, disponível nos plugins V1 e V2,
|
|
163
|
-
|
|
164
|
-
`PANTHEON_COST_DB=/caminho/absoluto/para/opencode.db
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
296
|
+
O relatório `pantheon_cost`, disponível nos plugins V1 e V2, resolve o banco por
|
|
297
|
+
CAMINHO, nesta ordem: um `dbPath` explícito fornecido pelo chamador da
|
|
298
|
+
ferramenta, depois `PANTHEON_COST_DB=/caminho/absoluto/para/opencode.db`,
|
|
299
|
+
depois `OPENCODE_DB`, e por fim o padrão do XDG `opencode.db`. Não há nome de
|
|
300
|
+
arquivo por versão nessa cadeia: `opencode-v2.db` não é um banco de um host 2.x
|
|
301
|
+
— é o nome que um sandbox dá ao próprio banco de estado via `OPENCODE_DB`.
|
|
302
|
+
|
|
303
|
+
A distinção v1/v2 é o SCHEMA DETECTADO, não o nome do arquivo. O relatório
|
|
304
|
+
procura as tabelas `message` e `session_message` e lê aquele que o banco aberto
|
|
305
|
+
realmente tiver, porque um banco migrado carrega as duas famílias ao mesmo
|
|
306
|
+
tempo. `PANTHEON_OPENCODE_VERSION=v1|v2` não seleciona arquivo nenhum: apenas
|
|
307
|
+
estreita um conjunto já detectado para uma família de tabelas, e falha rápido
|
|
308
|
+
quando o valor não é `v1` nem `v2` ou quando a família pedida não existe lá.
|
|
309
|
+
Sem a variável, todas as famílias detectadas são lidas. Um banco sem nenhuma
|
|
310
|
+
das duas tabelas volta como erro acionável (`CORRUPT_DATA`), e um ledger que
|
|
311
|
+
existe mas não produz tokens legíveis como `UNSUPPORTED` — nunca como um
|
|
312
|
+
relatório vazio com sucesso.
|
|
169
313
|
|
|
170
314
|
O instalador continua gravando as configurações de compatibilidade exigidas
|
|
171
315
|
pelo host OpenCode selecionado, como `experimental.subagent_depth`; isso não
|
|
172
316
|
converte um plugin V1 em V2 nem dá hooks V1 ao V2.
|
|
173
317
|
|
|
318
|
+
O Pantheon não define mais um teto de passos para os agentes. No OpenCode 2 o
|
|
319
|
+
campo `steps` é opcional e não tem default: ausente significa que o host não
|
|
320
|
+
aplica nenhum limite nativo. Uma config escrita antes dessa mudança ainda
|
|
321
|
+
carrega o valor antigo, e o caminho de instalação v2 o remove de todos os
|
|
322
|
+
agentes que o Pantheon gerencia — um agente definido por você nunca é tocado,
|
|
323
|
+
e o bloco V1 singular `agent`, em retirada, é deixado intacto. Rode o
|
|
324
|
+
instalador uma vez para limpar um valor antigo de uma config existente:
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
npx pantheon-opencode init --opencode-version=v2
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
O controle de contexto não é uma configuração do Pantheon. Qualquer orçamento
|
|
331
|
+
que um agente terá vem das settings de compactação do próprio host OpenCode,
|
|
332
|
+
e o Pantheon não as define.
|
|
333
|
+
|
|
334
|
+
Quando um bloco V1 `agent` e um bloco V2 `agents` coexistem — o que acontece
|
|
335
|
+
em qualquer `opencode.json` já instalado — a conversão V1→V2 mescla os dois em
|
|
336
|
+
vez de deixar um substituir o outro. O bloco V2 é a base, os campos
|
|
337
|
+
gerenciados que vêm do V1 sobrescrevem, e os seus próprios campos são
|
|
338
|
+
preservados, com a mesma precedência que o instalador já aplica em outros
|
|
339
|
+
pontos. A ordem das chaves não muda o resultado.
|
|
340
|
+
|
|
174
341
|
## Atualizando entre releases (beta.5+)
|
|
175
342
|
|
|
176
343
|
Um comando mantém uma instalação existente em dia:
|
|
@@ -193,7 +360,15 @@ pacote. Duas garantias de freshness sustentam isso:
|
|
|
193
360
|
- **Sync de artifacts no postinstall** — depois de qualquer `npm install`, os
|
|
194
361
|
artefatos de cópia (agents, skills, AGENTS.md, commands, scripts MCP,
|
|
195
362
|
payload code-mode) são atualizados automaticamente no config dir existente;
|
|
196
|
-
você nunca precisa re-rodar `init` só para atualizar arquivos.
|
|
363
|
+
você nunca precisa re-rodar `init` só para atualizar arquivos. O config dir
|
|
364
|
+
global recebe o **artefato global** agnóstico de repositório
|
|
365
|
+
(`AGENTS.global.md`: tabela de agentes + regras compartilhadas), enquanto o
|
|
366
|
+
`AGENTS.md` de cada projeto carrega apenas o setup específico do projeto —
|
|
367
|
+
os dois são esculpidos para serem disjuntos (trabalho de latência beta-10),
|
|
368
|
+
então nenhuma regra é paga duas vezes por sessão. A instalação é
|
|
369
|
+
conservadora: conteúdo fora da região gerenciada (regras próprias do
|
|
370
|
+
usuário) é preservado verbatim, um `AGENTS.md` legado totalmente gerado é
|
|
371
|
+
atualizado in place, e qualquer merge é reportado com um aviso.
|
|
197
372
|
- **Detecção de drift** — o instalador grava a versão instalada em
|
|
198
373
|
`.pantheon/install-state.json` e o `doctor` avisa quando o pacote é mais
|
|
199
374
|
novo que o último sync, apontando para o `update`.
|
|
@@ -213,6 +388,10 @@ de PR, push, merge e tag nunca publicam nada, e todos os gates de validação s
|
|
|
213
388
|
fail-closed: somente um PASS explícito autoriza release evidence. Consulte
|
|
214
389
|
[docs/RELEASING.md](docs/RELEASING.md) para detalhes de validação e recuperação.
|
|
215
390
|
|
|
391
|
+
Se a seção de uma versão candidata já existir, atualize as notas com
|
|
392
|
+
`node scripts/versioning.mjs changelog <versão>`; o comando mescla `[Unreleased]`
|
|
393
|
+
na versão indicada sem avançar o número do pacote.
|
|
394
|
+
|
|
216
395
|
A validação mantém cada manifest junto do seu lockfile: o root
|
|
217
396
|
`package.json` + `package-lock.json` e o TUI
|
|
218
397
|
`src/plugins/tui/package.json` + `src/plugins/tui/package-lock.json`. Ambos usam
|
|
@@ -267,6 +446,92 @@ de testar silenciosamente a instalação do host.
|
|
|
267
446
|
Isso valida somente o sandbox isolado e preparado. Um PASS não prova suporte
|
|
268
447
|
para todo host real nem para configurações de host que não foram exercitadas.
|
|
269
448
|
|
|
449
|
+
## Benchmark de latência (bench/)
|
|
450
|
+
|
|
451
|
+
O `bench/` mede a latência de sessão de ponta a ponta do CLI `opencode`
|
|
452
|
+
instalado com o plugin V2 do repositório — o baseline contra o qual toda
|
|
453
|
+
mudança de performance de uma release deve ser comparada. Executa dois
|
|
454
|
+
cenários N vezes cada, intercalados (não-interativo, um diretório de sandbox
|
|
455
|
+
novo por run), coleta métricas por run do `opencode.db` em modo READ-ONLY
|
|
456
|
+
(tokens root + sessões filhas sem dupla contagem, tool calls por nome, número
|
|
457
|
+
de sessões filhas) e tempos de hook das linhas `[bench]` que o plugin anexa ao
|
|
458
|
+
`hooks.log`:
|
|
459
|
+
|
|
460
|
+
```bash
|
|
461
|
+
node bench/bin/bench.mjs # 5 runs por cenário (A e B), ~1h
|
|
462
|
+
BENCH_MODEL=opencode-go/glm-5.3-flash node bench/bin/bench.mjs # fixar modelo
|
|
463
|
+
node bench/bin/bench.mjs --runs 1 # smoke: um run por cenário
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
Os resultados vão para `bench/results/<label>-<git-sha>.json` (mediana +
|
|
467
|
+
p80 + falhas por cenário); o label padrão é `baseline` e o harness recusa
|
|
468
|
+
sobrescrever um resultado existente, então a identidade do run fica no nome do
|
|
469
|
+
arquivo. O cenário A faz pesquisa web real, então a variância de rede é
|
|
470
|
+
registrada por run.
|
|
471
|
+
|
|
472
|
+
### Perfis de medição (explícitos, nunca inferidos)
|
|
473
|
+
|
|
474
|
+
As instruções são injetadas por duas superfícies: o diretório de config global
|
|
475
|
+
e o diretório do projeto. O harness declara qual delas exercita, porque um
|
|
476
|
+
resultado só significa algo no perfil onde a mudança atua:
|
|
477
|
+
|
|
478
|
+
| `--profile` | `AGENTS.md` global | `AGENTS.md` de projeto | Uso |
|
|
479
|
+
|---|---|---|---|
|
|
480
|
+
| `host` (padrão) | diretório de config do host (ou `--global-agents`) | nenhum — run dirs ficam vazios | a injeção real do host, sem alteração |
|
|
481
|
+
| `double-injection` | diretório de config do host (ou `--global-agents`) | `--project-agents`, escrito em cada run dir | o perfil no repo onde global+projeto se sobrepõem |
|
|
482
|
+
|
|
483
|
+
O padrão mede os cenários A e B. Use `--scenarios B` para isolar o claim
|
|
484
|
+
one-shot de F1; o cenário selecionado ainda roda N vezes (`--runs 5` por
|
|
485
|
+
padrão).
|
|
486
|
+
|
|
487
|
+
```bash
|
|
488
|
+
# braço candidato: artefato global carveado + artefato de projeto carveado
|
|
489
|
+
node bench/bin/bench.mjs --runs 5 --scenarios B --profile double-injection \
|
|
490
|
+
--global-agents AGENTS.global.md --project-agents AGENTS.md --label f1-candidate
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
Cada braço registra, por run e lido do banco, a identidade (caminho, bytes,
|
|
494
|
+
sha256) de cada arquivo de instrução que a sessão de fato carregou
|
|
495
|
+
(`instruction_state` + `instruction_blob`) — a prova de fidelidade de que o
|
|
496
|
+
que foi medido é o que foi gerado. Um claim só pode se apoiar num run cuja
|
|
497
|
+
provenance mostre que os artefatos global **e** de projeto pretendidos foram
|
|
498
|
+
carregados.
|
|
499
|
+
|
|
500
|
+
### Sinal vs ruído
|
|
501
|
+
|
|
502
|
+
Wall time é pista, não critério: o spread same-day chega a ~8× no cenário A e
|
|
503
|
+
~13× no B. Um efeito só é **confirmado** quando excede o spread same-day (ou
|
|
504
|
+
exige N maior); caso contrário é registrado como **inconclusivo**. Prefira
|
|
505
|
+
medianas de tokens, bem mais estáveis. O wall do cenário A não é métrica de
|
|
506
|
+
claim — ele faz pesquisa web real, então a variância de rede domina.
|
|
507
|
+
|
|
508
|
+
### Proxy do 1º request e evidência de F1
|
|
509
|
+
|
|
510
|
+
O payload de instruções injetado só incide no primeiro request, então o
|
|
511
|
+
`tokens.input` total da árvore (somado em todo turno) é dominado pela variância
|
|
512
|
+
de duração da sessão. Cada run também registra `firstRequest` — o
|
|
513
|
+
`tokens.input` + `tokens.cache.read` da primeira linha assistant — o proxy que
|
|
514
|
+
isola o payload.
|
|
515
|
+
|
|
516
|
+
Uma rodada intercalada no OpenCode v2.0.29 (C1/K1…C5/K5, N=5/braço) mediu o
|
|
517
|
+
contexto do 1º request em 17555 tokens no controle e 15489 na candidata
|
|
518
|
+
(**−2066, −11,8%**; spread intra-braço de 14 tokens em cada braço). D4 confirmou
|
|
519
|
+
22350 B carregados no controle e 13400 B na candidata (−8950 B, −40,0%); o
|
|
520
|
+
oráculo pré-registrado passou em 5/5 nos dois braços. O efeito no primeiro
|
|
521
|
+
request está confirmado contra o spread intra-braço; a aceitação final de F1
|
|
522
|
+
aguarda revisão do Themis. O input total da árvore caiu da mediana de 47594 para
|
|
523
|
+
38253 tokens, mas os ranges se sobrepõem e a hipótese de ≤30k não foi atingida.
|
|
524
|
+
As medianas de wall foram 30,078 s e 24,130 s, com spread alto; input total e
|
|
525
|
+
wall permanecem **inconclusivos**. Não há claim de ganho de wall ou custo
|
|
526
|
+
monetário. Detalhes e artefatos por run:
|
|
527
|
+
`bench/results/f1-di-v229-interleaved-2026-10-14.md`. O par sequencial anterior
|
|
528
|
+
permanece somente como evidência de apoio em
|
|
529
|
+
`bench/results/f1-di-v229-clean-2026-10-14.md`. As rodadas exploratórias
|
|
530
|
+
anteriores foram preservadas separadamente em
|
|
531
|
+
`bench/results/f1-double-injection.md` e
|
|
532
|
+
`bench/results/f1-di-v229-preliminary-2026-10-14.md`.
|
|
533
|
+
|
|
534
|
+
|
|
270
535
|
## Cobertura TypeScript do Plugin V2
|
|
271
536
|
|
|
272
537
|
`npm run coverage:plugin-v2` executa a suíte `tests/pantheon/*.test.ts` com a
|
|
@@ -291,7 +556,7 @@ preparado.
|
|
|
291
556
|
|
|
292
557
|
### Divergência intencional do memory MCP
|
|
293
558
|
|
|
294
|
-
`scripts/
|
|
559
|
+
`scripts/memory_mcp.py` e `src/mcp/memory_mcp.py` são
|
|
295
560
|
intencionalmente diferentes. A cópia independente em `scripts/` mantém o
|
|
296
561
|
contrato leve de `memory_*`; a cópia instalada em `src/mcp/` também expõe o
|
|
297
562
|
schema opcional de codemap e `code_index`, `code_query` e `code_neighbors`. As
|
package/bin/pantheon-init.mjs
CHANGED
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
* installOpenCode() from scripts/install/opencode.mjs.
|
|
9
9
|
*
|
|
10
10
|
* Dual-version install (Phase 3): the generated config is V1-shaped and valid
|
|
11
|
-
* under BOTH OpenCode V1 (`opencode` 1.18.x) and V2 (`opencode2
|
|
12
|
-
*
|
|
11
|
+
* under BOTH OpenCode V1 (`opencode` 1.18.x) and V2 (`opencode2`, OpenCode 2.x —
|
|
12
|
+
* `opencode2 --version` prints "opencode v2.0.22"; an early 2.x prerelease
|
|
13
|
+
* printed "0.0.0-next-17444", which is history and not a host observation).
|
|
14
|
+
* V2 reads the same config locations and normalizes V1
|
|
13
15
|
* fields in memory — no native V2 conversion. `--version v2` labels the
|
|
14
16
|
* install for the operator; state isolation is a runtime concern
|
|
15
17
|
* (OPENCODE_DB ~/.local/share/opencode/opencode-v2.db, service port 49375).
|
|
@@ -54,6 +56,9 @@ function printUsage() {
|
|
|
54
56
|
console.log(' npx pantheon-opencode init --components agents,skills,instructions')
|
|
55
57
|
console.log(' npx pantheon-opencode init --opencode-version v1|v2|auto')
|
|
56
58
|
console.log(' npx pantheon-opencode init --preset <name> # Install and activate model preset')
|
|
59
|
+
console.log(
|
|
60
|
+
' npx pantheon-opencode init --merge-dev-config <path> # Merge a dev config (off by default)',
|
|
61
|
+
)
|
|
57
62
|
console.log(' npx pantheon-opencode set-tier <name> # Set active model preset (global)')
|
|
58
63
|
console.log(
|
|
59
64
|
' npx pantheon-opencode update [--stable] # Update package + re-run init (default: beta channel)',
|
|
@@ -287,6 +292,7 @@ async function main() {
|
|
|
287
292
|
'--version',
|
|
288
293
|
'--opencode-version',
|
|
289
294
|
'--components',
|
|
295
|
+
'--merge-dev-config',
|
|
290
296
|
])
|
|
291
297
|
for (let i = 1; i < args.length; i++) {
|
|
292
298
|
const arg = args[i]
|
|
@@ -368,6 +374,22 @@ async function main() {
|
|
|
368
374
|
}
|
|
369
375
|
}
|
|
370
376
|
|
|
377
|
+
// --merge-dev-config <path> opts IN to merging a contributor's personal
|
|
378
|
+
// OpenCode config into the generated one. Only third-party plugin/provider/
|
|
379
|
+
// compaction entries are merged; Pantheon-owned entries are always stripped.
|
|
380
|
+
// Absent this flag no repository-root config is read (product defaults come
|
|
381
|
+
// from the installer code, never from a dev checkout).
|
|
382
|
+
const mergeDevConfigIndex = args.indexOf('--merge-dev-config')
|
|
383
|
+
const inlineMergeDevConfig = args.find((arg) => arg.startsWith('--merge-dev-config='))
|
|
384
|
+
const mergeDevConfigOpt =
|
|
385
|
+
mergeDevConfigIndex >= 0
|
|
386
|
+
? (args[mergeDevConfigIndex + 1] ?? null)
|
|
387
|
+
: (inlineMergeDevConfig?.split('=', 2)[1] ?? null)
|
|
388
|
+
if (mergeDevConfigIndex >= 0 && mergeDevConfigOpt === null) {
|
|
389
|
+
console.error('❌ --merge-dev-config requires a file path')
|
|
390
|
+
process.exit(1)
|
|
391
|
+
}
|
|
392
|
+
|
|
371
393
|
const components = requestedComponents ?? [
|
|
372
394
|
'agents',
|
|
373
395
|
'skills',
|
|
@@ -402,7 +424,8 @@ async function main() {
|
|
|
402
424
|
model: modelOpt,
|
|
403
425
|
smallModel: smallModelOpt,
|
|
404
426
|
preset: presetOpt,
|
|
405
|
-
version: versionOpt ?? '
|
|
427
|
+
version: versionOpt ?? 'auto',
|
|
428
|
+
mergeDevConfig: mergeDevConfigOpt,
|
|
406
429
|
})
|
|
407
430
|
} catch (err) {
|
|
408
431
|
if (err?.message === 'Canceled') {
|
|
@@ -15,7 +15,13 @@ agent: "zeus"
|
|
|
15
15
|
## Layers
|
|
16
16
|
|
|
17
17
|
### Layer 1 — Heuristic Scan
|
|
18
|
-
|
|
18
|
+
Resolve the installed helper first (do not assume the current project contains
|
|
19
|
+
Pantheon source). Check, in order: `$OPENCODE_CONFIG_DIR/.opencode/scripts/`,
|
|
20
|
+
`$OPENCODE_CONFIG_DIR/scripts/`, `${XDG_CONFIG_HOME:-$HOME/.config}/opencode/scripts/`,
|
|
21
|
+
`$HOME/.opencode/scripts/`, `.opencode/scripts/`, then
|
|
22
|
+
`$(npm root -g)/pantheon-opencode/scripts/`. Resolve the first existing file to
|
|
23
|
+
an absolute path and run `python3 "$helper" --path="$PWD"`; if none exists,
|
|
24
|
+
report the helper as missing and stop Layer 1 rather than claiming it passed.
|
|
19
25
|
Zero tokens, <2s. Checks: ruff, biome, anti-pattern slop, anti-overengineering (YAGNI), hash-anchored edits. Returns score 0-100 + APPROVED/BLOCKING.
|
|
20
26
|
|
|
21
27
|
### Layer 2 — Themis Deep Review
|
|
@@ -15,8 +15,15 @@ Structured, checkpointed workflow for complex multi-step tasks spanning multiple
|
|
|
15
15
|
## Workflow
|
|
16
16
|
|
|
17
17
|
```
|
|
18
|
-
Phase 0:
|
|
19
|
-
└─
|
|
18
|
+
Phase 0: PLAN AND APPROVAL
|
|
19
|
+
└─ @athena returns the complete, detailed Markdown plan to Zeus
|
|
20
|
+
└─ Zeus publishes the full plan as a normal message in the main conversation (not only in the child-agent transcript)
|
|
21
|
+
└─ GATE 1: open the approval UI only after that plan message is visible; never bundle or reverse the two
|
|
22
|
+
└─ If the runtime cannot guarantee that order, ask for approval in plain text after the plan and wait
|
|
23
|
+
└─ Wait for explicit approval or requested changes
|
|
24
|
+
└─ For requested changes, redisplay the entire revised plan and repeat Gate 1
|
|
25
|
+
└─ Do not start discovery or implementation before approval
|
|
26
|
+
└─ After approval, persist the approved plan as PLAN.md through the artifact workflow
|
|
20
27
|
|
|
21
28
|
Phase 1: DISCOVERY
|
|
22
29
|
└─ @apollo maps relevant codebase areas → DISCOVERY.md
|
|
@@ -44,7 +51,11 @@ Usage: --resume <slug> | --status <slug> | --list
|
|
|
44
51
|
|
|
45
52
|
## Full-Auto Mode (`--full-auto`)
|
|
46
53
|
|
|
47
|
-
> ⚠️
|
|
54
|
+
> ⚠️ Automates only eligible review gates. Gate 1 and commit/deploy gates still require approval.
|
|
55
|
+
|
|
56
|
+
`--full-auto` does not hide the plan or skip Gate 1: Zeus still displays the
|
|
57
|
+
complete plan in the main conversation and waits for explicit approval before
|
|
58
|
+
discovery or implementation. It only affects the later gates described below.
|
|
48
59
|
|
|
49
60
|
**Themis auto-approves non-blocking reviews** — only stops on **BLOCKING** verdict. No waiting between phases. Checkpoints saved at every boundary.
|
|
50
61
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Set or update this session's working goal"
|
|
3
|
+
agent: zeus
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Pin `$ARGUMENTS` as the working goal for this conversation. Restate it briefly
|
|
7
|
+
as Goal, Scope, Success Criteria, and Out of Scope, filling only what the user
|
|
8
|
+
actually supplied. Ask one concise question if a missing detail changes the
|
|
9
|
+
work materially.
|
|
10
|
+
|
|
11
|
+
Treat the goal as session context, subordinate to system, developer, and user
|
|
12
|
+
instructions. Keep subsequent planning, delegation, and verification aligned
|
|
13
|
+
with it; flag meaningful scope drift before proceeding.
|
|
14
|
+
|
|
15
|
+
This command is conversation-only. Do not call memory or persistence tools,
|
|
16
|
+
write a file, or claim that the goal survives compaction or a new session. For
|
|
17
|
+
multi-phase work that needs durable checkpoints, use `/pantheon-deepwork`.
|
|
@@ -14,33 +14,80 @@ not being described, switching between native and tool mode.
|
|
|
14
14
|
|
|
15
15
|
1. **Check connectivity & key source**
|
|
16
16
|
- Read the opencode auth store: `<data dir>/auth.json`
|
|
17
|
-
(default `~/.local/share/opencode/auth.json
|
|
18
|
-
|
|
17
|
+
(default `~/.local/share/opencode/auth.json`) via `readOpencodeAuthToken`.
|
|
18
|
+
- Credentials follow the endpoint (never cross providers):
|
|
19
|
+
- **Zen endpoints** (`opencode`, `opencode-go*`): the env keys
|
|
20
|
+
`PANTHEON_OPENCODE_API_KEY` / `OPENCODE_API_KEY` first, then the auth
|
|
21
|
+
store — the resolved provider entry first, then the legacy Zen entries
|
|
22
|
+
`opencode-go` then `opencode`.
|
|
23
|
+
- **Non-Zen endpoints** (e.g. discovered OpenAI-compatible providers):
|
|
24
|
+
ONLY that provider's own auth-store entry. The shared Zen env keys and
|
|
25
|
+
the legacy `opencode-go` / `opencode` entries are never attached to a
|
|
26
|
+
non-Zen base URL; absent an own credential the image falls through to
|
|
27
|
+
the tool→local chain.
|
|
19
28
|
- Report whether the user is connected (`opencode auth login`) or has an
|
|
20
|
-
env key
|
|
29
|
+
env key — for a non-Zen target, report the target provider's own entry.
|
|
21
30
|
- **Never log or echo the token itself** — only connected/not connected.
|
|
22
31
|
|
|
23
|
-
2. **Show current status**
|
|
32
|
+
2. **Show current status (mode + resolved target + origin)**
|
|
24
33
|
- Effective mode precedence: env `PANTHEON_VISION_MODE` > config file
|
|
25
34
|
`mode` > default `auto`.
|
|
26
|
-
-
|
|
27
|
-
|
|
35
|
+
- Resolved target + origin, in precedence order:
|
|
36
|
+
env `PANTHEON_VISION_MODEL` → config `visionModel` (project
|
|
37
|
+
`.opencode/opencode-vision.json`, then user
|
|
38
|
+
`~/.config/opencode/opencode-vision.json`) → active preset `vision.model`
|
|
39
|
+
→ **automatic discovery** in the host catalog (`GET /config/providers`)
|
|
40
|
+
→ built-in default.
|
|
41
|
+
- Resolve the installed helper first (do not assume the current project
|
|
42
|
+
contains Pantheon source). Check, in order:
|
|
43
|
+
`$OPENCODE_CONFIG_DIR/.opencode/scripts/`,
|
|
44
|
+
`$OPENCODE_CONFIG_DIR/scripts/`,
|
|
45
|
+
`${XDG_CONFIG_HOME:-$HOME/.config}/opencode/scripts/`,
|
|
46
|
+
`$HOME/.opencode/scripts/`, `.opencode/scripts/`, then
|
|
47
|
+
`$(npm root -g)/pantheon-opencode/scripts/`. Run the first existing
|
|
48
|
+
`vision-status.mjs` as `node "$helper" --dir="$PWD"` and show its output
|
|
49
|
+
(mode + target + origin). The same helper drives the picker with
|
|
50
|
+
`--list` (enumerate candidates) and `--set <provider/model>` (pin one).
|
|
51
|
+
- If the helper is missing, resolve inline with the same precedence and be
|
|
52
|
+
honest: discovery needs the live host catalog, so when no explicit model
|
|
53
|
+
is configured report `auto (resolved at session start)` and name the
|
|
54
|
+
fallback default — never invent a value.
|
|
28
55
|
|
|
29
56
|
3. **Ask what to set (interactive)**
|
|
30
57
|
- **Mode:** `native` | `tool` | `auto`
|
|
31
|
-
- `native` — describe images via the multimodal model directly (needs
|
|
58
|
+
- `native` — describe images via the multimodal model directly (needs a
|
|
59
|
+
usable credential for the resolved endpoint)
|
|
32
60
|
- `tool` — always use the MCP tool fallback (`imageAnalysisTool`)
|
|
33
61
|
- `auto` — try native first, fall back to the tool (default)
|
|
34
|
-
- **Vision model
|
|
35
|
-
|
|
36
|
-
`
|
|
62
|
+
- **Vision model — show the picker, do NOT make the user type blind.**
|
|
63
|
+
Run `node "$helper" --list --dir="$PWD"` and present its numbered list.
|
|
64
|
+
- **Read the `Source:` line out loud.** It is `host catalog`
|
|
65
|
+
(`capabilities.input.image`) when the live catalog is available, or
|
|
66
|
+
`heuristic` (`opencode models` + known vision families) otherwise — the
|
|
67
|
+
heuristic is a *guess*, so say so; never present it as certain.
|
|
68
|
+
- Each row shows `Access` (free/paid when the catalog reports cost) and
|
|
69
|
+
`Credential`. **`Credential: no` means the native path has no key for
|
|
70
|
+
that provider, so images degrade to the MCP tool fallback (which then
|
|
71
|
+
falls back to local metadata like EXIF/size) — that is expected, not an
|
|
72
|
+
error.** `yes (env|store)` means a key is present (never echo it).
|
|
73
|
+
- Let the user choose by **number** or type a `provider/model`. Then apply
|
|
74
|
+
it with `node "$helper" --set <provider/model> --dir="$PWD"` (add
|
|
75
|
+
`--global` to pin in the user config; default is the project config).
|
|
76
|
+
- If the list is empty, report the helper's `Source: none` reason (e.g.
|
|
77
|
+
`opencode models` unavailable) and let the user type the model manually.
|
|
78
|
+
- Precedence for the effective model is unchanged: env
|
|
79
|
+
`PANTHEON_VISION_MODEL` > config `visionModel` > active preset
|
|
80
|
+
`vision.model` > automatic discovery > default `opencode-go/mimo-v2.5`.
|
|
37
81
|
- **Tool fallback:** `imageAnalysisTool` (default
|
|
38
82
|
`pantheon_vision_vision_describe`). Bifrost is opt-in only when
|
|
39
83
|
explicitly selected here or through `PANTHEON_VISION_TOOL`.
|
|
40
84
|
|
|
41
85
|
4. **Save the config**
|
|
42
|
-
-
|
|
43
|
-
(
|
|
86
|
+
- The `--set` in step 3 already merged `visionModel` atomically
|
|
87
|
+
(`.bak` backup, existing keys preserved, corrupted JSON left untouched).
|
|
88
|
+
If the user typed a model instead of using `--set`, apply it the same way.
|
|
89
|
+
- Default target: project config `.opencode/opencode-vision.json`
|
|
90
|
+
(resolved alongside the user config `~/.config/opencode/opencode-vision.json`;
|
|
44
91
|
project wins on conflicts).
|
|
45
92
|
- `--global` → write to `~/.config/opencode/opencode-vision.json`.
|
|
46
93
|
- Shape:
|
|
@@ -65,3 +112,5 @@ not being described, switching between native and tool mode.
|
|
|
65
112
|
- Do NOT print tokens or auth.json contents.
|
|
66
113
|
- Do NOT overwrite existing config keys not being changed — merge.
|
|
67
114
|
- If the config file is corrupted JSON, warn and ask before overwriting.
|
|
115
|
+
- State the picker's `Source:` (catalog vs heuristic) honestly — a heuristic
|
|
116
|
+
list is a guess; never imply certainty about image capability.
|