pantheon-opencode 1.4.0 → 1.4.2

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
  <h1 align="center">Pantheon</h1>
3
3
 
4
4
  <p align="center">
5
- <a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-v1.3.6--beta-blue" alt="Version"></a>
5
+ <a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-v1.4.2-blue" alt="Version"></a>
6
6
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="License"></a>
7
7
  <a href="docs/agents/README.md"><img src="https://img.shields.io/badge/agents-14-purple" alt="Agents"></a>
8
8
  <a href="src/skills/README.md"><img src="https://img.shields.io/badge/skills-21-orange" alt="Skills"></a>
@@ -225,7 +225,7 @@ via three delegation tools, tracked on a persistent job board
225
225
 
226
226
  | Tool | Signature | Behavior |
227
227
  |------|-----------|----------|
228
- | `pantheon_delegate` | `{prompt, agent, description?, read_only?}` | Creates a child session (parentID = caller), registers it on the job board, arms a 15-minute timeout, and fire-and-forgets `promptAsync` on the child. Returns the readable alias (e.g. `apo-1`). Only root sessions may delegate (sub-sessions are rejected by the depth guard). |
228
+ | `pantheon_delegate` | `{prompt, agent, description?, read_only?, model?}` | Creates a child session (parentID = caller), registers it on the job board, arms a 15-minute timeout, and sends `promptAsync` to the child. `model` is optional and uses `provider/model-id`. Returns the readable alias (e.g. `apo-1`). Only root sessions may delegate (sub-sessions are rejected by the depth guard). |
229
229
  | `pantheon_delegation_read` | `{id}` | Blocks (`waitForTerminal`, up to 15 min) until the delegation reaches a terminal state, returns the report markdown, and marks the job reconciled. Resolves by alias or task ID. |
230
230
  | `pantheon_delegation_list` | `{}` | Lists the current session's delegations with `[unread]` on finished, unreconciled jobs. |
231
231
 
@@ -239,17 +239,16 @@ Fail-open: if the child session messages are unavailable (or empty), the read
239
239
  returns the report exactly as before — the activity sampling never breaks the
240
240
  delegation read.
241
241
 
242
- **Completion visibility — no chat injection.** User policy: ZERO delegation
243
- notifications in the chat transcript — no `<task-notification>` block is ever
244
- injected into a `chat.message` output (the old queue + flush channel was
245
- removed). When a job reaches a terminal state (completion observed via
246
- `session.idle`/`session.error` on the child, or the timeout finalize path), the
247
- plugin writes a file-only audit log line (echo opt-in via `PANTHEON_HOOKS_LOG`).
248
- Completion visibility lives in the legitimate channels: the board `[unread]`
249
- marker (`pantheon_delegation_list`), `pantheon_delegation_read`, TUI toasts
250
- (pantheon-hooks, `PANTHEON_TOASTS` gate) and compaction carry-forward. Reconcile
251
- is an acknowledgment, not a completion — it never re-fires the terminal
252
- transition.
242
+ **Completion visibility — zero chat noise.** Delegation notifications are never
243
+ injected into the chat transcript: neither `chat.message` nor any other chat
244
+ hook or transcript marker is used as a delivery channel. When a job reaches a
245
+ terminal state (completion observed via `session.idle`/`session.error` on the
246
+ child, or the timeout finalize path), the plugin writes a file-only audit log
247
+ line (echo opt-in via `PANTHEON_HOOKS_LOG`). Completion visibility lives in the
248
+ legitimate channels: the board `[unread]` marker
249
+ (`pantheon_delegation_list`), `pantheon_delegation_read`, TUI toasts
250
+ (`PANTHEON_TOASTS` gate), and compaction carry-forward. Reconcile is an
251
+ acknowledgment, not a completion — it never re-fires the terminal transition.
253
252
 
254
253
  **Timeout:** `background_delegation.timeout_ms` (default `900000` = 15 min). A job
255
254
  that has not reached a terminal state is finalized as `error`/`timedOut`.
@@ -278,6 +277,22 @@ agent in `background_delegation.read_only_agents` (`apollo`, `gaia`), registers
278
277
  the child session as read-only — the `tool.execute.before` guard denies
279
278
  `edit`/`write`/`bash`/`task` inside that session.
280
279
 
280
+ **Delegated model resolution:** the optional child model is resolved in this
281
+ order: (1) explicit `model` on `pantheon_delegate`; (2) the target agent's
282
+ model in the active preset; (3) the current model of the parent session; (4)
283
+ no model, allowing OpenCode's native inheritance. `small_model` is never used
284
+ for delegates. When a model resolves, the same `provider/model-id` is sent as
285
+ `{providerID, id}` to both `session.create` and `promptAsync`, including the
286
+ single safe bootstrap retry; the retry does not select a different model. If
287
+ the resolution lookup yields no model, the model field is omitted and the
288
+ delegation continues with native inheritance.
289
+
290
+ Model availability is not inferred from the string. The provider must exist in
291
+ OpenCode and the referenced model must be available through that provider's
292
+ account, subscription, or configured endpoint; otherwise the child host may
293
+ reject startup. An active preset supplies provider configuration and model
294
+ mappings, but does not make an unavailable provider or model available.
295
+
281
296
  **R1 — Per-error-type retry + provider cooldown (LiteLLM pattern):**
282
297
  `retry_policy` in `src/routing.yml` maps an error class (`auth`, `rate_limit`,
283
298
  `timeout`, `other`) to max retries before escalating — `auth` is never retried
@@ -338,10 +353,9 @@ logged warn and pass-through.
338
353
 
339
354
  **Post-compaction state re-assertion (1.3.4):** on `session.compacted`, fresh
340
355
  state — running/unread delegations from the board + active goals, capped at 10
