pantheon-opencode 1.6.0-beta.1 → 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 (133) hide show
  1. package/AGENTS.global.md +206 -0
  2. package/AGENTS.md +10 -891
  3. package/CHANGELOG.md +350 -0
  4. package/README.md +561 -52
  5. package/README.pt-BR.md +285 -20
  6. package/bin/pantheon-init.mjs +70 -4
  7. package/commands/pantheon-audit.md +7 -1
  8. package/commands/pantheon-consolidate.md +1 -1
  9. package/commands/pantheon-deepwork.md +14 -3
  10. package/commands/pantheon-focus.md +17 -0
  11. package/commands/pantheon-vision.md +61 -12
  12. package/package.json +24 -17
  13. package/plugin.json +2 -2
  14. package/pyproject.toml +8 -6
  15. package/scripts/build-agents-md.mjs +428 -56
  16. package/scripts/changelog-merge.mjs +161 -0
  17. package/scripts/{code_mode_server.py → code_mode.py} +3 -3
  18. package/scripts/cost.mjs +244 -41
  19. package/scripts/doctor.mjs +151 -1
  20. package/scripts/install/agents-md.mjs +4 -4
  21. package/scripts/install/backup.mjs +475 -0
  22. package/scripts/install/cli-ui.mjs +6 -1
  23. package/scripts/install/config-migration.mjs +317 -4
  24. package/scripts/install/exit-codes.mjs +26 -0
  25. package/scripts/install/health-check.mjs +21 -19
  26. package/scripts/install/interactive.mjs +16 -2
  27. package/scripts/install/migrate.mjs +41 -22
  28. package/scripts/install/opencode-version.mjs +246 -4
  29. package/scripts/install/opencode.mjs +1175 -215
  30. package/scripts/install/plan.mjs +287 -0
  31. package/scripts/install/plugin.mjs +62 -14
  32. package/scripts/install/shared.mjs +190 -48
  33. package/scripts/install/strings.mjs +20 -0
  34. package/scripts/install/venv.mjs +13 -3
  35. package/scripts/install/vision-prompt.mjs +171 -0
  36. package/scripts/install-mcp.mjs +28 -9
  37. package/scripts/{mcp_persistence_server.py → mcp_persistence.py} +52 -17
  38. package/{src/mcp/mcp_resources_server.py → scripts/mcp_resources.py} +2 -2
  39. package/scripts/{memory_mcp_server.py → memory_mcp.py} +2 -2
  40. package/scripts/probe-context-rehydrate.mjs +8 -2
  41. package/scripts/probe-pantheon-cost.mjs +71 -15
  42. package/scripts/prune.mjs +9 -3
  43. package/scripts/restore.mjs +222 -0
  44. package/scripts/run-node-tests.mjs +189 -0
  45. package/scripts/sync-artifacts.mjs +26 -13
  46. package/scripts/sync-tui.mjs +24 -3
  47. package/scripts/test-opencode-v2-sandbox.sh +180 -26
  48. package/scripts/validate-routing.mjs +3 -3
  49. package/scripts/validate-sandbox-install.mjs +138 -0
  50. package/scripts/versioning.mjs +13 -1
  51. package/scripts/vision-status.mjs +682 -0
  52. package/skills-lock.json +8 -8
  53. package/src/agents/aphrodite.md +20 -37
  54. package/src/agents/apollo.md +7 -3
  55. package/src/agents/athena.md +63 -35
  56. package/src/agents/demeter.md +8 -28
  57. package/src/agents/gaia.md +1 -1
  58. package/src/agents/hephaestus.md +10 -21
  59. package/src/agents/hermes.md +15 -38
  60. package/src/agents/iris.md +7 -1
  61. package/src/agents/mnemosyne.md +18 -54
  62. package/src/agents/nyx.md +1 -1
  63. package/src/agents/prometheus.md +16 -20
  64. package/src/agents/talos.md +10 -2
  65. package/src/agents/themis.md +5 -5
  66. package/src/agents/zeus.md +99 -172
  67. package/src/instructions/agent-return-format.instructions.md +34 -17
  68. package/src/instructions/backend-standards.instructions.md +2 -0
  69. package/src/instructions/frontend-standards.instructions.md +3 -1
  70. package/src/instructions/memory-protocol.instructions.md +12 -110
  71. package/src/instructions/test-economy.instructions.md +21 -0
  72. package/src/instructions/zeus-anti-stall.instructions.md +20 -67
  73. package/src/instructions/zeus-communication-rules.instructions.md +0 -1
  74. package/src/instructions/zeus-council-synthesis.instructions.md +31 -260
  75. package/src/instructions/zeus-memory-operations.instructions.md +30 -0
  76. package/src/instructions/zeus-timeout-retry.instructions.md +61 -89
  77. package/src/mcp/{code_mode_server.py → code_mode.py} +3 -3
  78. package/src/mcp/eval_store.py +2 -2
  79. package/src/mcp/{mcp_persistence_server.py → mcp_persistence.py} +52 -17
  80. package/{scripts/mcp_resources_server.py → src/mcp/mcp_resources.py} +2 -2
  81. package/src/mcp/{memory_mcp_server.py → memory_mcp.py} +2 -2
  82. package/src/mcp/{pantheon_vision_server.py → pantheon_vision.py} +286 -42
  83. package/src/mcp/requirements-mcp.txt +6 -4
  84. package/src/mcp/requirements-vision.txt +2 -2
  85. package/src/pantheon/cost-command.ts +403 -102
  86. package/src/pantheon/delegation-enforce.ts +10 -1
  87. package/src/pantheon/model-agents.ts +19 -0
  88. package/src/pantheon/model-command.ts +218 -56
  89. package/src/pantheon/presets.d.mts +0 -8
  90. package/src/pantheon/presets.mjs +5 -32
  91. package/src/pantheon/v2-bounded-read.ts +640 -0
  92. package/src/pantheon/v2-delegation-enforce.ts +214 -0
  93. package/src/pantheon/v2-execute-after.ts +186 -0
  94. package/src/pantheon/v2-model-overrides.ts +275 -0
  95. package/src/pantheon/v2-tools.ts +418 -0
  96. package/src/pantheon/v2-unsupported.d.mts +11 -0
  97. package/src/pantheon/v2-unsupported.mjs +90 -0
  98. package/src/pantheon/v2-vision.ts +622 -0
  99. package/src/pantheon/vision-local.ts +531 -0
  100. package/src/pantheon/vision.ts +1160 -115
  101. package/src/plugin-v2.ts +1158 -219
  102. package/src/plugin.ts +12 -9
  103. package/src/plugins/tui/dist/server.d.ts +1 -2
  104. package/src/plugins/tui/dist/server.d.ts.map +1 -1
  105. package/src/plugins/tui/dist/tui-v2.d.ts +154 -0
  106. package/src/plugins/tui/dist/tui-v2.d.ts.map +1 -0
  107. package/src/plugins/tui/dist/tui-v2.js +659 -0
  108. package/src/plugins/tui/dist/tui-v2.js.map +1 -0
  109. package/src/plugins/tui/dist/tui.d.ts +85 -82
  110. package/src/plugins/tui/dist/tui.d.ts.map +1 -1
  111. package/src/plugins/tui/dist/tui.js +72 -59
  112. package/src/plugins/tui/index-v2.ts +6 -0
  113. package/src/plugins/tui/package-lock.json +5516 -1353
  114. package/src/plugins/tui/package.json +22 -12
  115. package/src/plugins/tui/src/index-v2.tsx +734 -0
  116. package/src/plugins/tui/src/index.tsx +106 -85
  117. package/src/plugins/tui/src/opencode-v2.d.ts +13 -0
  118. package/src/plugins/tui/tsconfig.build.json +5 -0
  119. package/src/plugins/tui/tsconfig.typecheck.json +5 -0
  120. package/src/plugins/tui/tsdown.config.ts +22 -2
  121. package/src/plugins/tui/tui-v2.ts +2 -0
  122. package/src/plugins/tui/tui.ts +3 -0
  123. package/src/routing.yml +11 -21
  124. package/src/skills/README.md +3 -3
  125. package/src/skills/agent-coordination/SKILL.md +7 -2
  126. package/src/skills/artifact-management/SKILL.md +12 -5
  127. package/src/skills/auto-continue/SKILL.md +52 -35
  128. package/src/skills/code-review-checklist/SKILL.md +5 -5
  129. package/src/skills/context-compression/SKILL.md +26 -879
  130. package/src/skills/session-goal/SKILL.md +14 -5
  131. package/src/skills/spec-driven-development/SKILL.md +3 -1
  132. package/src/skills/tdd-with-agents/SKILL.md +18 -10
  133. package/opencode.json +0 -58
