pantheon-opencode 1.6.0-beta.10 → 1.6.0-beta.11

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.
Files changed (46) hide show
  1. package/AGENTS.global.md +42 -18
  2. package/AGENTS.md +1 -1
  3. package/CHANGELOG.md +24 -0
  4. package/README.md +66 -21
  5. package/bin/pantheon-init.mjs +44 -1
  6. package/package.json +4 -4
  7. package/plugin.json +1 -1
  8. package/pyproject.toml +1 -1
  9. package/scripts/build-agents-md.mjs +60 -6
  10. package/scripts/install/backup.mjs +475 -0
  11. package/scripts/install/cli-ui.mjs +6 -1
  12. package/scripts/install/exit-codes.mjs +26 -0
  13. package/scripts/install/interactive.mjs +15 -1
  14. package/scripts/install/migrate.mjs +41 -22
  15. package/scripts/install/opencode.mjs +562 -50
  16. package/scripts/install/plan.mjs +287 -0
  17. package/scripts/install/plugin.mjs +22 -8
  18. package/scripts/install/shared.mjs +89 -55
  19. package/scripts/install/strings.mjs +20 -0
  20. package/scripts/install/venv.mjs +13 -3
  21. package/scripts/install/vision-prompt.mjs +11 -1
  22. package/scripts/mcp_persistence.py +50 -15
  23. package/scripts/prune.mjs +9 -3
  24. package/scripts/restore.mjs +222 -0
  25. package/skills-lock.json +1 -1
  26. package/src/agents/iris.md +6 -0
  27. package/src/agents/zeus.md +19 -62
  28. package/src/instructions/agent-return-format.instructions.md +17 -15
  29. package/src/instructions/memory-protocol.instructions.md +3 -2
  30. package/src/instructions/test-economy.instructions.md +21 -0
  31. package/src/instructions/zeus-anti-stall.instructions.md +6 -6
  32. package/src/instructions/zeus-council-synthesis.instructions.md +10 -11
  33. package/src/instructions/zeus-memory-operations.instructions.md +10 -6
  34. package/src/instructions/zeus-timeout-retry.instructions.md +28 -9
  35. package/src/mcp/mcp_persistence.py +50 -15
  36. package/src/pantheon/cost-command.ts +5 -2
  37. package/src/pantheon/model-agents.ts +19 -0
  38. package/src/pantheon/model-command.ts +218 -56
  39. package/src/pantheon/v2-model-overrides.ts +275 -0
  40. package/src/pantheon/v2-tools.ts +18 -29
  41. package/src/plugin-v2.ts +13 -0
  42. package/src/plugins/tui/dist/tui-v2.js +2 -2
  43. package/src/plugins/tui/dist/tui.js +1 -1
  44. package/src/plugins/tui/package-lock.json +2 -2
  45. package/src/plugins/tui/package.json +1 -1
  46. package/src/skills/auto-continue/SKILL.md +14 -6
@@ -40,7 +40,7 @@ the complete plan in the current conversation before requesting approval.
40
40
 
41
41
  ## Council Specialist Response Format
42
42
 
43
- When responding to a `/pantheon` council synthesis invocation, specialists MUST return this structured format:
43
+ When responding to a `/pantheon` council synthesis invocation, specialists MUST return this structured format. First-round specialists receive independent prompts without peer responses, whether dispatch is parallel or synchronous/sequential; they therefore cannot know actual peer positions. Do not guess them, claim agreement/disagreement with unseen peers, or self-reference in agreement signals. Omit `agreement_signals` or write `none` in the first round. In a rebuttal round, signals may reference only peer responses included in that round's prompt. Zeus derives agreement and disagreement during synthesis by comparing actual responses.
44
44
 
45
45
  ```
46
46
  ## specialist_response
@@ -49,8 +49,8 @@ When responding to a `/pantheon` council synthesis invocation, specialists MUST
49
49
  **trade_offs:** <what's gained vs lost, specific>
50
50
  **risks:** <what could go wrong, max 3 items>
51
51
  **confidence:** High | Medium | Low
52
- **agreement_signals:** agree:@agent1 on <issue>, agree:@agent2 on <issue> | disagree:@agent3 on <issue>
53
- **specific_claims:** <count of specific factual claims in response>
52
+ **agreement_signals:** <omit or `none` in first round; rebuttal may cite only visible peer responses>
53
+ **specific_claims:** <optional self-reported count; advisory only, not evidence>
54
54
  ```