341
- lines — is re-injected as a `<system-reminder>` into the session's next
342
- message via the shared chat-reminder buffer (`chat-reminders.ts`, the same P0
343
- messageID guard that protects subagent fires). A session with nothing to
344
- assert is a silent skip.
356
+ lines — remains available through compaction carry-forward and the board
357
+ (`pantheon_delegation_list` / `pantheon_delegation_read`). A session with
358
+ nothing to assert is a silent skip; no chat transcript injection is performed.
345
359
 
346
360
  **Preemptive compaction check (1.3.4):** a pure threshold core
347
361
  (`preemptive-compact.ts`) warns the model before the context fills: at 78%
@@ -350,36 +364,22 @@ dormant / ready-to-wire — opencode 1.18.x exposes no runtime context-usage
350
364
  percentage, so nothing observes it yet; when a source appears, the caller
351
365
  wires it in (the enqueue callback is injected).
352
366
 
353
- **Model API-key validation (1.3.4):** `pantheon_delegate` gates the resolved
354
- child model's provider before dispatching (single source of truth:
355
- `routing.yml` preset definitions' `apiKeyEnv` — the same check `applyPreset`
356
- enforces at startup). If an **auto-resolved** model (`options.agentModels` or
357
- the active preset) points to a provider that requires an API key
358
- (`apiKeyEnv`) and the env var is unset, the delegate falls back to
359
- `opencode-go/deepseek-v4-flash` (validated the same way). If the fallback is
360
- also unusable, the tool returns a clear error **text** (never throws) naming
361
- the missing env var — and registers **no job** on the board. An **explicit**
362
- `model` passed by the caller is always respected (warned, not overridden).
363
- Setting `PANTHEON_MODEL_PRESET` to a preset whose providers have keys, or
364
- filling the required `PANTHEON_*_API_KEY` env var for the preset's provider,
365
- resolves the fallback path. If nothing resolves at all (no model, no preset),
366
- the child keeps using opencode's default model (warned).
367
-
368
- **agentModels wiring (1.3.4):** the delegate now also resolves the child model
369
- via `routing.yml` — `loadRoutingAgentModels` extracts the per-agent models of
370
- the FIRST-listed preset (the static default, `go-deepseek` today) and passes
371
- them as `options.agentModels`, branch (b) of the resolve precedence: explicit
372
- `model` > `options.agentModels` > active preset > opencode default. Delegation
373
- no longer depends exclusively on the active preset — a delegated child gets a
374
- sane per-agent model even when no preset is active. Fail-open: a missing or
375
- unparseable routing.yml yields `{}` (previous behavior, warned).
367
+ **Model selection (1.4.1):** the child session inherits the parent session's
368
+ model through OpenCode. A model override is supplied only when the active
369
+ routing profile defines one; no model API-key validation is performed here.
370
+
371
+ **agentModels wiring (1.3.4):** `loadRoutingAgentModels` extracts only the
372
+ per-agent models from the explicitly active routing profile and passes them as
373
+ `options.agentModels`. No active profile, missing profile entry, or profile
374
+ without `model` produces an empty map; there is no implicit first-preset or
375
+ DeepSeek fallback. A missing or unparseable `routing.yml` is fail-open and
376
+ omits the child model.
376
377
 
377
378
  **Delegation log hygiene (1.3.4):** `delegations.log` now records the real
378
379
  `task_id` (omitted when empty, never `""`) and a **numeric** `duration_ms`
379
- (null when unset) so downstream aggregation works. The idle-flush log entry is
380
- deduplicated: the flush logs a summary (count + aggregated line count) and the
381
- reminder content is logged exactly once, at `chat.message` delivery — no more
382
- duplicate lines for the same notification.
380
+ (null when unset) so downstream aggregation works. Terminal events are
381
+ file-only audit entries; completion is surfaced by TUI toast (when enabled),
382
+ the board, and the list/read tools — never by chat delivery.
383
383
 
384
384
  **Env vars & config:**
385
385
 
@@ -657,112 +657,211 @@ on demand to perform specialized tasks. Skills are organized into domains:
657
657
  ## Model Tiers & Presets
658
658
 
659
659
  Pantheon agents declare abstract model tiers (`fast` / `default` / `coding` / `premium`) rather than
660
- hardcoded model names. The actual model resolved for each tier depends on your platform
661
- subscription (OpenCode Go, Copilot Pro, Claude Pro, etc.).
660
+ hardcoded model names. The actual model resolved for each tier depends on your chosen **preset**
661
+ and is pinned to concrete `provider/model` IDs in [src/routing.yml](src/routing.yml).
662
662
 
663
- | Tier | Purpose | Agents | Typical Models |
663
+ | Tier | Purpose | Agents | Typical Models (2026) |
664
664
  |------|---------|--------|----------------|
665
- | `premium` | Deep reasoning, critical | Zeus, Athena, Themis | DeepSeek V4 Pro, Claude Opus, o3 |
666
- | `default` | Balanced quality/speed | Hermes, Aphrodite, Demeter, Prometheus, Hephaestus, Gaia | Kimi K2.6, Claude Sonnet, GPT-4o |
667
- | `coding` | Heavy coding tasks | Hermes, Aphrodite, Demeter, Prometheus, Hephaestus, Talos | DeepSeek V4 Flash, Claude Sonnet |
668
- | `fast` | Quick, cheap ops | Apollo, Iris, Mnemosyne, Talos, Nyx | DeepSeek V4 Flash, MiniMax M2.7, Gemini Flash |
665
+ | `premium` | Deep reasoning, critical | Zeus, Athena, Themis | gpt-5.6-sol, qwen3.8-max, deepseek-v4-pro |
666
+ | `default` | Balanced quality/speed | Hermes, Aphrodite, Demeter, Prometheus, Hephaestus, Gaia | gpt-5.6-terra, kimi-k3, deepseek-v4-flash |
667
+ | `coding` | Heavy coding tasks | Hermes, Aphrodite, Demeter, Prometheus, Hephaestus, Talos | gpt-5.6-terra, deepseek-v4-flash, mimo-v2.5 |
668
+ | `fast` | Quick, cheap ops | Apollo, Iris, Mnemosyne, Talos, Nyx | gpt-5.6-luna-fast, mimo-v2.5-free, gpt-5.6-luna |
669
669
 