@@ -1,132 +1,100 @@
1
1
  ---
2
2
  description: "Timeout enforcement, retry policies, subtask dispatch, and timeout tracking for Zeus"
3
3
  name: "Zeus Timeout & Retry"
4
- applyTo: "agents/zeus.agent.md"
4
+ agents: [zeus]
5
+ fallback: shared
5
6
  ---
6
7
 
7
8
  # ⏱️ TIMEOUT & RETRY ENFORCEMENT
8
9
 
9
10
  When a delegated agent does not respond in time, enforce the timeout policy from `routing.yml`.
10
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
+
11
19
  ## Timeout Behavior by Agent Role
12
20
 
13
- | Agent Role | Timeout | Retry Policy | Fallback Chain | Partial Results OK? | Reasoning Effort |
14
- |------------|---------|-------------|----------|---------------------|------------------|
15
- | Explorer (@apollo) | 60s | 2 retries, exp backoff | @athena (plan) → @hermes (impl) | ✅ Yes | low |
16
- | Implementer (@hermes, @aphrodite, @demeter) | 180s | 3 retries, exp backoff | @talos (hotfix) → @athena (replan) | ❌ No | medium |
17
- | Reviewer (@themis) | 120s | 3 retries, exp backoff | @zeus (escalate) → user | ❌ No | high |
18
- | Infrastructure (@prometheus) | 300s | 3 retries, exp backoff | @hermes (config) → @zeus (escalate) | ❌ No | medium |
19
- | Hotfix (@talos) | 30s | 2 retries, no backoff | @hermes (full fix) | ✅ Yes | low |
20
- | Remote Sensing (@gaia) | 120s | 2 retries, exp backoff | @hermes (generic) | ✅ Yes | high |
21
+ | Agent Role | Timeout | Retry Policy | Partial Results OK? | Reasoning Effort |
22
+ |------------|---------|--------------|---------------------|------------------|
23
+ | Explorer (@apollo) | 60s | 1 retry | ✅ Yes | low |
24
+ | Implementer (@hermes, @aphrodite, @demeter) | 180s | 1 retry | ❌ No | medium |
25
+ | Reviewer (@themis) | 120s | 1 retry | ❌ No | high |
26
+ | Infrastructure (@prometheus) | 300s | 1 retry | ❌ No | medium |
27
+ | Hotfix (@talos) | 30s | 1 retry | ✅ Yes | low |
28
+ | Remote Sensing (@gaia) | 120s | 1 retry | ✅ Yes | high |
21
29
 