55
55
 
56
56
  ### Field Rules
@@ -62,26 +62,28 @@ When responding to a `/pantheon` council synthesis invocation, specialists MUST
62
62
  | trade_offs | ✅ | At least one gain and one loss, specific to context |
63
63
  | risks | ✅ | Max 3 bullet points |
64
64
  | confidence | ✅ | One of: High, Medium, Low |
65
- | agreement_signals | Optional | Format: `agree:@agent on issue \| disagree:@agent on issue`. Use only when you can reference other specialists expected positions. |
66
- | specific_claims | ✅ | Integer count of verifiable factual statements in the response |
65
+ | agreement_signals | Optional | Omit or use `none` in the first round. In rebuttal, reference only peer responses visible in the prompt; never speculate or self-reference. Zeus derives synthesis positions from actual responses, not these signals. |
66
+ | specific_claims | Optional | Self-reported integer count only; advisory and not independently validated. Do not treat the count alone as evidence or proof of confidence. |
67
67
 
68
68
  ### Confidence Guidelines
69
69
 
70
- - **High**: Position backed by 3+ specific claims with evidence or direct experience
71
- - **Medium**: Position backed by 1-2 specific claims
70
+ - **High**: Position backed by at least 3 verifiable claims supported by evidence in the response; a self-reported count alone does not qualify
71
+ - **Medium**: Position backed by at least 1 verifiable claim supported by evidence in the response
72
72
  - **Low**: Position is opinion-based or speculative
73
73
 
74
+ Equal self-reported counts (for example, several specialists each reporting 7) do not by themselves prove fabrication; assess whether the actual response contains verifiable, supported claims.
75
+
74
76
  ### Example
75
77
  ```
76
78
  ## specialist_response
77
- **position:** The BackgroundJobBoard should be used for council crash recovery
78
- **reasoning:** The board already supports running→completed→reconciled state machine with persistence. Registering council dispatches there adds ~50ms overhead but prevents total session loss on context crash. The WAL pattern ensures no data loss on restart.
79
- **trade_offs:** Gain: crash recovery for multi-minute council sessions. Lose: ~50ms registration overhead per council.
80
- **risks:** Board persistence failure could block council start — implement with fire-and-forget error handling
81
- **confidence:** High
82
- **agreement_signals:** agree:@themis on persist-before-notify
83
- **specific_claims:** 3
79
+ **position:** Use a bounded local cache for the read-heavy endpoint.
80
+ **reasoning:** The endpoint repeatedly reads the same reference data. A bounded cache reduces repeated lookups, while a short TTL limits staleness.
81
+ **trade_offs:** Gain: fewer repeated reads. Lose: results may remain stale until the TTL expires.
82
+ **risks:** Cache invalidation may lag after updates.
83
+ **confidence:** Medium
84
+ **agreement_signals:** none
85
+ **specific_claims:** 2 (self-reported; advisory)
84
86
  ```
85
87
 
86
88
  ## Memory Context
87
- If memory affected the result, state the takeaway briefly; do not repeat the entry or task context.
89
+ If memory affected the result, state the takeaway briefly; do not repeat the entry or task context. If persistence was expected but no write tool was exposed or a write failed, state that it was not persisted; never imply a successful store without confirmation.
@@ -16,8 +16,9 @@ These rules apply to all agents; each agent file may add domain-specific rules.
16
16
  - Use a targeted query (`top_k=2`); do not search the whole prompt by default. Missing or irrelevant results never block current work.
17
17
 
18
18
  ### Persistence
19
- - `memory_store()` is manual, not automatic. Store at most one concise, reusable top-level result; never persist routine child summaries, phase updates, test logs, or temporary state.
20
- - Confirm the store succeeded before claiming persistence. There is no automatic memory WAL or recovery. Add ADRs to the memory bank only when explicitly requested.
19
+ - A memory write is optional and conditional on a write tool being exposed and permitted in the active session. Search permission does not imply write permission; in the reported Beta 10 Zeus root, `memory_store` is not exposed/granted.
20
+ - Store at most one concise, reusable top-level result; never persist routine child summaries, phase updates, test logs, or temporary state. Confirm a successful write before claiming persistence.
21
+ - If no write tool is available or the write did not succeed, say that the information was not persisted. Do not imply automatic memory storage or recovery. Add ADRs to the memory bank only when explicitly requested.
21
22
 
22
23
  ### Relevance and permanent records
23
24
  Ignore weak matches; routine summaries do not belong in durable memory.