670
670
  ---
671
671
 
672
672
  ## Model Routing Presets
673
673
 
674
- The abstract tiers above are pinned to concrete `provider/model` IDs by **6 built-in model presets**. Each preset maps all 14 agents to a specific model plus a reasoning effort per role (planners/reviewers, implementers, scouts). **Zero-mutation default**: without an active preset, agents run on OpenCode's default model — behavior is unchanged.
674
+ The abstract tiers above are pinned to concrete `provider/model` IDs by **4 built-in model presets**.
675
+ Cada preset mapeia os 14 agentes para um modelo específico + `reasoning_effort` por papel (planners/reviewers, implementers, scouts).
676
+
677
+ > **Default = herdar do chat (sem `active-preset.json`)** — sem preset ativo, os delegates **herdam nativamente** o modelo do chat pai ([herança nativa](src/pantheon/delegation.ts)). O instalador **não grava** `active-preset.json` quando você escolhe `0`/`inherit` no wizard (ou não seleciona preset via `--preset`). A resolução do modelo delegado segue: `explicit model` em `pantheon_delegate` > modelo do agente-alvo no preset ativo > modelo atual da sessão pai > herança nativa (sem `model`, sem `small_model`). `small_model` nunca é usado para delegates.
678
+
679
+ Tabelas abaixo são **geradas a partir de [src/routing.yml](src/routing.yml)** — rode `node scripts/generate-preset-docs.mjs` para regenerar. Nenhum segredo é hardcoded: apenas nomes de env vars (`PANTHEON_OPENCODE_API_KEY`, `OPENAI_API_KEY`) e `baseURL`s.
680
+
681
+ <!-- Generated from src/routing.yml — run: node scripts/generate-preset-docs.mjs -->
682
+ ### Presets — resumo (provider / baseURL / key / pricing / vision)
683
+
684
+ | Preset | Provider / BaseURL | Key env (nome) | Pricing 2026 | Vision (fallback) | Papéis / Modelos |
685
+ |---|---|---|---|---|---|
686
+ | `go-free` | `opencode` `https://opencode.ai/zen/v1` (env: `PANTHEON_OPENCODE_API_KEY`) | `PANTHEON_OPENCODE_API_KEY` | Gratuito — Zen free, sem custo, quota limitada, só modelos `-free` | `opencode/mimo-v2.5-free` [low] 👁️ vision | zeus: `opencode/big-pickle` [medium]<br>athena: `opencode/nemotron-3-super-free` [high]<br>themis: `opencode/qwen3.6-plus-free` [high]<br>hermes,aphrodite,demeter,prometheus,hephaestus: `opencode/deepseek-v4-flash-free` [medium]<br>apollo,nyx,gaia,iris,mnemosyne,talos: `opencode/mimo-v2.5-free` [low] |
687
+ | `go-fast` | `opencode-go` `https://opencode.ai/zen/go/v1` (env: `PANTHEON_OPENCODE_API_KEY`) | `PANTHEON_OPENCODE_API_KEY` | Baixo custo — Go gateway, baixa latência (kimi-k2.7-code / glm-5.3-flash) | `opencode-go/mimo-v2.5` [low] 👁️ vision | athena: `opencode-go/kimi-k2.7-code` [high]<br>themis: `opencode-go/glm-5.3-flash` [high]<br>zeus: `opencode-go/kimi-k2.7-code` [medium]<br>hermes,prometheus: `opencode-go/deepseek-v4-flash` [medium]<br>aphrodite,hephaestus: `opencode-go/mimo-v2.5` [low]<br>demeter: `opencode-go/gpt-5.6-luna` [low]<br>apollo,nyx,gaia,iris,mnemosyne,talos: `opencode-go/gpt-5.6-luna-fast` [low] |
688
+ | `go-premium` | `opencode-go` `https://opencode.ai/zen/go/v1` (env: `PANTHEON_OPENCODE_API_KEY`) | `PANTHEON_OPENCODE_API_KEY` | Premium — Go gateway, melhor qualidade (gpt-5.6-sol / qwen3.8-max / deepseek-v4-pro) | `opencode-go/gpt-5.6-sol` [high] 👁️ vision | zeus: `opencode-go/gpt-5.6-sol` [medium]<br>athena: `opencode-go/deepseek-v4-pro` [high]<br>themis: `opencode-go/qwen3.8-max` [high]<br>hermes,demeter,hephaestus: `opencode-go/gpt-5.6-terra` [medium]<br>aphrodite,prometheus: `opencode-go/kimi-k3` [medium]<br>apollo,nyx,gaia,iris,mnemosyne,talos: `opencode-go/gpt-5.6-luna` [low] |
689
+ | `openai` | `openai` `https://api.openai.com/v1` (env: `OPENAI_API_KEY`) | `OPENAI_API_KEY` | Pago (OpenAI) — Direto OpenAI, `gpt-5.6` family | `openai/gpt-5.6-sol` [high] 👁️ vision | athena,themis,zeus: `openai/gpt-5.6-sol` [high]<br>hermes,aphrodite,demeter,prometheus,hephaestus: `openai/gpt-5.6-luna` [high]<br>apollo,nyx,gaia,iris,mnemosyne,talos: `openai/gpt-5.6-luna-fast` [low] |
690
+
691
+ > **Pricing 2026 verificado** via `scripts/install/model-picker.mjs` (`PRESET_PRICE`) e `routing.yml` descrições. `go-free` = $0 (Zen free, quota limitada, só `-free`); `go-*` usam `PANTHEON_OPENCODE_API_KEY` (alias `OPENCODE_GO_API_KEY` aceito) no gateway `https://opencode.ai/zen/go/v1`; `openai` usa `OPENAI_API_KEY` em `https://api.openai.com/v1`. Custos reais dependem de conta/assinatura.
692
+
693
+ ### 14 agentes × 4 presets — modelo + effort + vision
675
694
 