22
30
  ## Retry Flow
23
31
 
24
32
  ```
25
- Task dispatch → timeout elapsed → log timeout
26
- ├─ retry_count > 0 → retry with exponential backoff → decrement retry_count
27
- │ └─ still failing? → retry again (up to retry_count limit)
28
- │
29
- ├─ retries exhausted → FALLBACK CHAIN:
30
- │ ├─ fallback[0] exists? → dispatch to fallback agent
31
- │ │ └─ keep original task spec + context; add error context
32
- │ ├─ fallback[1] exists? → dispatch to second fallback
33
- │ └─ all fallbacks failed? → ESCALATE
34
- │
35
- ├─ no fallbacks defined → return TIMEOUT error to user
36
- │
37
- └─ ESCALATE: "Agent X failed after N retries. Fallbacks Y, Z also failed.
38
- Options: (a) try different agent, (b) simplify scope, (c) manual"
33
+ Initial attempt → timeout/failure → log it → make at most one retry
34
+ └─ retry fails → try fallback agents left-to-right with original task/context
35
+ └─ all fallbacks fail (or none exist) → report the chain and escalate
39
36
  ```
37
+ `background_delegation.retry_count: 1` means one retry after the initial attempt, not one total attempt. Never restart an exhausted chain automatically.
40
38
 