@@ -0,0 +1,21 @@
1
+ ---
2
+ description: "Test economy — write smaller, focused suites; heavy install/E2E suites are opt-in, never per-phase."
3
+ name: "Test Economy"
4
+ ---
5
+
6
+ Write the smallest test that proves the behavior: one behavior → one focused
7
+ test, never the same coverage duplicated across suites or files.
8
+
9
+ - Do NOT add E2E, full-install, or network-dependent tests unless the change
10
+ actually alters that end-to-end path. Prefer unit or integration tests.
11
+ - Do not assert on copy/format strings redundantly, and do not write
12
+ assertions that only restate the implementation ("test the test").
13
+ - Heavy or slow suites (e.g. real install/E2E) MUST be opt-in via a separate
14
+ script/tier. Never run them per edit or per phase; run only the affected
15
+ subset.
16
+ - Respect a per-phase validation time budget: if a suite takes minutes,
17
+ justify running it and prefer the targeted subset. Reserve the full heavy
18
+ suites for release gates.
19
+ - Fixing a bug: add one targeted regression test, not a broad new suite.
20
+ - This economy rule does NOT weaken stronger gates: auth, security,
21
+ data-integrity, and required coverage thresholds stay mandatory.
@@ -16,18 +16,18 @@ You MUST self-monitor for these stall conditions:
16
16
  | Symptom | Detection Rule | Recovery Action |
17
17
  |---------|---------------|-----------------|
18
18
  | Silent loop | 3+ consecutive turns with no tool call AND no visible progress | Output `[STALL_DETECTED]` and re-read your task definition. If still stuck, escalate to user with: "I appear to be stuck on [task]. Options: (1) retry with different approach, (2) delegate to specialist, (3) simplify scope." |
19
- | Delegation black hole | Agent dispatched but no response after 2x the timeout from routing.yml | Log the hang, cancel via `cancel_task`, then follow the fallback chain in `## ⏱️ Timeout & Retry Enforcement` |
19
+ | Delegation black hole | No result or host completion notification after the applicable timeout | Stop dependent work; do not call an unavailable cancel/status tool. Follow `## ⏱️ Timeout & Retry Enforcement`, report uncertainty, and retry/reroute only under that policy |
20
20
  | Circular delegation | Same specialist re-dispatched for same task 2+ times without progress | Break cycle: dispatch to different specialist OR escalate to user |
21
21
  | Idle after completion | All background tasks completed but no synthesis/next step for 2+ turns | Force synthesis: summarize all completed results and propose next action |
22
22
  | Context thrash | Re-reading same files repeatedly without new action | Stop re-reading. State: "Already have context on [file]. Proceeding with [action]." |
23
23
 
24
24
  ## Phase Reminder
25
25
 
26
- After dispatching background specialists, you MUST:
27
- 1. DO NOT poll running jobs or consume their partial output
28
- 2. DO NOT advance dependent work until terminal results arrive
29
- 3. Continue orchestration ONLY on non-overlapping independent work
30
- 4. If nothing independent remains, briefly report what was launched and WAIT
26
+ Use the root `subagent` dispatch observed in the Beta 10 runtime; `task()` is host/API terminology, and the exact signature/background options depend on the active runtime. Prefer synchronous delegation unless the visible schema supports background and the host exposes a way to observe completion. For asynchronous work:
27
+ 1. Do not invoke `task_status`, `cancel_task`, or board methods unless a corresponding tool is actually exposed (none was exposed in the reported Beta 10 root catalog).
28
+ 2. Do not advance dependent work until a result or host-provided completion notification arrives.
29
+ 3. Continue orchestration only on non-overlapping independent work.
30
+ 4. If nothing independent remains, briefly report what was dispatched and wait for host notification; do not claim job tracking or recovery.
31
31
 
32
32
  Self-check every 3 turns: "Am I waiting on a delegate? Have I polled without need? Is there independent work I can do?"
33
33
 
@@ -13,19 +13,18 @@ Use an inline specialist council for material trade-offs, architecture/security
13
13
 
14
14
  1. **Precedent:** Run the separate `council_decisions` search defined in `## Memory Protocol`. Apply its age/score rules; if no fast-path decision applies, continue.
15
15
  2. **Research (optional):** For `/pantheon --research <question>`, ask @apollo for a 30s pre-scan and pass findings as `shared_context` to every specialist.