676
- ### Presets
695
+ | Agente | `go-free` | `go-fast` | `go-premium` | `openai` |
696
+ |---|---|---|---|---|
697
+ | `zeus` | `opencode/big-pickle` [medium] · | `opencode-go/kimi-k2.7-code` [medium] · | `opencode-go/gpt-5.6-sol` [medium] 👁️ | `openai/gpt-5.6-sol` [high] 👁️ |
698
+ | `athena` | `opencode/nemotron-3-super-free` [high] · | `opencode-go/kimi-k2.7-code` [high] · | `opencode-go/deepseek-v4-pro` [high] · | `openai/gpt-5.6-sol` [high] 👁️ |
699
+ | `themis` | `opencode/qwen3.6-plus-free` [high] · | `opencode-go/glm-5.3-flash` [high] · | `opencode-go/qwen3.8-max` [high] · | `openai/gpt-5.6-sol` [high] 👁️ |
700
+ | `hermes` | `opencode/deepseek-v4-flash-free` [medium] · | `opencode-go/deepseek-v4-flash` [medium] · | `opencode-go/gpt-5.6-terra` [medium] 👁️ | `openai/gpt-5.6-luna` [high] 👁️ |
701
+ | `aphrodite` | `opencode/deepseek-v4-flash-free` [medium] · | `opencode-go/mimo-v2.5` [low] 👁️ | `opencode-go/kimi-k3` [medium] · | `openai/gpt-5.6-luna` [high] 👁️ |
702
+ | `demeter` | `opencode/deepseek-v4-flash-free` [medium] · | `opencode-go/gpt-5.6-luna` [low] 👁️ | `opencode-go/gpt-5.6-terra` [medium] 👁️ | `openai/gpt-5.6-luna` [high] 👁️ |
703
+ | `prometheus` | `opencode/deepseek-v4-flash-free` [medium] · | `opencode-go/deepseek-v4-flash` [medium] · | `opencode-go/kimi-k3` [medium] · | `openai/gpt-5.6-luna` [high] 👁️ |
704
+ | `hephaestus` | `opencode/deepseek-v4-flash-free` [medium] · | `opencode-go/mimo-v2.5` [low] 👁️ | `opencode-go/gpt-5.6-terra` [medium] 👁️ | `openai/gpt-5.6-luna` [high] 👁️ |
705
+ | `apollo` | `opencode/mimo-v2.5-free` [low] 👁️ | `opencode-go/gpt-5.6-luna-fast` [low] 👁️ | `opencode-go/gpt-5.6-luna` [low] 👁️ | `openai/gpt-5.6-luna-fast` [low] 👁️ |
706
+ | `nyx` | `opencode/mimo-v2.5-free` [low] 👁️ | `opencode-go/gpt-5.6-luna-fast` [low] 👁️ | `opencode-go/gpt-5.6-luna` [low] 👁️ | `openai/gpt-5.6-luna-fast` [low] 👁️ |
707
+ | `gaia` | `opencode/mimo-v2.5-free` [low] 👁️ | `opencode-go/gpt-5.6-luna-fast` [low] 👁️ | `opencode-go/gpt-5.6-luna` [low] 👁️ | `openai/gpt-5.6-luna-fast` [low] 👁️ |
708
+ | `iris` | `opencode/mimo-v2.5-free` [low] 👁️ | `opencode-go/gpt-5.6-luna-fast` [low] 👁️ | `opencode-go/gpt-5.6-luna` [low] 👁️ | `openai/gpt-5.6-luna-fast` [low] 👁️ |
709
+ | `mnemosyne` | `opencode/mimo-v2.5-free` [low] 👁️ | `opencode-go/gpt-5.6-luna-fast` [low] 👁️ | `opencode-go/gpt-5.6-luna` [low] 👁️ | `openai/gpt-5.6-luna-fast` [low] 👁️ |
710
+ | `talos` | `opencode/mimo-v2.5-free` [low] 👁️ | `opencode-go/gpt-5.6-luna-fast` [low] 👁️ | `opencode-go/gpt-5.6-luna` [low] 👁️ | `openai/gpt-5.6-luna-fast` [low] 👁️ |
677
711
 
678
- | Preset | Provider | Planners/Reviewers | Implementers | Scouts |
679
- |--------|----------|--------------------|--------------|--------|
680
- | `go-deepseek` | opencode (Zen) | `opencode/deepseek-v4-pro` | `opencode/deepseek-v4-flash` | `opencode/deepseek-v4-flash-free` |
681
- | `go-fast` | opencode-go | `opencode-go/deepseek-v4-flash` — all 14 agents, effort `low` | | |
682
- | `go-claude` | anthropic | `anthropic/claude-opus-4-8` | `anthropic/claude-sonnet-5` | `anthropic/claude-haiku-4-5` |
683
- | `go-openai` | openai | `openai/gpt-5.6-sol` | `openai/gpt-5.6-terra` | `openai/gpt-5.6-luna-fast` |
684
- | `go-premium` | opencode-go | GLM-5.1 (zeus), DeepSeek V4 Pro (athena), Qwen3.7 Max (themis) | MiniMax M2.7 (hermes, hephaestus), Kimi K2.6 (aphrodite), Qwen3.7 Plus (demeter), GLM-5.2 (prometheus) | DeepSeek V4 Flash (scouts) |
685
- | `go-free` | opencode (Zen free, $0) | Big Pickle (zeus), Nemotron 3 Ultra Free (athena) | DeepSeek V4 Flash Free | North Mini Code Free (scouts) |
712
+ `·` = text-only, `👁️` = vision (image-input) per `CAPABILITY_TABLE` em [src/pantheon/presets.mjs](src/pantheon/presets.mjs) — ex.: `mimo-v2.5`/`mimo-v2.5-free` e `gpt-5.6-*` são multimodais; `deepseek-v4-pro/flash`, `kimi-k2.7-code`, `glm-5.3-flash`, `qwen3.6-plus-free`, `big-pickle`, `nemotron-3-super-free` são text-only.
686
713
 