41
-
39
+ Apply the retry only to a transient dispatch failure (timeout, crash, or empty response). A failed test, validation, or migration is a result to diagnose, not a reason to repeat the same command or agent blindly. Track agents already tried: each agent may be retried at most once and each listed fallback may be tried at most once. For auth/security/data/schema work, a fallback must preserve specialist competence, Themis review, and human approval; otherwise stop and escalate. Never let full-auto bypass these gates.
40
+ An agent refusal or scope-boundary response is not a transient failure: do not retry it with a rephrased prompt. Correct the route once if the right specialist is clear; otherwise stop and ask.
42
41
 
43
42
  ## Fallback Chain Definitions
44
43
 
45
- Each fallback chain is evaluated left-to-right: if the first fallback fails, try the second, etc.
46
-
47
- | Agent | Fallback[0] | Fallback[1] | Escalate To |
48
- |-------|------------|------------|-------------|
49
- | @apollo | @athena (plan scoped task) | @hermes (implement search) | @zeus |
50
- | @hermes | @talos (minimal fix) | @athena (replan + simplify) | @zeus |
51
- | @aphrodite | @talos (CSS/UX fix) | @hermes (generic fallback) | @zeus |
52
- | @demeter | @hermes (generic backend) | @athena (replan schema) | @zeus |
53
- | @themis | @zeus (direct escalation) | — | user |
54
- | @prometheus | @hermes (config/deploy) | @zeus | user |
55
- | @talos | @hermes (full implementation) | — | @zeus |
56
- | @hephaestus | @nyx (observability debug) | @hermes (generic) | @zeus |
57
- | @nyx | @hermes (generic) | — | @zeus |
58
- | @iris | @zeus (manual override) | — | user |
59
- | @mnemosyne | @zeus (manual) | — | user |
44
+ `routing.yml` → `fallback_chains` is the canonical agent-by-agent mapping. Evaluate
45
+ the configured chain left-to-right; if an agent has no configured chain, stop
46
+ and escalate rather than guessing a fallback. Each listed fallback may be tried
47
+ at most once, and an exhausted chain is never restarted automatically.
60
48
 
61
- ### Escalation Protocol
62
- When ALL fallbacks fail:
63
- 1. Log the full failure chain: which agents were tried, what error each returned
64
- 2. Report to user: "Task [X] failed. Tried: [agent list]. Error: [summary]."
65
- 3. Offer options: (a) try different approach, (b) simplify scope, (c) manual fix
66
- 4. NEVER retry the same chain automatically — break the cycle
49
+ ### Refusal Is a Routing Error
67
50
 
68
- ### Session Reuse Check
69
- Before dispatching a task, check if a reusable session exists:
51
+ For a domain/scope refusal, do not retry with a rephrased prompt. Correct the
52
+ route once only when the right specialist is clear; otherwise stop and ask.
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.
70
57
 
71
- ```
72
- @hermes — continuing from previous session.
73
- Files already explored: backend/routers/auth.py, backend/services/auth_service.py.
74
- New task: add refresh token rotation.
75
- ```
58
+ ### Escalation Protocol
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.
76
60
 
77
- Use `session_max` from routing.yml to determine how many sessions to keep per agent.
61
+ ### Session Reuse Check
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.
78
65
 
79
66
  ---
80
67
 
81
68
  # 📦 SUBTASK DISPATCH (Lightweight Delegation)
82
69
 
83
- Subtask is a bounded, low-risk delegation mode that **skips** the standard artifact lifecycle. Use it for focused work that doesn't need Themis review.
70
+ Subtask is a bounded, low-risk delegation mode that **skips** the standard artifact lifecycle. Choose it by risk and need for review, not by a fixed file/line count.
84
71
 
85
72
  ## When to Use Subtask vs Full Task
86
73
 