16
- 3. **Register:** Before dispatch, call `board.registerLaunch` with a council task ID, parent session, Zeus, question, and synthesis objective. This enables crash recovery.
17
- 4. **Select and dispatch:** Choose at most 3 agents using the domain map below. Send all `task()` calls in one message. Each prompt includes the question, shared context, required response format, and role timeout (120s reviewers; 60s explorers/implementers).
18
- 5. **Collect:** Wait for all responses and note timeouts. Partial responses are acceptable only from read-only @apollo or @gaia.
19
- 6. **Validate confidence:** High requires at least 3 verifiable claims; otherwise downgrade to Medium and state why. Medium requires at least 1 claim; Low needs no minimum. Opinions alone are not specific claims.
20
- 7. **Resolve divergence:** Compute agreement rate as `min(agreements, divergences) / total_points` from structured `agreement_signals`. Below 50%, and only if no agent timed out, run one rebuttal round with all responses and the current synthesis draft. Treat revised responses as final. If disagreement remains below 50%, research factual divergence points with official docs, benchmarks, or issues (max 3 searches; seek 2 independent sources per point when possible). Skip research for subjective-only disagreements. Send responses and a cited evidence brief to @themis as moderator; request verdicts, overall direction, confidence, and unresolved issues. Low confidence or unresolved points remain explicit in the synthesis. Moderator and audit roles are separate.
21
- 8. **Synthesize and audit:** Use the output format below, then ask @themis to compare raw responses with the synthesis. Check representation of every specialist, preserved divergences, accurate attribution, and confidence specificity. Fix any issue before delivery.
22
- 9. **Persist:** Store the decision using the `council_decisions` write format in `## Memory Protocol`, then call `board.markReconciled(task_id)`.
16
+ 3. **Select and dispatch:** Choose at most 3 agents using the domain map below. Dispatch through the root `subagent` tool observed in the Beta 10 runtime. `task()` is host/API terminology; signature, background mode, and parallel dispatch depend on the active runtime schema. Keep first-round prompts independent: do not include other specialists' responses. Dispatch in parallel when the observed tool/runtime supports it; synchronous or sequential dispatch is also valid if each first-round prompt excludes prior first-round responses. Specialists therefore cannot know actual peer positions in the first round: do not ask them to guess, signal agreement/disagreement, or refer to themselves/peers speculatively. First-round `agreement_signals` must be omitted or set to `none`.
17
+ 4. **Collect:** Use returned subagent results or host-provided completion notifications. Do not call `task_status` or claim job tracking/recovery when unavailable. Note timeouts and missing responses explicitly. Partial responses are acceptable only from read-only @apollo or @gaia.
18
+ 5. **Validate confidence:** High requires at least 3 verifiable claims; otherwise downgrade to Medium and state why. Medium requires at least 1 claim; Low needs no minimum. Opinions alone are not specific claims. Assess the claims and evidence actually present in each response; a self-reported `specific_claims` count is advisory, not evidence or proof of confidence.
19
+ 6. **Resolve divergence:** After all initial responses arrive, Zeus groups their actual substantive positions by issue and derives agreement from those positions, not from speculative or self-reported `agreement_signals`. For each comparable issue, compare every unordered pair of specialists who provided a comparable substantive position on that issue. A pair agrees only when its substantive positions are compatible; every pair whose positions are not aligned counts as divergent. For an issue with `n` specialists providing comparable positions, include `n*(n-1)/2` pairs in `total_comparable_pairs`; sum this across included issues. Exclude issues with fewer than two comparable positions and state that they were excluded. Calculate `agreement_rate = agreeing_pairs / total_comparable_pairs`: unanimity is 100%, all pairs in divergence is 0%, and non-aligned pairs are divergences. If the denominator is zero, the rate is indeterminate/has no basis; never substitute an artificial zero or trigger rebuttal from an undefined rate. Below 50%, and only if no agent timed out, run one rebuttal round with all responses and the current synthesis draft. In that round, signals may refer only to peer responses visible in the rebuttal prompt; treat revised responses as final and recompute the rate from their actual positions. If the defined rate remains below 50%, research factual divergence points with official docs, benchmarks, or issues (max 3 searches; seek 2 independent sources per point when possible). Skip research for subjective-only disagreements. Send responses and a cited evidence brief to @themis as moderator; request verdicts, overall direction, confidence, and unresolved issues. Low confidence or unresolved points remain explicit in the synthesis. Moderator and audit roles are separate.
20
+ 7. **Synthesize and audit:** Use the output format below, then ask @themis to compare raw responses with the synthesis. Check representation of every specialist, preserved divergences, accurate attribution, and confidence specificity. Fix any issue before delivery.
21
+ 8. **Persist (conditional):** Store the decision only if a memory-write tool is explicitly exposed and permitted in the active root tool list; require its success result before saying it was saved. Otherwise say the decision was not persisted. The `BackgroundJobBoard` is internal and has no root-callable board tool in the reported runtime.
23
22
 
24
- If context is lost, use `board.recoverRunningJobs()` and `board.formatForPrompt()` to find unreconciled work. Re-dispatch a crashed council with the same question and label it as a retry.
23
+ The `BackgroundJobBoard` is internal bookkeeping, not a tool available to Zeus root; do not call `board.registerLaunch`, `markReconciled`, `recoverRunningJobs`, or `formatForPrompt`, and do not assume crash recovery. If context is lost, continue only from results still present in the conversation or a host handoff; otherwise report the missing context and ask how to proceed.
25
24
 
26
25
  ## Specialist Response Format
27
26
 
28
- Require `## specialist_response` from `## Agent Return Format`: `position`, `reasoning`, `trade_offs`, `risks`, `confidence`, `agreement_signals`, and `specific_claims`.
27
+ Require `## specialist_response` from `## Agent Return Format`. The first round must not prompt specialists to infer other agents' views; agreement signals are omitted or `none` until actual peer responses are visible.
29
28
 
30
29
  ## Domain Map
31
30
 
@@ -53,7 +52,7 @@ Question / date / response rate / timed-out agents / precedent / research contex
53
52
  - Points shared by multiple specialists
54
53
 
55
54
  ### Divergences
56
- | Issue | Sides | Resolution |
55
+ | Issue | Specialist positions (attribute each side to its agent) | Resolution |
57
56
 
58
57
  ### Evidence & Moderation (when used)
59
58
  Research points, evidence, moderator verdict, cited sources, unresolved issues
@@ -68,4 +67,4 @@ Themis approved, or issues corrected
68
67
  Confidence adjusted for response rate
69
68
  ```
70
69
 
71
- The user invokes this flow with `/pantheon <question>`; `--research` enables the Apollo pre-scan. Preserve actual specialist timeout or unresolved-tie details in the response.
70
+ Initial agreement signals remain omitted/`none`; consensus and agreements are derived by Zeus from compared substantive positions and presented in the synthesis. Preserve actual specialist timeout or unresolved-tie details in the response. The user invokes this flow with `/pantheon <question>`; `--research` enables the Apollo pre-scan.
@@ -18,9 +18,13 @@ Before a council, search separately from the task-level lookup only when a past
18
18
  Use a recent, directly matching decision only after checking current context;
19
19
  otherwise treat it as background, never as authority to skip a needed review.
20
20
 
21
- Persist only reusable, material decisions. Use
22
- `key="council:<yyyy-mm-dd>:<slug>"`; JSON-stringify both `value` and
23
- `metadata` for `memory_store(namespace="council_decisions", ...)`. Keep the
24
- record concise: question, recommendation, specialists, confidence, unresolved
25
- trade-off, and timestamp. Do not store routine subtask summaries or status
26
- updates. Use the memory bank for ADRs only when explicitly requested.
21
+ Persist only reusable, material decisions, and only if a memory-write tool is
22
+ explicitly exposed and permitted in the active root tool list. The reported Beta
23
+ 10 Zeus root has `memory_search` but no `memory_store` grant/tool; search access
24
+ does not imply write access. If a write tool is available, use
25
+ `key="council:<yyyy-mm-dd>:<slug>"`, JSON-stringify both `value` and `metadata`,
26
+ and confirm success before claiming persistence. Otherwise tell the user the
27
+ decision was not persisted. Keep any saved record concise: question, recommendation,
28
+ specialists, confidence, unresolved trade-off, and timestamp. Do not store routine
29
+ subtask summaries or status updates. Use the memory bank for ADRs only when
30
+ explicitly requested.
@@ -9,6 +9,13 @@ fallback: shared
9
9
 
10
10
  When a delegated agent does not respond in time, enforce the timeout policy from `routing.yml`.
11
11
 
12
+ Use the root `subagent` dispatch observed in the Beta 10 runtime. `task()` is
13
+ host/API terminology; the active runtime determines the callable schema and any
14
+ background options. Do not assume root `task_status`, `cancel_task`, or board
15
+ tracking/recovery tools. Prefer synchronous dispatch unless background completion
16
+ is observable through the host, and keep any retry list in the current context
17
+ only; do not claim persistent job tracking.
18
+
12
19
  ## Timeout Behavior by Agent Role
13
20
 
14
21
  | Agent Role | Timeout | Retry Policy | Partial Results OK? | Reasoning Effort |
@@ -43,14 +50,18 @@ at most once, and an exhausted chain is never restarted automatically.
43
50
 
44
51
  For a domain/scope refusal, do not retry with a rephrased prompt. Correct the
45
52
  route once only when the right specialist is clear; otherwise stop and ask.
46
- Record one `DelegationCacheDecision` telemetry item for the corrected route,
47
- including `reroute_from`, `reroute_to`, and `delegation_id` when available.
53
+ Record one `DelegationCacheDecision` telemetry item only when telemetry recording
54
+ is actually exposed; otherwise keep the corrected route in the current handoff
55
+ and do not claim telemetry was persisted. Include `reroute_from`, `reroute_to`,
56
+ and `delegation_id` when available.
48
57
 
49
58
  ### Escalation Protocol
50
59
  When all fallbacks fail, report the tried agents and errors, offer a different approach/simpler scope/manual fix, and stop. Never retry the same chain automatically.
51
60
 
52
61
  ### Session Reuse Check
53
- Check for a reusable session before dispatch and obey `session_max` in `routing.yml`.
62
+ Reuse a prior specialist session only when the active host exposes that capability;
63
+ otherwise dispatch through `subagent` with necessary context. Treat `session_max`
64
+ as policy context, not as a claim that Zeus can enumerate sessions.
54
65
 
55
66
  ---
56
67
 
@@ -65,19 +76,23 @@ Use the lightest path that safely meets the request. A multi-file but bounded lo
65
76
  ### Subtask Decision Tree (run BEFORE every delegation)
66
77
 
67
78
  ```