687
- The exact per-agent mapping (model + reasoning effort + fallbacks) lives in the `presets:` block of [src/routing.yml](src/routing.yml).
714
+ O mapeamento exato por agente (modelo + `reasoning_effort` + `vision` fallback) vive no bloco `presets:` de [src/routing.yml](src/routing.yml) e é validado por `validatePresetDefs` + `capabilityEntry` / `hasVision`.
688
715
 
689
716
  ### Requirements
690
717
 
691
- - **Env vars** — checked fail-fast (CLI and plugin) when the selected preset uses the provider:
692
- - `PANTHEON_OPENCODE_API_KEY` — `opencode` + `opencode-go` providers (`go-deepseek`, `go-fast`, `go-premium`, `go-free`)
693
- - `PANTHEON_ANTHROPIC_API_KEY` — `anthropic` provider (`go-claude`)
694
- - `PANTHEON_OPENAI_API_KEY` — `openai` provider (`go-openai`)
695
- - **OpenCode Go subscription** required for `go-fast` / `go-premium`.
696
- - **OpenCode Zen free tier** for `go-free` — note `nemotron-3-ultra-free` has known intermittent failures ([opencode#38028](https://github.com/opencode/opencode/issues/38028)); fall back to `go-fast` if flaky.
718
+ - **Env vars** — checadas fail-fast (CLI e plugin) quando o preset usa o provider (sem hardcodar valores):
719
+ - `PANTHEON_OPENCODE_API_KEY` — `opencode` + `opencode-go` (`go-free`, `go-fast`, `go-premium`) — alias `OPENCODE_GO_API_KEY` também aceito (wizard Q2)
720
+ - `OPENAI_API_KEY` — `openai` provider (`openai` puro)
721
+ - **OpenCode Go subscription** para `go-fast` / `go-premium` (gateway `https://opencode.ai/zen/go/v1`).
722
+ - **OpenCode Zen free tier** para `go-free` (`https://opencode.ai/zen/v1`, só modelos `-free`, quota limitada).
723
+ - **Sem preset (default)**: zero-mutação — nenhum `.pantheon/active-preset.json` gravado, herança nativa do chat pai.
697
724
 
698
- ### Commands
725
+ ### Wizard — instalação interativa (3 perguntas)
699
726
 
700
- ```bash
701
- # Install + activate a preset
702
- npx pantheon-opencode init --preset go-fast
727
+ Durante `npx pantheon-opencode init` (TTY, sem `--preset`/`--headless`/`-y`):
703
728
 
704
- # Switch preset (global config; --project for project-local; --dry-run to preview)
705
- pantheon-opencode set-tier go-deepseek
706
- pantheon-opencode set-tier go-fast --project
707
- pantheon-opencode set-tier go-fast --dry-run
729
+ 1. **Perfil (Q1)** — `0` = herdar do chat (**default**, não grava `active-preset.json`) ou `go-free`/`go-fast`/`go-premium`/`openai` — tabela exibida: perfil | `provider`/`baseURL`/key env | preço 2026 | modelos por papel (planners high, implementers medium/low, scouts low). `askQuestions` quando disponível, fallback `readline` TTY.
730
+ 2. **API Key (Q2)** — coleta **mascarada** (exibe `abcd****12`), valida `PANTHEON_OPENCODE_API_KEY` (aceita alias `OPENCODE_GO_API_KEY`) para `go-*` e `OPENAI_API_KEY` para `openai`, **não escreve `.env`** — só seta `env` da sessão e loga `maskKey`. Se já configurada no ambiente, apenas loga mascarada e segue.
731
+ 3. **Escopo (Q3)** — `project` (`./.pantheon/active-preset.json`, seguro, default) ou `global` (`~/.config/opencode/.pantheon/active-preset.json`). Gravação **atômica** (`tmp`+`rename`) com backup `.bak` + health-check (lê JSON e valida `preset`).
708
732
 
709
- # Clear preset — back to the zero-mutation default
710
- pantheon-opencode set-tier none
733
+ Headless / CI: use `npx pantheon-opencode init --headless` ou `--preset <name>` (pula wizard). Veja [docs/INSTALLATION.md](docs/INSTALLATION.md) para `headless` + troubleshooting de chaves.
711
734
 
712
- # No name → lists available presets (none, go-deepseek, go-fast, go-claude, go-openai, go-premium, go-free)
713
- pantheon-opencode set-tier
735
+ ### Comandos
736
+
737
+ ```bash
738
+ # Instalação interativa (wizard 3 perguntas — Q1 default = herdar do chat)
739
+ npx pantheon-opencode init
740
+ npx pantheon-opencode init --project # escopo project-local
741
+ npx pantheon-opencode init --preset go-fast # pula wizard, ativa direto
742
+
743
+ # Alternar preset depois (global por padrão; --project para projeto; --dry-run para preview)
744
+ npx pantheon-opencode set-tier go-free
745
+ npx pantheon-opencode set-tier go-premium --project
746
+ npx pantheon-opencode set-tier openai --dry-run
747
+
748
+ # Limpar preset — volta ao default (herança nativa)
749
+ npx pantheon-opencode set-tier none
750
+
751
+ # Sem nome → lista presets (none, go-free, go-fast, go-premium, openai)
752
+ npx pantheon-opencode set-tier
753
+
754
+ # Per-agent customization (novo — sem top-level model/small_model)
755
+ # Lista 14 agentes com modelo/effort/origem (preset|override|env|none), sem segredos
756
+ /pantheon-model status # alias: show
757
+ /pantheon-model # sem args → wizard interativo (agente → modelo → effort → scope via askQuestions)
758
+ /pantheon-model set --agent hermes --model opencode-go/gpt-5.6-terra --effort medium --scope project
759
+ /pantheon-model set --agent apollo --model opencode/mimo-v2.5-free --effort low
760
+ /pantheon-model reset --agent hermes --scope project
714
761
  ```
715
762
 
716
- **Env override (CI/headless)** — wins over the file:
763
+ **Env override (CI/headless)** — vence o arquivo:
717
764
 
718
765
  ```bash
719
- export PANTHEON_MODEL_PRESET=go-deepseek
766
+ export PANTHEON_MODEL_PRESET=go-fast # ou go-free / go-premium / openai / none
767
+ export PANTHEON_OPENCODE_API_KEY=... # para go-* (ou OPENCODE_GO_API_KEY como alias)
768
+ export OPENAI_API_KEY=... # para openai puro
720
769
  ```
721
770
 
722
771
  ### How it works
723
772
 
724
- - The active selection is persisted to `.pantheon/active-preset.json` — `{version, preset, source, updated_at}` — written atomically (tmp file + rename) with a `.bak` backup of the previous file. It applies on the next OpenCode startup (no hot-swap); the plugin's `hooks.config` injects it.
725
- - **Resolution precedence**: `PANTHEON_MODEL_PRESET` env → first existing `.pantheon/active-preset.json` (project → `~/.config/opencode` → `~/.opencode`) → **none** (defaults).
726
- - **Partial semantics**: a preset overrides only the agents it lists; unlisted agents inherit the invoking primary agent's model.
727
- - Interactive picker during `init`: one prompt listing the 6 presets (select by number or name, blank to skip). It never touches your `opencode.json` — the choice is injected at startup instead. The file format also supports an optional `overrides` block (per-agent `model`/`variant`, per-provider `baseURL`/`apiKeyEnv`) merged over the preset definition.
728
- - **Capability normalization**: requested reasoning effort is clamped to each model family's ceiling (`deepseek-v4-flash` max `medium`; claude models strip the variant entirely — Anthropic uses thinking).
729
- - **fallback_models**: per-agent ordered fallback list where configured (e.g. `go-deepseek` sets `[opencode/mimo-v2.5]` for every agent).
773
+ - A seleção ativa é persistida (se não for `inherit`) em `.pantheon/active-preset.json` — `{version, preset, source, updated_at, overrides?}` — escrita atômica (`tmp`+`rename`) com backup `.bak`. Só aplica no próximo startup do OpenCode (sem hot-swap); o plugin em `hooks.config` injeta `provider`/`baseURL`/`apiKeyEnv`.
774
+ - **Precedência**: `PANTHEON_MODEL_PRESET` env → primeiro `.pantheon/active-preset.json` existente (project → `~/.config/opencode` → `~/.opencode`) → **none = herança nativa** (sem `active-preset.json`).
775
+ - **Herança nativa de delegates** (1.4.2): `src/pantheon/delegation.ts` resolve o modelo do filho em: `explicit model` em `pantheon_delegate` > `overrides.agents[agent].model` em `active-preset.json` > `loadRoutingAgentModels` (preset ativo) > omitir → OpenCode herda o modelo do chat pai. `small_model` nunca é enviado. Validação `provider/model-id` com `MODEL_REF_PATTERN`.
776
+ - **Partial & overrides**: um preset sobrescreve só os agentes listados; agentes não listados herdam do pai. O bloco `overrides.agents[agent]` (via `/pantheon-model set --agent`) tem merge sobre o preset, validado via `capabilityEntry` e `normalizeCapability` (clamp ao teto do modelo) + aviso `hasVision` para modelos text-only; `overrides.providers` permite `baseURL`/`apiKeyEnv` custom. Escrita atômica com lock por path + `.bak`.
777
+ - **Capability normalization**: `requested effort` é clamped ao teto da família em `CAPABILITY_TABLE` (`deepseek-v4-flash/-free` max `medium`; `gop-5.6-luna*`/`mimo-v2.5*` max `low`; `claude` strip; `qwen3.6-plus-free`/`big-pickle` etc. text-only).
778
+ - **Interactive picker / wizard**: `scripts/install/model-picker.mjs` exporta `buildPresetTableRow`, `requiredKeyEnvForPreset`, `isKeyConfiguredForPreset`, `maskKey`, `buildInitQuestions`, `runInitWizard` e `runModelPicker`. Nunca toca `opencode.json`; também expõe helper `maskKey` para logs.
730
779
 
731
780
  ### Quick smoke test
732
781
 
733
782
  ```bash
783
+ # 1) default (herança nativa) — sem preset
784
+ npx pantheon-opencode init --headless # escolha 0 no wizard interativo = inherit
785
+ opencode run "hello" 2>&1 | grep "Pantheon"
786
+ # sem log de preset → herança nativa
787
+
788
+ # 2) com preset
734
789
  export PANTHEON_OPENCODE_API_KEY=...
735
- pantheon-opencode set-tier go-fast --project
790
+ npx pantheon-opencode set-tier go-fast --project
736
791
  opencode run "hello" 2>&1 | grep "Pantheon"
737
792
  # expect: [Pantheon Plugin] Model preset active: go-fast (source: file)
793
+
794
+ # 3) override per-agent
795
+ # no chat OpenCode:
796
+ /pantheon-model status
797
+ /pantheon-model set --agent hermes --model openai/gpt-5.6-luna --effort high --scope project
798
+ # persiste em .pantheon/active-preset.json overrides.agents.hermes
738
799
  ```
739
800
 
801
+
740
802
  ---
741
803
 
742
804
  ## Quick Start
743
805
 
744
806
  ### 1. Install Pantheon
745
807
 
746
- Pantheon runs on **OpenCode**. Install it globally:
808
+ Pantheon runs on **OpenCode**. Instalação global com **wizard 3 perguntas** (default = herdar do chat):
747
809
 
748
810
  ```bash
749
811
  npx pantheon-opencode init
812
+ # Q1: perfil — 0=herdar do chat [default] (sem active-preset.json), ou go-free / go-fast / go-premium / openai
813
+ # tabela exibida: perfil | provider/baseURL/key | preço 2026 | modelos por papel
814
+ # Q2: API key — coleta mascarada (PANTHEON_OPENCODE_API_KEY alias OPENCODE_GO_API_KEY, ou OPENAI_API_KEY), não escreve .env
815
+ # Q3: escopo — project (./.pantheon/active-preset.json, default) ou global (~/.config/opencode/.pantheon/active-preset.json)
816
+ # gravação atômica tmp+rename com .bak + health-check
817
+ ```
818
+
819
+ Atalhos:
820
+
821
+ ```bash
822
+ npx pantheon-opencode init --preset go-fast --headless # pula wizard
823
+ npx pantheon-opencode init --project # escopo project-local
824
+ npx pantheon-opencode init --headless --no-mcp # minimal sem Python
750
825
  ```
751
826
 
752
- For MCP servers (memory, persistence):
827
+ MCP servers (memory, persistence) — opcional via:
753
828
 
754
829
  ```bash
755
830
  npm run setup
756
831
  ```
757
832
 
833
+ Ou já incluído no wizard se escolher instalação completa.
834
+
758
835
  ### 2. Launch OpenCode
759
836
 
760
837
  ```bash
761
838
  export OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true
762
839
  opencode
840
+ # ou
841
+ npm run start
763
842
  ```
764
843
 
765
- ### 3. Run your first feature
844
+ Dica: após instalar preset, `opencode run "hello" 2>&1 | grep "Pantheon"` deve mostrar `[Pantheon Plugin] Model preset active: <preset> (source: file)`; sem preset, fica em herança nativa (sem log de preset).
845
+
846
+ ### 3. Customize per-agent (opcional)
847
+
848
+ No chat OpenCode:
849
+
850
+ ```
851
+ # lista 14 agentes com modelo/effort/origem
852
+ /pantheon-model status
853
+
854
+ # wizard interativo (agente → modelo → effort → scope)
855
+ /pantheon-model
856
+
857
+ # override explícito por agente (validado via CAPABILITY_TABLE, clamp, hasVision)
858
+ /pantheon-model set --agent hermes --model opencode-go/gpt-5.6-terra --effort medium --scope project
859
+ /pantheon-model reset --agent hermes --scope project
860
+ ```
861
+
862
+ Overrides vivem em `.pantheon/active-preset.json` em `overrides.agents[agent]` — sem `model`/`small_model` top-level e sem `.env`.
863
+
864
+ ### 4. Run your first feature
766
865
 
767
866
  Once agents are loaded, invoke the orchestrator:
768
867
 
@@ -794,6 +893,7 @@ Type these in the OpenCode chat:
794
893
  | `/pantheon-remember` | Store in memory |
795
894
  | `/pantheon-search` | Search memory |
796
895
  | `/pantheon-status` | System health and agent status |
896
+ | `/pantheon-model` (wizard) / `status\|show\|set --agent\|reset --agent` | Herança nativa default; `status` lista 14 agentes (model/effort/origem); `set --agent X --model provider/model-id [--effort low|medium|high] [--scope project|global]` com validação CAPABILITY_TABLE + clamp + hasVision; `reset --agent X`; default scope `project`; global exige `confirm`+`authorize_global`; nunca escreve `.env` nem top-level `model`; persistência atômica `.bak` + health-check |
797
897
  | `/pantheon-verify` | Hash edit verification |
798
898
 
799
899
  ---
@@ -1040,11 +1140,17 @@ Use the isolated sandbox (`~/pantheon-sandbox/`) — **never** the dev environme
1040
1140
 
1041
1141
  **Happy path (clean edit):** any normal tool call (exit 0) is **silent** — no console output by design, even though the audit hooks append their log files (`sessions.log`, `delegations.log`). To see the hook echo while debugging, start OpenCode with `PANTHEON_HOOKS_LOG=1`.
1042
1142
 
1043
- **Delegation path (chat.message reminders):** on OpenCode 1.18.13 the TUI drops `tui.toast.show` events, so delegation signals are injected into the next user message as a single `<system-reminder>` text part (oh-my-openagent fallback pattern). Ask something that dispatches subagents (e.g. *"dispare 2 subagentes apollo em paralelo para listar arquivos e comparar resultados"*) and expect:
1143
+ **Delegation path (zero chat noise):** delegation signals are surfaced through
1144
+ TUI toasts (when enabled), the board's `[unread]` marker, and the
1145
+ `pantheon_delegation_list` / `pantheon_delegation_read` tools. Ask something
1146
+ that dispatches subagents (e.g. *"dispare 2 subagentes apollo em paralelo para
1147
+ listar arquivos e comparar resultados"*) and expect:
1044
1148
 
1045
- - A `<system-reminder>` in the chat with `🚀 apollo em execução` / `✅ apollo concluiu` (or the aggregate `✅ N agentes concluídos (...)` for 3+ agents completing within 6s)
1149
+ - A TUI toast with `🚀 apollo em execução` / `✅ apollo concluiu` when
1150
+ `PANTHEON_TOASTS` permits it
1151
+ - `[unread]` in `pantheon_delegation_list` until the terminal result is read
1046
1152
  - An honest append to `logs/agent-sessions/delegations.log`: the **real agent name** (extracted from `tool_input.subagent_type`, never `unknown` when present) and a **non-fabricated status** — `success` only on explicit completion evidence, `failure` for refusals/errors, `unknown` otherwise
1047
- - With `export PANTHEON_TOASTS=off` before starting OpenCode: no toasts/reminders at all
1153
+ - With `export PANTHEON_TOASTS=off` before starting OpenCode: no toasts; board/list/read and audit-log visibility remain available
1048
1154
 
1049
1155
  ### Pre-commit hooks (local secret gate)
1050
1156
 
@@ -190,6 +190,11 @@ async function main() {
190
190
  const autoYes = args.includes('--yes') || args.includes('-y')
191
191
  const presetIndex = args.indexOf('--preset')
192
192
  const presetOpt = presetIndex >= 0 ? (args[presetIndex + 1] ?? null) : null
193
+ // Explicit top-level model overrides for the generated config.
194
+ const modelIndex = args.indexOf('--model')
195
+ const modelOpt = modelIndex >= 0 ? (args[modelIndex + 1] ?? null) : null
196
+ const smallModelIndex = args.indexOf('--small-model')
197
+ const smallModelOpt = smallModelIndex >= 0 ? (args[smallModelIndex + 1] ?? null) : null
193
198
  // --version v1|v2 labels the install target (informational; the config is
194
199
  // shared and V1-shaped under both versions). Invalid values fail fast.
195
200
  const versionIndex = args.indexOf('--version')
@@ -218,6 +223,8 @@ async function main() {
218
223
  interactive: forceInteractive,
219
224
  headless: forceHeadless,
220
225
  yes: autoYes,
226
+ model: modelOpt,
227
+ smallModel: smallModelOpt,
221
228
  preset: presetOpt,
222
229
  version: versionOpt ?? 'v1',
223
230
  })
@@ -0,0 +1,34 @@
1
+ ---
2
+ description: "Inspect or change per-agent model overrides in active-preset.json"
3
+ agent: zeus
4
+ ---
5
+ # /pantheon-model — Per-agent model overrides
6
+
7
+ Use the deterministic `pantheon_model` tool for this command. Operates exclusively
8
+ on `active-preset.json` `overrides.agents[agent]` (project or global). Never
9
+ writes `.env` and never injects top-level `model`/`small_model` into `opencode.json`.
10
+
11
+ ## Usage
12
+
13
+ - `/pantheon-model status` or `/pantheon-model show` — list 14 canonical agents
14
+ (`zeus`, `athena`, `apollo`, `hermes`, `aphrodite`, `demeter`, `themis`,
15
+ `prometheus`, `hephaestus`, `nyx`, `gaia`, `iris`, `mnemosyne`, `talos`)
16
+ with effective `model`, `effort`, and origin (`preset` | `override` | `env` | `none`)
17
+ and the active preset, without showing secrets.
18
+ - `/pantheon-model` (no args) — interactive wizard via `askQuestions`:
19
+ agente → modelo (`provider/model-id`) → effort (`low`/`medium`/`high`) → scope.
20
+
21
+ - `/pantheon-model set --agent <name> --model <provider/model-id> [--effort low|medium|high] [--scope project|global]`
22
+ — set per-agent override. Validates agent is one of the 14, `provider/model-id`
23
+ format, `CAPABILITY_TABLE` entry via `capabilityEntry()` and clamps effort via
24
+ `normalizeCapability()`; warns via `hasVision` for text-only models. Persists
25
+ atomically with `.bak` backup and per-path lock. Default scope is `project`.
26
+
27
+ - `/pantheon-model reset --agent <name> [--scope project|global]` — remove the
28
+ per-agent override from `overrides.agents[agent]`.
29
+
30
+ `--scope project|global` is supported by `set` and `reset`. Global changes require
31
+ explicit `confirm` and `authorize_global`. Values must use `provider/model-id`.
32
+ Changes are backed up (`.bak`) and written atomically; restart OpenCode after a
33
+ successful change. The tool never writes `.env` and never injects `model`/`small_model`
34
+ global keys — delegate inheritance is native (no model → inherits chat/preset model).
package/opencode.json CHANGED
@@ -14,8 +14,6 @@
14
14
  "experimental": {
15
15
  "subagent_depth": 2
16
16
  },
17
- "model": "opencode-go/deepseek-v4-flash",
18
- "small_model": "opencode-go/deepseek-v4-flash",
19
17
  "permission": {
20
18
  "skill": {
21
19
  "*": "allow"
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "pantheon-opencode",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "Multi-agent orchestration for OpenCode — 14 specialized agents, TDD, Themis review gates.",
5
5
  "publishConfig": {
6
6
  "access": "public",
7
7
  "registry": "https://registry.npmjs.org/"
8
8
  },
9
9
  "scripts": {
10
- "postinstall": "node scripts/postinstall.mjs",
10
+ "postinstall": "node scripts/postinstall.mjs && node scripts/sync-tui.mjs",
11
11
  "prepare": "husky",
12
12
  "setup": "node bin/pantheon-init.mjs init",
13
13
  "build:agents-md": "node scripts/build-agents-md.mjs",