pantheon-opencode 1.6.0-beta.6 → 1.6.0-beta.8
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.md +19 -769
- package/CHANGELOG.md +53 -0
- package/README.md +78 -9
- package/README.pt-BR.md +10 -4
- package/package.json +5 -1
- package/plugin.json +2 -2
- package/pyproject.toml +3 -1
- package/scripts/build-agents-md.mjs +159 -26
- package/scripts/install/agents-md.mjs +2 -2
- package/scripts/install/config-migration.mjs +115 -1
- package/scripts/install/interactive.mjs +1 -1
- package/scripts/install/opencode.mjs +245 -12
- package/scripts/install/shared.mjs +115 -7
- package/scripts/sync-artifacts.mjs +2 -2
- package/scripts/test-opencode-v2-sandbox.sh +155 -4
- package/scripts/validate-sandbox-install.mjs +138 -0
- package/skills-lock.json +5 -5
- package/src/agents/aphrodite.md +18 -36
- package/src/agents/demeter.md +8 -27
- package/src/agents/gaia.md +1 -0
- package/src/agents/hephaestus.md +10 -20
- package/src/agents/hermes.md +15 -37
- package/src/agents/mnemosyne.md +14 -42
- package/src/agents/prometheus.md +16 -19
- package/src/agents/talos.md +4 -1
- package/src/agents/themis.md +4 -4
- package/src/agents/zeus.md +24 -127
- package/src/instructions/agent-return-format.instructions.md +2 -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 -121
- package/src/instructions/zeus-anti-stall.instructions.md +14 -69
- 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/pantheon/v2-delegation-enforce.ts +87 -0
- package/src/pantheon/v2-execute-after.ts +186 -0
- package/src/pantheon/v2-unsupported.mjs +0 -23
- package/src/plugin-v2.ts +271 -36
- package/src/plugins/tui/dist/tui.d.ts +11 -8
- package/src/plugins/tui/dist/tui.d.ts.map +1 -1
- package/src/plugins/tui/dist/tui.js +53 -37
- package/src/plugins/tui/package-lock.json +30 -33
- package/src/plugins/tui/package.json +5 -1
- package/src/plugins/tui/src/index.tsx +103 -82
- package/src/plugins/tui/tsdown.config.ts +17 -0
- package/src/routing.yml +10 -5
- package/src/skills/README.md +3 -3
- package/src/skills/artifact-management/SKILL.md +12 -5
- package/src/skills/auto-continue/SKILL.md +37 -28
- package/src/skills/code-review-checklist/SKILL.md +5 -5
- package/src/skills/context-compression/SKILL.md +26 -879
- package/src/skills/tdd-with-agents/SKILL.md +18 -10
package/CHANGELOG.md
CHANGED
|
@@ -18,6 +18,59 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
18
18
|
|
|
19
19
|
## ✅ Closed Issues
|
|
20
20
|
|
|
21
|
+
## [v1.6.0-beta.8] - 2026-10-11
|
|
22
|
+
|
|
23
|
+
<!-- Add new changes here. Running `node scripts/versioning.mjs apply` will
|
|
24
|
+
move this section to a versioned entry and reset the template below. -->
|
|
25
|
+
|
|
26
|
+
## 🐞 Fixed
|
|
27
|
+
|
|
28
|
+
- **opencode-v2** — repair session lookup and beta sandbox reuse
|
|
29
|
+
- **scripts** — isolate beta background service port
|
|
30
|
+
## [v1.6.0-beta.7] - 2026-10-10
|
|
31
|
+
|
|
32
|
+
<!-- Add new changes here. Running `node scripts/versioning.mjs apply` will
|
|
33
|
+
move this section to a versioned entry and reset the template below. -->
|
|
34
|
+
|
|
35
|
+
## 🆕 What's New
|
|
36
|
+
|
|
37
|
+
- **Permissões MCP nativas por agente no OpenCode V1 e V2.** O instalador
|
|
38
|
+
converte a allowlist `mcp_tools` de cada agente em regras nativas: nega por
|
|
39
|
+
padrão os servidores Pantheon omitidos, libera apenas as ferramentas
|
|
40
|
+
declaradas e preserva MCPs de terceiros. O V2 mantém os servidores
|
|
41
|
+
conectados; as regras limitam quais ferramentas cada agente vê.
|
|
42
|
+
- **Guarda V2 de delegação alinhada ao contrato de permissões.** Os hooks de
|
|
43
|
+
permissão e de sessão aplicam as restrições de sessão somente-leitura e a
|
|
44
|
+
matriz caller→target sem conceder acesso além do configurado pelo host.
|
|
45
|
+
- **Menos chamadas automáticas de memória e compressão.** A busca de contexto
|
|
46
|
+
do Zeus reutiliza o resultado de início de tarefa, e o protocolo de
|
|
47
|
+
compressão deixa de recomendar pipelines automáticos extensos.
|
|
48
|
+
- **Prova de identidade da instalação do sandbox.** O teste global compara a
|
|
49
|
+
versão e arquivos do pacote instalado com este checkout e rejeita referências
|
|
50
|
+
npm antigas nas configurações ativas antes de validar o runtime.
|
|
51
|
+
- O `--prepare` agora gera `start-pantheon.sh` para abrir o TUI interativo com o
|
|
52
|
+
beta instalado e HOME, configuração XDG, projeto e banco de dados isolados do
|
|
53
|
+
sandbox. O launcher fixa a porta do serviço gerenciado em `49376` e falha sem
|
|
54
|
+
parar serviços existentes se a porta dedicada já estiver ocupada.
|
|
55
|
+
|
|
56
|
+
## 🐞 Fixed
|
|
57
|
+
|
|
58
|
+
- Referências versionadas/alias do pacote Pantheon que sobravam na lista
|
|
59
|
+
`plugins` agora são reconhecidas pelo instalador e substituídas pelo caminho
|
|
60
|
+
do plugin local correto, sem afetar plugins de terceiros com nomes parecidos.
|
|
61
|
+
- A suíte CI foi separada do caminho crítico de instalação/empacotamento para
|
|
62
|
+
reduzir o tempo até o resultado das verificações do pacote.
|
|
63
|
+
- O `run-test.sh` gerado agora define seu timeout do `mcp list` antes do uso
|
|
64
|
+
sob `set -u`; antes, a variável ausente interrompia o teste antes de chamar
|
|
65
|
+
o CLI. A saída do comando também fica disponível quando o gate falha.
|
|
66
|
+
|
|
67
|
+
## ⚠️ Known Issues
|
|
68
|
+
|
|
69
|
+
- **A delegação real ainda precisa de confirmação nesta beta.** O teste manual
|
|
70
|
+
anterior de `HERMES-PONG` foi negado com
|
|
71
|
+
`Pantheon delegation denied: authoritative caller session is unavailable`;
|
|
72
|
+
a correção de permissões e a instalação isolada precisam ser verificadas no
|
|
73
|
+
TUI OpenCode V2 antes de considerar a delegação validada.
|
|
21
74
|
## [v1.6.0-beta.6] - 2026-10-05
|
|
22
75
|
|
|
23
76
|
<!-- Add new changes here. Running `node scripts/versioning.mjs apply` will
|
package/README.md
CHANGED
|
@@ -54,6 +54,9 @@ project-local installation, or non-interactive setup, see the
|
|
|
54
54
|
[installation guide](docs/INSTALLATION.md).
|
|
55
55
|
The bundled Python MCP servers use the pinned MCP SDK 2.2.0 and standalone
|
|
56
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).
|
|
57
60
|
|
|
58
61
|
## A simple example
|
|
59
62
|
|
|
@@ -80,6 +83,13 @@ clear handoff between stages of work.
|
|
|
80
83
|
- Project memory that helps preserve relevant context between sessions.
|
|
81
84
|
- Optional integrations for common development tasks.
|
|
82
85
|
|
|
86
|
+
Memory is used selectively: the coordinator searches once only when project
|
|
87
|
+
history could affect a task, then passes relevant results to specialists. Store
|
|
88
|
+
one concise, reusable outcome at task completion when it will matter later;
|
|
89
|
+
routine child summaries and phase updates stay in the current handoff. The
|
|
90
|
+
session-checkpoint tools are separate, optional persistence APIs and are not
|
|
91
|
+
called automatically by compaction hooks. See [Memory usage](docs/MEMORY.md).
|
|
92
|
+
|
|
83
93
|
## Status
|
|
84
94
|
|
|
85
95
|
Candidate version: the manifests in this checkout express the version being
|
|
@@ -131,10 +141,15 @@ host is an unsupported mixed/wrong-generation configuration, not a supported mod
|
|
|
131
141
|
**Not inert.** The V2 path (`src/plugin-v2`, registered as a directory because
|
|
132
142
|
the V2 loader rejects bare file paths) registers real tools with real
|
|
133
143
|
`input`/`output` schemas via `ctx.tool.transform()`, 5 event subscriptions,
|
|
134
|
-
session hooks and
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
144
|
+
session hooks and tool/permission hooks that enforce read-only sessions and the
|
|
145
|
+
caller→target delegation matrix. The matrix applies only to Pantheon-managed
|
|
146
|
+
targets: Zeus may delegate to any registered agent; Athena and Hermes may target
|
|
147
|
+
Apollo only; other Pantheon callers and unknown callers are denied. Child
|
|
148
|
+
sessions cannot delegate to Pantheon agents. Calls between native/custom agents
|
|
149
|
+
remain under host permissions. The V2 path never adds an allow grant or
|
|
150
|
+
overrides an explicit host deny; missing or mismatched identity fails closed
|
|
151
|
+
for the attempted Pantheon delegation. The 3 goal tools remain unsupported and
|
|
152
|
+
are reported as `goal-tools`.
|
|
138
153
|
|
|
139
154
|
**Not complete either, and the V2 support claim is currently narrowed.** Two
|
|
140
155
|
facts, both recorded in this repository rather than smoothed over:
|
|
@@ -175,6 +190,28 @@ there is no Pantheon-specific delegation tool surface to configure. See
|
|
|
175
190
|
[ADR-0011](.pantheon/memory-bank/adr/0011-delegation-engine-contract.md) for the
|
|
176
191
|
historical engine contract.
|
|
177
192
|
|
|
193
|
+
This beta.8 candidate combines native per-agent MCP permissions for OpenCode V1
|
|
194
|
+
and V2, V2 delegation-permission alignment, simpler memory/compression
|
|
195
|
+
instructions, and a sandbox check that proves the installed package matches
|
|
196
|
+
this checkout instead of silently accepting stale npm-cached code. The isolated
|
|
197
|
+
sandbox launcher also pins the OpenCode background service to its dedicated
|
|
198
|
+
loopback port, rather than colliding with another OpenCode installation. The Zeus
|
|
199
|
+
prompt reuses one task-start memory-search result for context and routing;
|
|
200
|
+
runtime call counts and latency have not been measured. A beta.7 V2 dispatch
|
|
201
|
+
failed because the permission hook passed a bare string to `ctx.session.get`
|
|
202
|
+
instead of the V2 input object `{ sessionID }`; beta.8 corrects the call and
|
|
203
|
+
adds contract tests for the success and failure cases. The user subsequently
|
|
204
|
+
reported a successful Hermes liveness delegation in the active session, but
|
|
205
|
+
freshly restarting and testing the beta.8 sandbox remains the end-to-end gate.
|
|
206
|
+
The original report also included a separate `GET /api/session/{id}/permission`
|
|
207
|
+
404; the session ID exists in the beta7-candidate database but not the default
|
|
208
|
+
global database. Both OpenCode services were running, so the 404 in the global
|
|
209
|
+
log may come from the other instance; this remains an end-to-end verification
|
|
210
|
+
item.
|
|
211
|
+
|
|
212
|
+
Delegated tasks get at most one retry after an initial timeout or failure. If
|
|
213
|
+
that retry fails, the configured fallback or escalation chain applies.
|
|
214
|
+
|
|
178
215
|
## Cost tool backend
|
|
179
216
|
|
|
180
217
|
`pantheon_cost` prefers a read-only `node:sqlite` backend against the selected
|
|
@@ -285,10 +322,16 @@ surface: the host includes the active agent on the event, a read-only agent
|
|
|
285
322
|
`createEnforcementGuard` throws to deny `edit`, `write`, `bash`, `task`,
|
|
286
323
|
`hashline_edit` and `pantheon_model`. It does **not** rely on the V1
|
|
287
324
|
`tool.execute.before` hook, which lives in `src/plugin.ts` and is not loaded
|
|
288
|
-
when only `plugin-v2` is configured. The
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
325
|
+
when only `plugin-v2` is configured. The `permission.evaluate` hook enforces
|
|
326
|
+
the V2 caller/target matrix for Pantheon-managed targets across every entry in
|
|
327
|
+
the host's `resources` array. Native-only resources pass through unchanged to
|
|
328
|
+
OpenCode's permission policy; mixed native/Pantheon requests and multi-target
|
|
329
|
+
requests are denied unless every Pantheon target is explicitly allowed for the
|
|
330
|
+
authoritative caller. Explicit host denies remain final, and missing or
|
|
331
|
+
unknown resource data fails closed. If a denied evaluation has no mutable host
|
|
332
|
+
output argument, the hook throws to fail closed rather than silently omitting
|
|
333
|
+
the denial. V2 `execute.after` runs the completed-result chain:
|
|
334
|
+
`task-result-guard` → `context-sandbox` → `read-enhancer`.
|
|
292
335
|
|
|
293
336
|
Every V2 tool declares an `output` schema. OpenCode 2.0.x requires the
|
|
294
337
|
declaration and the resolved result to agree in both directions, so an
|
|
@@ -473,6 +516,10 @@ Release validation keeps each manifest with its lockfile: the root
|
|
|
473
516
|
SHA-256 of that same artifact, and binds the tarball and GitHub release to the
|
|
474
517
|
full `TARGET_SHA`; a second pack is not interchangeable.
|
|
475
518
|
|
|
519
|
+
CI also rebuilds the TUI with `npm run build --prefix src/plugins/tui` and
|
|
520
|
+
checks every packaged `dist` artifact byte-for-byte against its checked-in
|
|
521
|
+
version, including final newlines.
|
|
522
|
+
|
|
476
523
|
## Sandbox validation (V2)
|
|
477
524
|
|
|
478
525
|
`scripts/test-opencode-v2-sandbox.sh` validates the globally installed
|
|
@@ -484,6 +531,11 @@ agent delegation. The gate is fail-closed: every required check must return an
|
|
|
484
531
|
explicit PASS; timeouts, auth/network/provider failures and missing
|
|
485
532
|
prerequisites block the run.
|
|
486
533
|
|
|
534
|
+
The runner defaults to the current stable `@opencode/cli` package and its
|
|
535
|
+
`opencode2` alias; set `OPENCODE_V2_SPEC` only when a test needs a different
|
|
536
|
+
host build. This keeps Pantheon beta testing separate from the OpenCode CLI
|
|
537
|
+
release channel.
|
|
538
|
+
|
|
487
539
|
"V2" here refers only to the hook canary observed against an OpenCode v2.0.18
|
|
488
540
|
host, where at least one tested hook callback fired; it does not establish
|
|
489
541
|
compatibility with the stable `@opencode/plugin@2.0.18` SDK or full 2.x
|
|
@@ -495,6 +547,7 @@ single leg.
|
|
|
495
547
|
|
|
496
548
|
```bash
|
|
497
549
|
scripts/test-opencode-v2-sandbox.sh --prepare # tarball + install + init in the sandbox
|
|
550
|
+
~/pantheon-sandbox/start-pantheon.sh # interactive TUI in that isolated beta sandbox
|
|
498
551
|
scripts/test-opencode-v2-sandbox.sh --run v2 # base validation only
|
|
499
552
|
scripts/test-opencode-v2-sandbox.sh --prompts # base validation + prompt battery
|
|
500
553
|
scripts/test-opencode-v2-sandbox.sh --rehydrate # offline context rehydration/session-summary probe
|
|
@@ -533,7 +586,7 @@ Env overrides:
|
|
|
533
586
|
|----------|---------|---------|
|
|
534
587
|
| `PANTHEON_SANDBOX_ROOT` | `~/pantheon-sandbox` | Sandbox root (refused if unsafe for `--reset`) |
|
|
535
588
|
| `OPENCODE_V1_SPEC` | `opencode-ai@1.18.18` | Configures the V1 plugin only; the V2-only sandbox runner does not consume or support it |
|
|
536
|
-
| `OPENCODE_V2_SPEC` | `@opencode
|
|
589
|
+
| `OPENCODE_V2_SPEC` | `@opencode/cli@latest` | npm spec providing the `opencode2` binary |
|
|
537
590
|
| `PANTHEON_SANDBOX_MODEL` | `opencode-go/mimo-v2.5` | Model used by init and prompts |
|
|
538
591
|
| `PANTHEON_PROMPT_TIMEOUT` | `300` | Per-prompt timeout in seconds |
|
|
539
592
|
|
|
@@ -591,6 +644,22 @@ Ideas, bug reports, documentation improvements, and code contributions are
|
|
|
591
644
|
welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) before opening an issue
|
|
592
645
|
or pull request.
|
|
593
646
|
|
|
647
|
+
### Reproducible benchmark evidence
|
|
648
|
+
|
|
649
|
+
The beta2 benchmark records reported token usage separately from its
|
|
650
|
+
character-based fallback estimate; source bytes and logical line counts remain
|
|
651
|
+
provenance data and are never converted into tokens. Cross-report comparisons
|
|
652
|
+
require matching model/config provenance and reported OpenCode usage. Offline
|
|
653
|
+
fixture responses are mocked: their reported values are labeled separately,
|
|
654
|
+
excluded from `actual` usage, and blocked from comparative metrics and GEPA.
|
|
655
|
+
Fixture quality outcomes test the offline contract; they are not evaluation
|
|
656
|
+
evidence.
|
|
657
|
+
Reproduce the
|
|
658
|
+
checked-in AGENTS.md history manifest with
|
|
659
|
+
`python3 -m benchmarks.beta2.provenance --output benchmarks/beta2/fixtures/agent-baseline-provenance.json`.
|
|
660
|
+
For OpenCode benchmark runs, provide `--model` and `--config-sha256` so reports
|
|
661
|
+
can be compared safely.
|
|
662
|
+
|
|
594
663
|
### Project-level `opencode.json`
|
|
595
664
|
|
|
596
665
|
The published package carries no `opencode.json` template. `init` still writes
|
package/README.pt-BR.md
CHANGED
|
@@ -141,10 +141,16 @@ dessa superfície: o host inclui o agente ativo no evento, um agente somente-lei
|
|
|
141
141
|
compartilhado lança para negar `edit`, `write`, `bash`, `task`,
|
|
142
142
|
`hashline_edit` e `pantheon_model`. Ele **não** depende do hook
|
|
143
143
|
`tool.execute.before` do V1, que vive em `src/plugin.ts` e não é carregado
|
|
144
|
-
quando apenas `plugin-v2` está configurado.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
144
|
+
quando apenas `plugin-v2` está configurado. O hook `permission.evaluate`
|
|
145
|
+
aplica no V2 a matriz caller/target para destinos gerenciados pelo Pantheon,
|
|
146
|
+
considerando todos os itens do array `resources` do host. Recursos
|
|
147
|
+
exclusivamente nativos são repassados sem alteração à política de permissões do
|
|
148
|
+
OpenCode; pedidos mistos (nativos/Pantheon) e com vários destinos são negados,
|
|
149
|
+
a menos que todos os destinos Pantheon sejam explicitamente permitidos para o
|
|
150
|
+
chamador autoritativo. Uma negação explícita do host é final, e dados de
|
|
151
|
+
recursos ausentes ou desconhecidos são negados por padrão. O `execute.after` do
|
|
152
|
+
V2 executa a cadeia de resultados concluídos `task-result-guard` →
|
|
153
|
+
`context-sandbox` → `read-enhancer`; eventos de erro permanecem inalterados.
|
|
148
154
|
|
|
149
155
|
Toda ferramenta V2 declara um schema `output`. O OpenCode 2.0.x exige que a
|
|
150
156
|
declaração e o resultado resolvido concordem nos dois sentidos, então uma
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pantheon-opencode",
|
|
3
|
-
"version": "1.6.0-beta.
|
|
3
|
+
"version": "1.6.0-beta.8",
|
|
4
4
|
"description": "Multi-agent orchestration for OpenCode — 14 specialized agents, TDD, Themis review gates.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"workspaces": [
|
|
@@ -112,8 +112,12 @@
|
|
|
112
112
|
"typescript": "7.0.2"
|
|
113
113
|
},
|
|
114
114
|
"overrides": {
|
|
115
|
+
"@babel/core": "7.29.7",
|
|
116
|
+
"seroval": "1.6.8",
|
|
117
|
+
"solid-js": "1.9.12",
|
|
115
118
|
"rolldown": "1.2.7"
|
|
116
119
|
},
|
|
120
|
+
"//overrides": "TUI production advisory fixes: Babel >=7.29.6 and Seroval >=1.6.3; Solid stays at 1.9.12 to satisfy OpenTUI's exact peer. Remove only after upstream ranges include fixed versions; Seroval compatibility is covered by the Solid serializer regression test.",
|
|
117
121
|
"repository": {
|
|
118
122
|
"type": "git",
|
|
119
123
|
"url": "https://github.com/ils15/pantheon-opencode.git"
|
package/plugin.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pantheon",
|
|
3
3
|
"publisher": "ils15",
|
|
4
|
-
"version": "1.6.0-beta.
|
|
4
|
+
"version": "1.6.0-beta.8",
|
|
5
5
|
"displayName": "Pantheon",
|
|
6
|
-
"description": "Conductor-Delegate orchestration platform with 14 specialized agents,
|
|
6
|
+
"description": "Conductor-Delegate orchestration platform with 14 specialized agents, 20 skills, and OpenCode support.",
|
|
7
7
|
"agents": "./src/agents",
|
|
8
8
|
"skills": "./src/skills",
|
|
9
9
|
"instructions": "./src/instructions",
|
package/pyproject.toml
CHANGED
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.backends._legacy:_Backend"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pantheon"
|
|
7
|
-
version = "1.6.0-beta.
|
|
7
|
+
version = "1.6.0-beta.8"
|
|
8
8
|
description = "Multi-agent orchestration framework"
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
10
|
dependencies = []
|
|
@@ -16,6 +16,7 @@ dependencies = []
|
|
|
16
16
|
testpaths = [
|
|
17
17
|
"tests",
|
|
18
18
|
"benchmarks/beta2/test_beta2.py",
|
|
19
|
+
"benchmarks/beta2/test_t1.py",
|
|
19
20
|
]
|
|
20
21
|
asyncio_mode = "auto"
|
|
21
22
|
addopts = "-v --tb=short"
|
|
@@ -48,6 +49,7 @@ select = ["E", "F", "W", "I", "N", "UP", "B", "SIM", "PL", "RUF", "C901"]
|
|
|
48
49
|
"tests/test_code_mode_frontmatter.py" = ["PLR2004"]
|
|
49
50
|
"tests/test_eval.py" = ["PLR2004"]
|
|
50
51
|
"tests/test_mcp_persistence_server.py" = ["PLR2004"]
|
|
52
|
+
"benchmarks/beta2/test_t1.py" = ["PLR2004"]
|
|
51
53
|
|
|
52
54
|
[tool.mypy]
|
|
53
55
|
python_version = "3.11"
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
* across both versions without duplication, this script consolidates:
|
|
9
9
|
*
|
|
10
10
|
* (a) a static header (project description + agent table + setup notes)
|
|
11
|
-
* (b)
|
|
12
|
-
*
|
|
11
|
+
* (b) shared instruction bodies embedded under a `## <name>` section marker;
|
|
12
|
+
* agent-scoped bodies are rendered into only their matching agent prompt
|
|
13
13
|
*
|
|
14
|
-
* into
|
|
15
|
-
* the source of truth
|
|
14
|
+
* into AGENTS.md plus selective agent prompt content. The instruction files
|
|
15
|
+
* remain the source of truth; AGENTS.md is a committed build artifact, never
|
|
16
16
|
* hand-edited.
|
|
17
17
|
*
|
|
18
18
|
* Usage:
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
* No runtime dependencies (Node >= 18, stdlib only). Idempotent: running it
|
|
23
23
|
* twice produces byte-identical output.
|
|
24
24
|
*/
|
|
25
|
-
import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'
|
|
26
|
-
import { dirname, join } from 'node:path'
|
|
25
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'
|
|
26
|
+
import { dirname, join, resolve } from 'node:path'
|
|
27
27
|
import { fileURLToPath } from 'node:url'
|
|
28
28
|
|
|
29
29
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
@@ -44,19 +44,19 @@ This project uses the Pantheon multi-agent framework with 14 specialized agents.
|
|
|
44
44
|
|
|
45
45
|
| Agent | Role |
|
|
46
46
|
|-------|------|
|
|
47
|
-
| @aphrodite | Frontend specialist — React 19, TypeScript strict, WCAG accessibility, responsive design, TDD, modern API patterns, deprecated npm detection.
|
|
47
|
+
| @aphrodite | Frontend specialist — React 19, TypeScript strict, WCAG accessibility, responsive design, TDD, modern API patterns, deprecated npm detection. Uses discovery/review proportionally to scope and risk. |
|
|
48
48
|
| @apollo | Read-only investigation scout — 3–10 parallel searches across codebase, external docs, and GitHub. Called by: athena, zeus, hermes, aphrodite, demeter. No edits, no commands. |
|
|
49
49
|
| @athena | Strategic planner & architect — research-first, plan-only, never implements. Plans include quality gates (ruff/Biome, dep detection, LTS policy). Calls apollo for discovery. |
|
|
50
|
-
| @demeter | Database specialist — SQLAlchemy 2.0, Alembic, query optimization, N+1 prevention, TDD migrations, modern DB libs.
|
|
50
|
+
| @demeter | Database specialist — SQLAlchemy 2.0, Alembic, query optimization, N+1 prevention, TDD migrations, modern DB libs. Preserves review gates for schema/data changes. |
|
|
51
51
|
| @gaia | Remote sensing domain specialist — satellite image processing, spectral analysis, SAR, change detection, time series, ML/DL classification. Read-only analysis of geospatial data. |
|
|
52
52
|
| @hephaestus | AI tooling & pipelines specialist — LangChain/LangGraph chains, RAG architecture, vector stores, embedding strategies. Forges AI infrastructure. Calls apollo, sends to themis. |
|
|
53
|
-
| @hermes | Backend specialist — FastAPI, Python, async, TDD (RED→GREEN→REFACTOR), modern Python stdlib, obsolete lib detection.
|
|
53
|
+
| @hermes | Backend specialist — FastAPI, Python, async, TDD (RED→GREEN→REFACTOR), modern Python stdlib, obsolete lib detection. Uses discovery/review proportionally to scope and risk. |
|
|
54
54
|
| @iris | GitHub operations specialist — branches, pull requests, issues, releases, tags. Called by zeus after review. Never pushes or merges without explicit human approval. Integrates with VS Code GitHub Pull Requests extension. |
|
|
55
55
|
| @mnemosyne | Memory bank quality owner — initializes .pantheon/memory-bank/, writes ADRs and task records on explicit request. Called by zeus. Never invoked automatically after phases. |
|
|
56
56
|
| @nyx | Observability & monitoring specialist — OpenTelemetry tracing, token/cost tracking, agent performance analytics, LangSmith integration. Calls apollo for discovery, sends to themis. |
|
|
57
57
|
| @prometheus | Infrastructure + model provider specialist — Docker, CI/CD, multi-model routing, cost optimization, provider abstraction |
|
|
58
58
|
| @talos | Hotfix express lane — direct fixes for small bugs, CSS, typos, minor logic. No TDD ceremony, no orchestration overhead. Standalone, no subagents. Escalates complex issues to zeus. |
|
|
59
|
-
| @themis | Quality & security gate — ruff/Biome linting, dead/legacy code detection, OWASP Top 10, coverage
|
|
59
|
+
| @themis | Quality & security gate — ruff/Biome linting, dead/legacy code detection, OWASP Top 10, applicable coverage requirements, correctness, deprecation audit. Reviews material/sensitive changes. |
|
|
60
60
|
| @zeus | Central orchestrator — never implements. Delegates to: athena, apollo, hermes, aphrodite, demeter, prometheus, themis, iris, mnemosyne, talos, hephaestus, nyx |
|
|
61
61
|
|
|
62
62
|
## OpenCode Setup
|
|
@@ -78,8 +78,8 @@ Para validar a instalação global do pacote pantheon-opencode COMO UM USUÁRIO
|
|
|
78
78
|
|
|
79
79
|
## Conventions
|
|
80
80
|
|
|
81
|
-
- TDD:
|
|
82
|
-
-
|
|
81
|
+
- TDD: RED→GREEN→REFACTOR for testable behavior; use focused checks for micro-edits
|
|
82
|
+
- Honor repository coverage thresholds when relevant; preserve stronger auth/security/data-integrity gates
|
|
83
83
|
- Async/await on all I/O
|
|
84
84
|
- Type hints on all functions
|
|
85
85
|
- PRs always update the README — every pull request must document newly added features, behaviors, env vars, or commands in the README before being opened.
|
|
@@ -92,20 +92,41 @@ Para validar a instalação global do pacote pantheon-opencode COMO UM USUÁRIO
|
|
|
92
92
|
/**
|
|
93
93
|
* Parse YAML-ish frontmatter from an instruction file.
|
|
94
94
|
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
95
|
+
* Preserve the file-scope `applyTo` glob separately from the explicit
|
|
96
|
+
* `agents` selectors. In particular, a Python workspace glob is never
|
|
97
|
+
* interpreted as an agent name. The frontmatter block is stripped from
|
|
98
|
+
* the embedded body.
|
|
97
99
|
*
|
|
98
100
|
* @param {string} content - Raw file content
|
|
99
|
-
* @returns {{ name: string, body: string
|
|
101
|
+
* @returns {{ name: string, body: string, applyTo: string | null,
|
|
102
|
+
* agents: string[], fallback: string | null, appliesToAgent: (name: string) => boolean } | null}
|
|
100
103
|
*/
|
|
101
|
-
function parseInstruction(content) {
|
|
104
|
+
export function parseInstruction(content) {
|
|
102
105
|
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/)
|
|
103
106
|
if (!match) return null
|
|
104
107
|
const fm = match[1]
|
|
105
108
|
const nameMatch = fm.match(/^name:\s*["']?([^"'\r\n]+)["']?\s*$/m)
|
|
106
109
|
if (!nameMatch) return null
|
|
110
|
+
const applyToMatch = fm.match(/^applyTo:\s*["']?([^"'\r\n]+)["']?\s*$/m)
|
|
111
|
+
const agentsMatch = fm.match(/^agents:\s*\[([^\]\r\n]*)\]\s*$/m)
|
|
112
|
+
const agents = agentsMatch
|
|
113
|
+
? agentsMatch[1]
|
|
114
|
+
.split(',')
|
|
115
|
+
.map((agent) => agent.trim().replace(/^(["'])(.*)\1$/, '$2'))
|
|
116
|
+
.filter(Boolean)
|
|
117
|
+
: fm.match(/^agents:/m)
|
|
118
|
+
? [] // Malformed explicit selector: fail closed; never make it global.
|
|
119
|
+
: applyToMatch
|
|
120
|
+
? [] // File-scoped instructions need an explicit agent association.
|
|
121
|
+
: ['*'] // Legacy instructions without selectors remain shared.
|
|
122
|
+
const fallbackMatch = fm.match(/^fallback:\s*["']?([^"'\r\n]+)["']?\s*$/m)
|
|
123
|
+
const appliesToAgent = (agent) => agents.includes('*') || agents.includes(agent)
|
|
107
124
|
return {
|
|
108
125
|
name: nameMatch[1].trim(),
|
|
126
|
+
applyTo: applyToMatch?.[1].trim() ?? null,
|
|
127
|
+
agents,
|
|
128
|
+
fallback: fallbackMatch?.[1].trim() ?? null,
|
|
129
|
+
appliesToAgent,
|
|
109
130
|
body: `${content.slice(match[0].length).trimEnd()}\n`,
|
|
110
131
|
}
|
|
111
132
|
}
|
|
@@ -114,7 +135,8 @@ function parseInstruction(content) {
|
|
|
114
135
|
* Read all src/instructions/*.instructions.md files, sorted by filename for
|
|
115
136
|
* deterministic output.
|
|
116
137
|
*
|
|
117
|
-
* @returns {Array<{ file: string, name: string, body: string
|
|
138
|
+
* @returns {Array<{ file: string, name: string, body: string, applyTo: string | null,
|
|
139
|
+
* agents: string[], fallback: string | null, appliesToAgent: (name: string) => boolean }>}
|
|
118
140
|
*/
|
|
119
141
|
export function readInstructions() {
|
|
120
142
|
if (!existsSync(INSTRUCTIONS_DIR)) return []
|
|
@@ -137,10 +159,13 @@ export function readInstructions() {
|
|
|
137
159
|
/**
|
|
138
160
|
* Generate the full AGENTS.md content.
|
|
139
161
|
*
|
|
140
|
-
* @param {Array<{ file: string, name: string, body: string }>} instructions
|
|
162
|
+
* @param {Array<{ file: string, name: string, body: string, agents?: string[] }>} instructions
|
|
141
163
|
* @returns {string}
|
|
142
164
|
*/
|
|
143
165
|
export function generateAgentsMd(instructions) {
|
|
166
|
+
const sharedInstructions = instructions.filter(
|
|
167
|
+
(instr) => !instr.agents || instr.agents.includes('*'),
|
|
168
|
+
)
|
|
144
169
|
const sections = [
|
|
145
170
|
'<!-- Generated by scripts/build-agents-md.mjs — do not edit directly. -->',
|
|
146
171
|
'<!-- Source of truth: src/instructions/*.instructions.md (AGENTS.md is a committed build artifact). -->',
|
|
@@ -153,10 +178,11 @@ export function generateAgentsMd(instructions) {
|
|
|
153
178
|
'',
|
|
154
179
|
'The following sections are consolidated from `src/instructions/*.instructions.md`',
|
|
155
180
|
'so both OpenCode V1 (auto-loads AGENTS.md) and V2 (loads AGENTS.md, ignores the',
|
|
156
|
-
'`instructions` config key) receive identical
|
|
181
|
+
'`instructions` config key) receive identical shared rules. Agent-scoped rules',
|
|
182
|
+
'are rendered into only the matching installed agent prompts.',
|
|
157
183
|
'',
|
|
158
184
|
]
|
|
159
|
-
for (const instr of
|
|
185
|
+
for (const instr of sharedInstructions) {
|
|
160
186
|
sections.push(
|
|
161
187
|
`<!-- Source: src/instructions/${instr.file} -->`,
|
|
162
188
|
`## ${instr.name}`,
|
|
@@ -168,6 +194,110 @@ export function generateAgentsMd(instructions) {
|
|
|
168
194
|
return `${sections.join('\n').trimEnd()}\n`
|
|
169
195
|
}
|
|
170
196
|
|
|
197
|
+
const GENERATED_AGENT_BLOCK =
|
|
198
|
+
/\n?<!-- Pantheon selective instructions: generated -->[\s\S]*?<!-- \/Pantheon selective instructions -->\n?/g
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Render the agent-specific instruction set into the supported agent prompt.
|
|
202
|
+
* The shared rules remain in AGENTS.md; file globs are retained as scope
|
|
203
|
+
* guidance and are never used as agent selectors.
|
|
204
|
+
*
|
|
205
|
+
* @param {string} agentName - Canonical agent name from the prompt filename
|
|
206
|
+
* @param {string} prompt - Canonical source agent prompt
|
|
207
|
+
* @param {Array<{ file: string, name: string, body: string, applyTo?: string | null,
|
|
208
|
+
* agents?: string[], fallback?: string | null }>} instructions
|
|
209
|
+
* @returns {string}
|
|
210
|
+
*/
|
|
211
|
+
export function generateAgentPrompt(agentName, prompt, instructions = readInstructions()) {
|
|
212
|
+
const basePrompt = prompt.replace(GENERATED_AGENT_BLOCK, '').trimEnd()
|
|
213
|
+
const selected = instructions.filter(
|
|
214
|
+
(instr) => instr.agents && !instr.agents.includes('*') && instr.agents.includes(agentName),
|
|
215
|
+
)
|
|
216
|
+
if (selected.length === 0) {
|
|
217
|
+
return [
|
|
218
|
+
basePrompt,
|
|
219
|
+
'',
|
|
220
|
+
'<!-- Pantheon selective instructions: generated -->',
|
|
221
|
+
'No agent-specific instructions are assigned; follow the shared rules in AGENTS.md.',
|
|
222
|
+
'<!-- /Pantheon selective instructions -->',
|
|
223
|
+
'',
|
|
224
|
+
].join('\n')
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const sections = selected.map((instr) => {
|
|
228
|
+
const scope = instr.applyTo
|
|
229
|
+
? `\n\n> Apply only when a target workspace file matches \`${instr.applyTo}\`.`
|
|
230
|
+
: ''
|
|
231
|
+
const fallback =
|
|
232
|
+
instr.fallback === 'shared'
|
|
233
|
+
? '\n\n> For work outside this scope, use the shared rules in AGENTS.md.'
|
|
234
|
+
: ''
|
|
235
|
+
return [
|
|
236
|
+
`<!-- Source: src/instructions/${instr.file} -->`,
|
|
237
|
+
`## ${instr.name}${scope}`,
|
|
238
|
+
'',
|
|
239
|
+
`${instr.body.trimEnd()}${fallback}`,
|
|
240
|
+
].join('\n')
|
|
241
|
+
})
|
|
242
|
+
return [
|
|
243
|
+
basePrompt,
|
|
244
|
+
'',
|
|
245
|
+
'<!-- Pantheon selective instructions: generated -->',
|
|
246
|
+
sections.join('\n\n'),
|
|
247
|
+
'<!-- /Pantheon selective instructions -->',
|
|
248
|
+
'',
|
|
249
|
+
].join('\n')
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Copy agent prompts with scoped instructions embedded in each actual prompt.
|
|
254
|
+
* Used by both init and postinstall sync so the installed runtime receives the
|
|
255
|
+
* same selection without a per-turn injection hook.
|
|
256
|
+
*
|
|
257
|
+
* @param {string} sourceDir - Canonical src/agents directory
|
|
258
|
+
* @param {string} targetDir - OpenCode agents directory
|
|
259
|
+
* @param {boolean} dryRun - Do not write when true
|
|
260
|
+
* @param {boolean} existingOnly - Refresh installed prompts without adding missing agents
|
|
261
|
+
* @returns {{ created: number, skipped: number }}
|
|
262
|
+
*/
|
|
263
|
+
export function copyAgentPrompts(sourceDir, targetDir, dryRun = false, existingOnly = false) {
|
|
264
|
+
const instructions = readInstructions()
|
|
265
|
+
if (!dryRun && !existingOnly) mkdirSync(targetDir, { recursive: true })
|
|
266
|
+
let created = 0
|
|
267
|
+
let skipped = 0
|
|
268
|
+
for (const file of readdirSync(sourceDir)
|
|
269
|
+
.filter((entry) => entry.endsWith('.md'))
|
|
270
|
+
.sort()) {
|
|
271
|
+
if (file.toLowerCase() === 'readme.md') continue
|
|
272
|
+
const sourcePath = join(sourceDir, file)
|
|
273
|
+
if (!statSync(sourcePath).isFile()) continue
|
|
274
|
+
const agentName = file.replace(/\.md$/, '')
|
|
275
|
+
const output = generateAgentPrompt(agentName, readFileSync(sourcePath, 'utf8'), instructions)
|
|
276
|
+
const targetPath = join(targetDir, file)
|
|
277
|
+
if (existingOnly && !existsSync(targetPath)) continue
|
|
278
|
+
const existing = existsSync(targetPath) ? readFileSync(targetPath, 'utf8') : null
|
|
279
|
+
if (existing === output) {
|
|
280
|
+
skipped++
|
|
281
|
+
} else {
|
|
282
|
+
if (!dryRun) writeFileSync(targetPath, output, 'utf8')
|
|
283
|
+
created++
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return { created, skipped }
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Count LF-delimited logical lines without assuming a trailing newline.
|
|
291
|
+
*
|
|
292
|
+
* @param {string} content - File content
|
|
293
|
+
* @returns {number}
|
|
294
|
+
*/
|
|
295
|
+
export function logicalLineCount(content) {
|
|
296
|
+
if (content.length === 0) return 0
|
|
297
|
+
const separators = content.match(/\n/g)?.length ?? 0
|
|
298
|
+
return separators + (content.endsWith('\n') ? 0 : 1)
|
|
299
|
+
}
|
|
300
|
+
|
|
171
301
|
// ---------------------------------------------------------------------------
|
|
172
302
|
// CLI entry point
|
|
173
303
|
// ---------------------------------------------------------------------------
|
|
@@ -175,6 +305,9 @@ export function generateAgentsMd(instructions) {
|
|
|
175
305
|
function main() {
|
|
176
306
|
const checkOnly = process.argv.includes('--check')
|
|
177
307
|
const instructions = readInstructions()
|
|
308
|
+
const sharedCount = instructions.filter(
|
|
309
|
+
(instr) => !instr.agents || instr.agents.includes('*'),
|
|
310
|
+
).length
|
|
178
311
|
const content = generateAgentsMd(instructions)
|
|
179
312
|
|
|
180
313
|
if (checkOnly) {
|
|
@@ -183,15 +316,15 @@ function main() {
|
|
|
183
316
|
console.error(`❌ AGENTS.md is stale — run: node scripts/build-agents-md.mjs`)
|
|
184
317
|
process.exit(1)
|
|
185
318
|
}
|
|
186
|
-
console.log(`✅ AGENTS.md is up to date (${
|
|
319
|
+
console.log(`✅ AGENTS.md is up to date (${sharedCount} shared instruction sections)`)
|
|
187
320
|
return
|
|
188
321
|
}
|
|
189
322
|
|
|
190
323
|
writeFileSync(AGENTS_MD_PATH, content, 'utf8')
|
|
191
|
-
const lines = content
|
|
192
|
-
console.log(
|
|
193
|
-
`✅ Generated AGENTS.md (${instructions.length} instruction sections, ${lines} lines)`,
|
|
194
|
-
)
|
|
324
|
+
const lines = logicalLineCount(content)
|
|
325
|
+
console.log(`✅ Generated AGENTS.md (${sharedCount} shared instruction sections, ${lines} lines)`)
|
|
195
326
|
}
|
|
196
327
|
|
|
197
|
-
|
|
328
|
+
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
329
|
+
main()
|
|
330
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* agents-md.mjs — Dynamic AGENTS.md generator from canonical agent frontmatter
|
|
4
4
|
*
|
|
5
|
-
* Reads all agents/*.
|
|
5
|
+
* Reads all canonical src/agents/*.md files, extracts name + description from frontmatter,
|
|
6
6
|
* and generates AGENTS.md content dynamically. Eliminates hardcoded agent tables
|
|
7
7
|
* in platform installers (claude.mjs, cursor.mjs, windsurf.mjs, cline.mjs, etc.).
|
|
8
8
|
*
|
|
@@ -64,7 +64,7 @@ function parseAgentFrontmatter(content) {
|
|
|
64
64
|
// ---------------------------------------------------------------------------
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
|
-
* Read all canonical agents/*.
|
|
67
|
+
* Read all canonical src/agents/*.md files, parse frontmatter,
|
|
68
68
|
* and return an array of agent metadata objects sorted alphabetically by name.
|
|
69
69
|
*
|
|
70
70
|
* Skips files that don't match the `*.agent.md` pattern, files without
|