68
- □ Is the scope clear, bounded, and reversible? [YES→continue | NO→clarify/plan]
69
- □ Does it avoid auth/security, data/schema, and destructive risk? [YES→continue | NO→full review/gates]
70
- □ Is there no required Themis/audit handoff for this change? [YES→continue | NO→preserve that review]
79
+ □ Is the scope clear, bounded, reversible, and low-uncertainty? [YES→continue | NO→clarify/plan]
80
+ □ Does it avoid auth/security, data/schema, destructive, broad/material, and user-visible API risk? [YES→continue | NO→relevant gates]
81
+ □ Is there no required Themis/audit handoff for this change? [YES→continue | NO→preserve that review]
71
82
 
72
- ALL YES → direct/lightweight execution; no routine plan or artifact
83
+ ALL YES → one correct domain specialist; they inspect needed context, implement, and verify; no routine plan/artifact, separate discovery, council, or review
73
84
  ANY NO → add only the planning, artifact, specialist review, and approval gates the risk requires
74
85
  ```
75
86
 
76
87
  ### Safety Rules
77
88
  1. **Bounded scope** — can be a small multi-file change or a read-only investigation
78
- 2. **Low risk** — no security implications, no data loss, no breaking changes
89
+ 2. **Low risk and uncertainty** — no security implications, data loss, breaking/user-visible API impact, broad material scope, or unresolved high uncertainty
79
90
  3. **No required Themis dependency** — sensitive/material output retains its review gate
80
91
 
92
+ The selected specialist, not a routine Apollo discovery pass, inspects the relevant
93
+ local context for a lightweight implementation. Keep specialist roles available for
94
+ on-demand routing; do not remove an agent based on one task or one overhead observation.
95
+
81
96
  ## Subtask Return Format
82
97
  Return the required `## subtask_summary` fields defined in `## Agent Return Format`; include `memory_context` when memory was used.
83
98
 
@@ -89,4 +104,8 @@ Only agents marked ✅ in the Timeout Behavior table above may return partial re
89
104
 
90
105
  # 📊 TIMEOUT TRACKING
91
106
 
92
- Track in-flight delegations against the Timeout Behavior table above. Log timeouts to `/memories/session/timeout-log.md` for later analysis.
107
+ Keep only an in-context list of active delegations and already-tried agents when
108
+ needed. Use results returned by `subagent` or host completion notifications; do
109
+ not poll, cancel, or write a timeout log unless the corresponding tool is exposed.
110
+ Report any timeout and the retry/fallback taken in the user-facing handoff; do
111
+ not claim persistent tracking or recovery.
@@ -914,15 +914,35 @@ def _validate_delegations(delegations: object) -> None:
914
914
 
915
915
  def _validate_tail(tail: object, payload_bytes: int | None = None) -> list[str]:
916
916
  """Validate bounded serialized tail lines."""
917
- if not isinstance(tail, list) or len(tail) > MAX_TAIL_ITEMS:
918
- raise ValueError("tail exceeds its size limit")
917
+ if not isinstance(tail, list):
918
+ raise ValueError("tail must be an array")
919
+ if len(tail) > MAX_TAIL_ITEMS:
920
+ raise ValueError(
921
+ f"tail has {len(tail)} items; maximum is {MAX_TAIL_ITEMS}; "
922
+ "remove tail entries or omit tail"
923
+ )
919
924
  for line in tail:
920
- if not isinstance(line, str) or len(line.encode()) > MAX_TAIL_LINE_LENGTH:
921
- raise ValueError("tail entries exceed their size limit")
925
+ if not isinstance(line, str):
926
+ raise ValueError("tail entries must be strings")
927
+ line_bytes = len(line.encode())
928
+ if line_bytes > MAX_TAIL_LINE_LENGTH:
929
+ raise ValueError(
930
+ f"tail entries are {line_bytes:,} UTF-8 bytes; maximum is "
931
+ f"{MAX_TAIL_LINE_LENGTH:,}; remove or shorten tail entries, "
932
+ "or omit tail"
933
+ )
922
934
  if payload_bytes is not None and payload_bytes > MAX_CONTEXT_CONTENT_BYTES:
923
- raise ValueError("tail payload exceeds its size limit")
924
- if sum(len(line.encode()) for line in tail) > MAX_CONTEXT_CONTENT_BYTES:
925
- raise ValueError("tail payload exceeds its size limit")
935
+ raise ValueError(
936
+ f"tail payload is {payload_bytes:,} UTF-8 bytes; maximum is "
937
+ f"{MAX_CONTEXT_CONTENT_BYTES:,}; remove tail entries or omit tail"
938
+ )
939
+ tail_bytes = sum(len(line.encode()) for line in tail)
940
+ if tail_bytes > MAX_CONTEXT_CONTENT_BYTES:
941
+ raise ValueError(
942
+ f"tail contains {tail_bytes:,} UTF-8 bytes across strings; maximum "
943
+ f"is {MAX_CONTEXT_CONTENT_BYTES:,} bytes; remove tail entries or "
944
+ "omit tail"
945
+ )
926
946
  return tail
927
947
 
928
948
 
@@ -1020,8 +1040,14 @@ def _collect_context_content_errors(
1020
1040
  if not isinstance(content, str):
1021
1041
  errors.shape(prefix, "a string", content)
1022
1042
  return
1023
- if len(content.encode()) > MAX_CONTEXT_CONTENT_BYTES:
1024
- errors.add(prefix, f"exceeds the {MAX_CONTEXT_CONTENT_BYTES}-byte limit")
1043
+ content_bytes = len(content.encode())
1044
+ if content_bytes > MAX_CONTEXT_CONTENT_BYTES:
1045
+ errors.add(
1046
+ prefix,
1047
+ f"is {content_bytes:,} UTF-8 bytes; maximum is "
1048
+ f"{MAX_CONTEXT_CONTENT_BYTES:,} bytes. Reduce content or omit "
1049
+ "optional tail if it contributes",
1050
+ )
1025
1051
  return
1026
1052
  try:
1027
1053
  parsed = json.loads(content)
@@ -1030,11 +1056,10 @@ def _collect_context_content_errors(
1030
1056
  # it as a checkpoint. It is still bounded above.
1031
1057
  return
1032
1058
  if isinstance(parsed, list) and key == "tail":
1033
- if len(parsed) > MAX_TAIL_ITEMS or any(
1034
- not isinstance(line, str) or len(line.encode()) > MAX_TAIL_LINE_LENGTH
1035
- for line in parsed
1036
- ):
1037
- errors.add(f"{prefix}.tail", "exceeds its size limit")
1059
+ try:
1060
+ _validate_tail(parsed)
1061
+ except ValueError as exc:
1062
+ errors.reroot(prefix, str(exc))
1038
1063
  return
1039
1064
  if not isinstance(parsed, dict):
1040
1065
  # The message already names 'content': do not prepend the path again.
@@ -1164,6 +1189,11 @@ def _upsert_context_entry(
1164
1189
  name="context_save",
1165
1190
  description="Save a context checkpoint for a session/phase. "
1166
1191
  "Stores structured JSON in persistence KV with a key-specific TTL. "
1192
+ "The serialized content is limited to 65,536 UTF-8 bytes. An included "
1193
+ "tail may contain at most 100 strings, each at most 4,096 UTF-8 bytes, "
1194
+ "with at most 65,536 UTF-8 bytes across all tail strings. Oversized "
1195
+ "content or tail is rejected, never truncated; remove or omit optional "
1196
+ "tail data when applicable. "
1167
1197
  "content is a JSON STRING; when it parses to an object, 'goal', 'phase', "
1168
1198
  "'delegations' and 'heartbeat' must each be JSON OBJECTS and 'tail' must "
1169
1199
  "be a JSON ARRAY. 'phase' is an object {current,total,name} — NOT a phase "
@@ -1180,7 +1210,12 @@ async def context_save(
1180
1210
  str,
1181
1211
  Field(
1182
1212
  description=(
1183
- "JSON checkpoint string. When it parses to an object, 'goal', "
1213
+ "JSON checkpoint string, limited to 65,536 UTF-8 bytes. An "
1214
+ "included 'tail' may contain at most 100 strings, each at "
1215
+ "most 4,096 UTF-8 bytes, with at most 65,536 UTF-8 bytes "
1216
+ "across all tail strings. Oversized input is rejected, never "
1217
+ "truncated; remove or omit optional 'tail' when applicable. "
1218
+ "When it parses to an object, 'goal', "
1184
1219
  "'phase', 'delegations' and 'heartbeat' must be objects and "
1185
1220
  "'tail' must be an array; all are optional. 'phase' is an "
1186
1221
  "object {current,total,name}, not a counter. Example: "
@@ -129,7 +129,7 @@ const costArgs = {
129
129
  .min(1)
130
130
  .max(365)
131
131
  .optional()
132
- .describe('Number of days of delegation history to include (default 7).'),
132
+ .describe('Number of rolling 24-hour days of history to include (default 7).'),
133
133
  } satisfies z.ZodRawShape
134
134
 
135
135
  /** The XDG state directory every real host installation writes its ledger to. */
@@ -459,6 +459,9 @@ function renderMarkdown(query: CostQuery, days: number): string {
459
459
  const header = `## Token usage by agent and phase (last ${days} days)`
460
460
  const footer = [
461
461
  formatCoverage(coverage, days),
462
+ 'Window: rolling 24-hour days from query time (not calendar days or session boundaries).',
463
+ 'Aggregation: per agent and phase; phase may be unknown on V2.',
464
+ 'Limits: not grouped by session, task, model, or provider; tokens only (no dollar costs), so this cannot establish model-specific savings or deltas.',
462
465
  `Source: opencode.db (read-only) — table families: ${coverage.sources.join(' + ')} — ${coverage.assistantRows} assistant row(s) scanned`,
463
466
  ].join('\n')
464
467
  if (rows.length === 0) {
@@ -823,7 +826,7 @@ export function createCostCommand(options?: CostCommandOptions): CostCommand {
823
826
  return {
824
827
  pantheon_cost: {
825
828
  description:
826
- 'Report input, output, and total token usage by agent and phase over the last N days, read from opencode.db (read-only, no monetary values). The report states the coverage window it actually covers.',
829
+ 'Report input, output, and total token usage by agent and phase in a rolling N × 24-hour window from query time (read-only, no monetary values). It is not grouped by session, task, model, or provider; phase may be unknown on V2, so it cannot establish model-specific savings or deltas. The report states the coverage window it actually covers.',
827
830
  args: costArgs,
828
831
  execute,
829
832
  },
@@ -0,0 +1,19 @@
1
+ /** Canonical agent IDs shared by model routing and V2 override validation. */
2
+ export const KNOWN_AGENTS = [
3
+ 'zeus',
4
+ 'athena',
5
+ 'apollo',
6
+ 'hermes',
7
+ 'aphrodite',
8
+ 'demeter',
9
+ 'themis',
10
+ 'prometheus',
11
+ 'hephaestus',
12
+ 'nyx',
13
+ 'gaia',
14
+ 'iris',
15
+ 'mnemosyne',
16
+ 'talos',
17
+ ] as const
18
+
19
+ export type KnownAgent = (typeof KNOWN_AGENTS)[number]