87
- > **REGRA DE OURO:** Quando em dúvida, use full task. Subtask é para o que você tem 100% de certeza que é seguro pular revisão.
74
+ Use the lightest path that safely meets the request. A multi-file but bounded low-risk change does not automatically need a plan/artifact phase.
88
75
 
89
76
  ### Subtask Decision Tree (run BEFORE every delegation)
90
77
 
91
78
  ```
92
- □ Scope: ≤2 files AND ≤10 lines changed? [YES→continue | NO→full task]
93
- □ Risk: No schema change, no security impact? [YES→continue | NO→full task]
94
- □ Auth: No authentication/authorization logic? [YES→continue | NO→full task]
95
- □ Data: No data loss risk, no migration? [YES→continue | NO→full task]
96
- □ Review: Output does NOT feed into Themis review? [YES→continue | NO→full task]
97
-
98
- ALL YES → subtask (skip artifact + Themis)
99
- ANY NO → full task (IMPL artifact + Themis review mandatory)
100
- ```
101
-
102
- ### Comparison Table
103
-
104
- | Aspect | Subtask | Full Task |
105
- |--------|---------|-----------|
106
- | Scope | Single file, <10 lines, read-only | Feature, multi-file, schema change |
107
- | Risk | Low (no security/data implications) | Any risk level |
108
- | Artifact | ❌ No IMPL artifact | ✅ IMPL artifact required |
109
- | Themis review | ❌ None | ✅ Mandatory |
110
- | Use case | Apollo discovery, Talos hotfix, bounded fix | Feature implementation, migration, API change |
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]
111
82
 
112
- ### Concrete Examples
113
-
114
- | Task | Scope | Risk | Subtask? | Why |
115
- |------|-------|------|----------|-----|
116
- | Fix typo in CSS class | 1 file, 1 line | None | ✅ | Bounded, no security impact |
117
- | Add error handling to existing endpoint | 1 file, 5 lines | Low | ✅ | No schema change |
118
- | Implement login endpoint | 2+ files, 50+ lines | High (auth) | ❌ | Security-critical, needs Themis |
119
- | Database migration | 1 file, 15 lines | High (data) | ❌ | Data loss risk, needs rollback |
120
- | Apollo codebase search | 0 files | None | ✅ | Read-only investigation |
121
- | Update README | 1 file, 3 lines | None | ✅ | Documentation only |
83
+ ALL YES → one correct domain specialist; they inspect needed context, implement, and verify; no routine plan/artifact, separate discovery, council, or review
84
+ ANY NO → add only the planning, artifact, specialist review, and approval gates the risk requires
85
+ ```
122
86
 
123
87
  ### Safety Rules
124
- 1. **Bounded scope** — single file or read-only investigation
125
- 2. **Low risk** — no security implications, no data loss, no breaking changes
126
- 3. **No Themis dependency** — output doesn't feed into a phase that requires review
88
+ 1. **Bounded scope** — can be a small multi-file change or a read-only investigation
89
+ 2. **Low risk and uncertainty** — no security implications, data loss, breaking/user-visible API impact, broad material scope, or unresolved high uncertainty
90
+ 3. **No required Themis dependency** — sensitive/material output retains its review gate
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.
127
95
 
128
96
  ## Subtask Return Format
129
- Return the standard `## subtask_summary` defined in `## Agent Return Format` (files_changed, summary, tests, coverage, tokens, status, blockers).
97
+ Return the required `## subtask_summary` fields defined in `## Agent Return Format`; include `memory_context` when memory was used.
130
98
 
131
99
  ## Timeout Parcial (Partial Results)
132
100
 
@@ -136,4 +104,8 @@ Only agents marked ✅ in the Timeout Behavior table above may return partial re
136
104
 
137
105
  # 📊 TIMEOUT TRACKING
138
106
 
139
- 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.
@@ -5,12 +5,12 @@ Provides a confined execution environment for orchestration scripts
5
5
  via MCP tools and resources.
6
6
 
7
7
  Usage:
8
- python scripts/code_mode_server.py
8
+ python scripts/code_mode.py
9
9
 
10
10
  Or via MCP client (stdio transport):
11
11
  pantheon-code-mode:
12
12
  command: python
13
- args: ["scripts/code_mode_server.py"]
13
+ args: ["scripts/code_mode.py"]
14
14
  """
15
15
 
16
16
  from __future__ import annotations
@@ -36,7 +36,7 @@ from typing import Any
36
36
 
37
37
  import yaml
38
38
  from _pantheon_paths import pantheon_home, pantheon_project
39
- from mcp.server.fastmcp import FastMCP
39
+ from fastmcp import FastMCP
40
40
 
41
41
  # ── Constants ─────────────────────────────────────────────────────────────────
42
42
  ALLOWED_EXTENSIONS: frozenset[str] = frozenset({".sh", ".py"})
@@ -2,7 +2,7 @@
2
2
  """Plugin eval certification storage — ``plugin_eval`` memory namespace.
3
3
 
4
4
  Thin stdlib-only wrapper around the memory SQLite DB (same schema as
5
- ``src/mcp/memory_mcp_server.py``) for plugin-eval certification results.
5
+ ``src/mcp/memory_mcp.py``) for plugin-eval certification results.
6
6
 
7
7
  Namespace: ``plugin_eval``
8
8
  Key format: ``eval:<name>:<date>`` (e.g. ``eval:tdd-with-agents:2026-08-21``)
@@ -30,7 +30,7 @@ from typing import Any
30
30
 
31
31
  NAMESPACE = "plugin_eval"
32
32
 
33
- # Minimal schema — matches memory_mcp_server.SCHEMA_SQL for the memories
33
+ # Minimal schema — matches memory_mcp.SCHEMA_SQL for the memories
34
34
  # table (vec/FTS tables are initialized by the memory MCP server on first
35
35
  # run; eval entries remain readable via list/recall regardless).
36
36
  _SCHEMA_SQL = """
@@ -5,7 +5,7 @@ Key-Value store with FTS5 full-text search, TTL-based expiration,
5
5
  and namespace isolation. Uses SQLite with zero external dependencies.
6
6
 
7
7
  Usage:
8
- python scripts/mcp_persistence_server.py
8
+ python scripts/mcp_persistence.py
9
9
  """
10
10
 
11
11
  from __future__ import annotations
@@ -25,7 +25,7 @@ from pathlib import Path
25
25
  from typing import Annotated
26
26
 
27
27
  from _pantheon_paths import pantheon_home, pantheon_project
28
- from mcp.server.fastmcp import FastMCP
28
+ from fastmcp import FastMCP
29
29
  from pydantic import Field
30
30
 
31
31
  # ── Schema ──────────────────────────────────────────────────────────────────────
@@ -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: "
@@ -7,7 +7,7 @@ Provides MCP resources for the Pantheon agent framework:
7
7
  plans/status, memory-bank files
8
8
 
9
9
  Usage:
10
- python scripts/mcp_resources_server.py
10
+ python scripts/mcp_resources.py
11
11
  """
12
12
 
13
13
  from __future__ import annotations
@@ -19,7 +19,7 @@ from typing import Any
19
19
  import yaml
20
20
  from _pantheon_paths import has_symlink_component, pantheon_home, pantheon_project
21
21
  from eval_store import get_latest_eval, list_evals
22
- from mcp.server.fastmcp import FastMCP
22
+ from fastmcp import FastMCP
23
23
 
24
24
  # ── Path Resolution ──────────────────────────────────────────────────────────
25
25
  _PANTHEON_HOME: Path = pantheon_home()
@@ -19,7 +19,7 @@ Tools:
19
19
  memory_stats — DB statistics
20
20
 
21
21
  Usage:
22
- python scripts/memory_mcp_server.py
22
+ python scripts/memory_mcp.py
23
23
  """
24
24
 
25
25
  from __future__ import annotations
@@ -34,7 +34,7 @@ from pathlib import Path
34
34
  from typing import Annotated, Any
35
35
 
36
36
  from _pantheon_paths import pantheon_home
37
- from mcp.server.fastmcp import FastMCP
37
+ from fastmcp import FastMCP
38
38
  from pydantic import BeforeValidator, Field
39
39
 
40
40
  try: