pantheon-opencode 1.4.2 → 1.4.3

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
@@ -218,113 +218,28 @@ incompatible schema.
218
218
 
219
219
  ### Background Delegation
220
220
 
221
- Zeus (and other root sessions) can dispatch agents as **background child sessions**
222
- via three delegation tools, tracked on a persistent job board
223
- (`.pantheon/board/state.json`, 24h TTL) with reports written to
224
- `.pantheon/delegations/<parent>/<alias>.md`:
225
-
226
- | Tool | Signature | Behavior |
227
- |------|-----------|----------|
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
- | `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
- | `pantheon_delegation_list` | `{}` | Lists the current session's delegations with `[unread]` on finished, unreconciled jobs. |
231
-
232
- **Agent activity visibility.** While `pantheon_delegation_read` blocks on a
233
- running job, it samples the child session's messages every ~2s and appends the
234
- collected lines to the report as a trailing `## Agent Activity` section (latest
235
- tool calls with truncated args, or user/assistant text, capped at ~200 chars per
236
- line) — so you can see what the agent is doing during the wait. Likewise,
237
- `pantheon_delegation_list` shows a `last activity:` line for running jobs.
238
- Fail-open: if the child session messages are unavailable (or empty), the read
239
- returns the report exactly as before — the activity sampling never breaks the
240
- delegation read.
221
+ Zeus (and other root sessions) dispatch agents as **background child sessions**
222
+ via OpenCode's native `task(background=true, ...)` API. The plugin layer keeps a
223
+ persistent job board (`BackgroundJobBoard`, `.pantheon/board/state.json`, 24h
224
+ TTL) that tracks in-flight work and carries it forward across context
225
+ compaction, so a compacted session does not lose track of running delegations.
226
+
227
+ The plugin no longer ships a delegate toolset (`pantheon_delegate`,
228
+ `pantheon_delegation_read`, `pantheon_delegation_list` were removed in 1.4.3).
229
+ Dispatch and result collection use the native `task()` / `task_status()` API.
241
230
 
242
231
  **Completion visibility — zero chat noise.** Delegation notifications are never
243
232
  injected into the chat transcript: neither `chat.message` nor any other chat
244
233
  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.
234
+ terminal state, the plugin writes a file-only audit log line (echo opt-in via
235
+ `PANTHEON_HOOKS_LOG`). Completion visibility lives in the legitimate channels:
236
+ the board `[unread]` marker, TUI toasts (`PANTHEON_TOASTS` gate), and compaction
237
+ carry-forward. Reconcile is an acknowledgment, not a completion — it never
238
+ re-fires the terminal transition.
252
239
 
253
240
  **Timeout:** `background_delegation.timeout_ms` (default `900000` = 15 min). A job
254
241
  that has not reached a terminal state is finalized as `error`/`timedOut`.
255
242
 
256
- **Runtime delegation environment variables:**
257
-
258
- | Variable | Default | Scope and behavior |
259
- |---|---:|---|
260
- | `PANTHEON_ATHENA_APOLLO_BUDGET` | `5` dispatches | In-memory per `createDelegationTools()` factory/process instance and parent session, for the `athena → apollo` read-only exception. |
261
- | `PANTHEON_HERMES_APOLLO_BUDGET` | `5` dispatches | In-memory per `createDelegationTools()` factory/process instance and parent session, for the `hermes → apollo` read-only exception. |
262
- | `PANTHEON_DELEGATION_TIMEOUT_MS` | `900000` ms (15 min) | Per delegated child wall-clock timeout. The value is read when the plugin factory is created; unset or invalid values use the default. |
263
-
264
- Budgets are reserved before asynchronous child-session creation, so real
265
- concurrent calls cannot overshoot them. They reset when the factory/process
266
- restarts. If `ToolContext.agent` is missing, the default runtime matrix rejects
267
- the delegation (fail-closed); no caller identity or budget is inferred from the
268
- target, prompt, or session state. An explicitly legacy host using
269
- `enforceRuntimeMatrix: false` skips the budget because the caller cannot be
270
- identified and emits a warning. These budgets are separate from
271
- `background_delegation.max_concurrent_per_agent`: concurrency limits the number
272
- of currently running children, while an exception budget limits total dispatch
273
- reservations for that parent session during the factory lifetime.
274
-
275
- **Read-only enforcement:** delegating with `read_only: true`, or delegating to an
276
- agent in `background_delegation.read_only_agents` (`apollo`, `gaia`), registers
277
- the child session as read-only — the `tool.execute.before` guard denies
278
- `edit`/`write`/`bash`/`task` inside that session.
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
-
296
- **R1 — Per-error-type retry + provider cooldown (LiteLLM pattern):**
297
- `retry_policy` in `src/routing.yml` maps an error class (`auth`, `rate_limit`,
298
- `timeout`, `other`) to max retries before escalating — `auth` is never retried
299
- (0), `rate_limit` gets 3, `timeout` 2, `other` 1. Retries use exponential
300
- backoff (base 1s, doubling, capped 30s). `cooldown` (`allowed_fails`,
301
- `cooldown_time_seconds`) skips a provider for the configured window after that
302
- many consecutive failures; a success resets the counter. Enforcement lives in
303
- `RetryPolicyEngine` (`src/pantheon/retry-policy.ts`) and the R1 path of
304
- `zeusDelegateWithRetry` (`src/pantheon/zeus-delegate-with-retry.ts`) — pass
305
- `retryPolicy`/`cooldown`/`provider` to `createZeusRetryHelper`. In-memory only
306
- (no Redis).
307
-
308
- **R4 — Per-agent step caps:** `agents.<name>.max_steps` in `src/routing.yml`
309
- gives each agent a step budget (e.g. `apollo: 25`, `themis: 25`, `athena: 15`).
310
- When an agent reaches `max_steps` it is forced to summarize-and-stop: a
311
- delegation to an already-capped agent is skipped with a `[STEP CAP REACHED]`
312
- summary (no child session created), and a dispatch that hits the cap appends a
313
- stop instruction to the prompt. Enforcement: `StepCapTracker`
314
- (`src/pantheon/step-cap.ts`) wired into `pantheon_delegate`. The tracker is
315
- **permanent-per-process** — counters accumulate for the process lifetime and
316
- are intentionally not reset on success/session end (a per-session reset would
317
- let an agent exceed its process budget).
318
-
319
- **O5 — Permission globs for delegation:** `permission.task` in `src/routing.yml`
320
- controls which subagents an agent may invoke via glob patterns (last matching
321
- rule wins). A deny removes the agent from the delegate tool description
322
- entirely (not just blocks the call) — preventing circular delegation at the
323
- permission layer. Default `"*": allow` keeps the existing runtime matrix
324
- (zeus → anyone; athena/hermes → apollo only). Enforcement:
325
- `src/pantheon/permission-globs.ts` + the `permissionTask` option on
326
- `createDelegationTools` / `createEnforcementGuard`.
327
-
328
243
  **Compaction carry-forward:** during context compaction, running and unread
329
244
  terminal delegations (capped at `background_delegation.max_compaction_items`,
330
245
  default 10) are carried into the compacted context so the parent doesn't lose
@@ -353,8 +268,7 @@ logged warn and pass-through.
353
268
 
354
269
  **Post-compaction state re-assertion (1.3.4):** on `session.compacted`, fresh
355
270
  state — running/unread delegations from the board + active goals, capped at 10
356
- lines — remains available through compaction carry-forward and the board
357
- (`pantheon_delegation_list` / `pantheon_delegation_read`). A session with
271
+ lines — remains available through compaction carry-forward. A session with
358
272
  nothing to assert is a silent skip; no chat transcript injection is performed.
359
273
 
360
274
  **Preemptive compaction check (1.3.4):** a pure threshold core
@@ -378,8 +292,8 @@ omits the child model.
378
292
  **Delegation log hygiene (1.3.4):** `delegations.log` now records the real
379
293
  `task_id` (omitted when empty, never `""`) and a **numeric** `duration_ms`
380
294
  (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.
295
+ file-only audit entries; completion is surfaced by TUI toast (when enabled)
296
+ and the board — never by chat delivery.
383
297
 
384
298
  **Env vars & config:**
385
299
 
@@ -387,14 +301,13 @@ the board, and the list/read tools — never by chat delivery.
387
301
  - `PANTHEON_TOASTS` — TUI toast gate for the delegation lifecycle signals.
388
302
  Default `{errors, delegations, council}`; `PANTHEON_TOASTS=off` disables all
389
303
  TUI toasts (delegation signals then only surface via the board `[unread]`
390
- marker, `pantheon_delegation_read` and the on-disk audit log — never via
391
- chat.message injection from the plugin).
304
+ marker and the on-disk audit log — never via chat.message injection from the
305
+ plugin).
392
306
  - `background_delegation` section in `src/routing.yml` — `timeout_ms`,
393
- `poll_ms`, `max_compaction_items`, `prune_ttl_ms`, `read_only_agents`,
394
- `session_max`, `retry_count`.
307
+ `poll_ms`, `max_compaction_items`, `prune_ttl_ms`, `session_max`,
308
+ `retry_count`.
395
309
 
396
- See `src/agents/zeus.md` for the agent-facing delegation protocol and
397
- `src/pantheon/delegation.ts` for the tool implementations.
310
+ See `src/agents/zeus.md` for the agent-facing delegation protocol.
398
311
 
399
312
  ### Real-time Delegations panel (1.3.4)
400
313
 
@@ -402,7 +315,7 @@ The TUI sidebar ships a live **Delegations** panel (open by default, above the
402
315
  collapsed Sessions list). Its primary source is `api.client.session.children`,
403
316
  so it shows **both** kinds of background work in one place:
404
317
 
405
- - **`pantheon_delegate` children** — rendered with their board alias tag
318
+ - **Board-tracked children** — rendered with their board alias tag
406
319
  (`[apo-1]`) and enriched from the `.pantheon/delegations/` report.
407
320
  - **Native `task()` children** — rendered with a distinct `[task]` tag (info
408
321
  color) when no board report exists for the session.
@@ -674,7 +587,7 @@ and is pinned to concrete `provider/model` IDs in [src/routing.yml](src/routing.
674
587
  The abstract tiers above are pinned to concrete `provider/model` IDs by **4 built-in model presets**.
675
588
  Cada preset mapeia os 14 agentes para um modelo específico + `reasoning_effort` por papel (planners/reviewers, implementers, scouts).
676
589
 
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.
590
+ > **Default = herdar do chat (sem `active-preset.json`)** — sem preset ativo, os delegates **herdam nativamente** o modelo do chat pai. 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: 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
591
 
679
592
  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
593
 
@@ -1141,16 +1054,15 @@ Use the isolated sandbox (`~/pantheon-sandbox/`) — **never** the dev environme
1141
1054
  **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`.
1142
1055
 
1143
1056
  **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
1057
+ TUI toasts (when enabled) and the board's `[unread]` marker. Ask something
1146
1058
  that dispatches subagents (e.g. *"dispare 2 subagentes apollo em paralelo para
1147
1059
  listar arquivos e comparar resultados"*) and expect:
1148
1060
 
1149
1061
  - A TUI toast with `🚀 apollo em execução` / `✅ apollo concluiu` when
1150
1062
  `PANTHEON_TOASTS` permits it
1151
- - `[unread]` in `pantheon_delegation_list` until the terminal result is read
1063
+ - `[unread]` on the board until the terminal result is read
1152
1064
  - 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
1153
- - With `export PANTHEON_TOASTS=off` before starting OpenCode: no toasts; board/list/read and audit-log visibility remain available
1065
+ - With `export PANTHEON_TOASTS=off` before starting OpenCode: no toasts; board and audit-log visibility remain available
1154
1066
 
1155
1067
  ### Pre-commit hooks (local secret gate)
1156
1068
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pantheon-opencode",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "description": "Multi-agent orchestration for OpenCode — 14 specialized agents, TDD, Themis review gates.",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -144,33 +144,23 @@ task_status(task_id="ses_xxx", wait=true)
144
144
  -> bloqueia ate completar: { state: "completed", task_result: "..." }
145
145
  ```
146
146
 
147
- ### Pantheon Delegation Tools (plugin) — 3-tool API
147
+ ### Pantheon Delegation — BackgroundJobBoard (plugin)
148
148
 
149
- O plugin Pantheon adiciona 3 tools de delegacao gerenciada pelo BackgroundJobBoard:
149
+ O plugin Pantheon mantém um **BackgroundJobBoard** persistente
150
+ (`.pantheon/board/state.json`) que rastreia trabalho em voo e o carrega para o
151
+ contexto de compactação. O toolset de delegação do plugin
152
+ (`pantheon_delegate`, `pantheon_delegation_read`, `pantheon_delegation_list`)
153
+ foi **removido em 1.4.3** — dispatch e coleta usam a API nativa
154
+ `task(background=true)` / `task_status(wait=true)`.
150
155
 
151
- ```
152
- pantheon_delegate({prompt, agent, description?, read_only?})
153
- -> cria sessao filha, registra no board, retorna alias: [apo-1]
154
- pantheon_delegation_read({id: "apo-1"})
155
- -> BLOQUEIA ate o job terminar, retorna o report markdown, marca reconciled
156
- -> durante a espera, mostra o que o agente esta fazendo: seccao final "## Agent Activity"
157
- (amostra as messages do child a cada ~2s; tool calls + args truncados / texto)
158
- pantheon_delegation_list()
159
- -> lista jobs da sessao, com [unread] para jobs terminados nao lidos
160
- -> jobs RUNNING mostram "last activity:" (ultima acao visivel do child)
161
- -> fail-open: sem suporte a messages, formato atual inalterado
162
- ```
163
-
164
- - **Read-only enforcement:** agentes read-only (apollo, gaia — `read_only_agents` no routing.yml) tem `edit`, `write`, `bash`, `task` NEGADOS dentro da sessao delegada (o guard de `tool.execute.before` THROW com mensagem acionavel). Use `read_only: true` no delegate para qualquer agente de investigacao.
165
- - **Depth-2 hard-enforced:** sessao read-only NAO cria subagentes (`task` bloqueado) — investigacao nunca vira arvore.
166
156
  - **Compactacao:** jobs em voo (running + unread terminal) sao injetados no contexto de compactacao via `experimental.session.compacting` — delegacao em andamento nao se perde ao compactar.
167
157
 
168
- ### DELEGATION_RULES (plugin path)
158
+ ### DELEGATION_RULES (native task path)
169
159
 
170
- 1. **NUNCA** polle `pantheon_delegation_list` para checar se um job terminou.
171
- 2. Voce NAO recebe notificacao injetada no chat — politica do usuario: ZERO `task-notification` no transcript. Visibilidade de conclusao: marcador `[unread]` em `pantheon_delegation_list`, `pantheon_delegation_read({id})`, toasts TUI (pantheon-hooks) e carry-forward de compactacao.
172
- 3. Use `pantheon_delegation_read({id})` APENAS para fan-in explicito / recuperacao de resultado sob demanda (bloqueia ate o fim).
173
- 4. `pantheon_delegation_list` e para diagnostico, nao para polling.
160
+ 1. **NUNCA** polle `task_status` para checar se um job terminou — use `wait=true` para fan-in explicito.
161
+ 2. Voce NAO recebe notificacao injetada no chat — politica do usuario: ZERO `task-notification` no transcript. Visibilidade de conclusao: marcador `[unread]` no board, toasts TUI (pantheon-hooks) e carry-forward de compactacao.
162
+ 3. Use `task_status({task_id, wait: true})` APENAS para fan-in explicito / recuperacao de resultado sob demanda (bloqueia ate o fim).
163
+ 4. `task_status` sem `wait` e para diagnostico, nao para polling.
174
164
 
175
165
  ### Background (sempre usar)
176
166
  - **Apollo, Hermes, Aphrodite, Demeter, Hephaestus, Prometheus**
@@ -324,9 +314,8 @@ out = await guard.maybeRetry(result, async () => { ...task() de novo... })
324
314
  Regra: retry 1x APENAS em `empty-mode1`/`empty-mode2`. Resultado com conteudo
325
315
  nunca redispara. Apos 1 retry vazio → escalate (mesma regra do TODO Enforcer).
326
316
 
327
- > **Waves DEVEM usar `zeusDelegateWithRetry`** (`src/pantheon/zeus-delegate-with-retry.ts`) — encapsula `delegate → waitForTerminal → classify → retry 1x → escalate` com cap duro 1; se ainda vazio throw `ZeusEscalationError` (escale: tente outro agente, simplifique, manual).
328
- > Uso alto-nível: `import { zeusDelegateWithRetry } from './pantheon/zeus-delegate-with-retry.ts'` → `await zeusDelegateWithRetry({ board, client, sessionID, agent, prompt })`.
329
- > Uso baixo-nível: `createZeusRetryHelper().executeWithRetry(first, () => secondRead())` — classifica empty e decide retry/escalate (mesmo cap 1).
317
+ > **Waves DEVEM usar `dispatch-guard`** (`src/pantheon/dispatch-guard.ts`) — encapsula `task → classify → retry 1x → escalate` com cap duro 1; se ainda vazio throw `ZeusEscalationError` (escale: tente outro agente, simplifique, manual).
318
+ > Uso alto-nível: `import { createDispatchGuard } from './pantheon/dispatch-guard.ts'` → `await guard.maybeRetry(result, () => task(...))`.
330
319
 
331
320
  ### /cost — pantheon_cost tool (WIRED no plugin)
332
321
  `pantheon_cost({ days?: number })` le o `opencode.db` READ-ONLY (node:sqlite;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Cost Command (Wave 4, PR #46) — `pantheon_cost` structural tool: cost +
3
- * token visibility for delegation traffic, straight from opencode.db.
3
+ * token visibility by agent, straight from opencode.db.
4
4
  *
5
5
  * Reads the opencode session database READ-ONLY (sum cost + tokens by
6
6
  * agent over the last N days → markdown table). Zero new dependencies:
@@ -13,8 +13,8 @@
13
13
  * dbPath resolution: explicit option > env PANTHEON_COST_DB > the version-aware
14
14
  * default selected by PANTHEON_OPENCODE_VERSION (v1 or v2). An unset version
15
15
  * deliberately preserves V1 behavior. The tool is wired in
16
- * plugin.ts alongside the delegation toolset (usable by zeus and any agent
17
- * with tool access — no routing change needed).
16
+ * plugin.ts (usable by zeus and any agent with tool access — no routing change
17
+ * needed).
18
18
  *
19
19
  * @module cost-command
20
20
  */
@@ -25,7 +25,7 @@ import { join } from 'node:path'
25
25
  import { promisify } from 'node:util'
26
26
  import { z } from 'zod'
27
27
 
28
- import type { ToolContextLike } from './delegation.ts'
28
+ import type { ToolContextLike } from './tool-context.ts'
29
29
 
30
30
  const execFileAsync = promisify(execFile)
31
31
 
@@ -44,7 +44,7 @@ export interface CostCommandOptions {
44
44
 
45
45
  export type OpenCodeVersion = 'v1' | 'v2'
46
46
 
47
- /** One cost tool: description + zod args shape + execute (delegation.ts shape). */
47
+ /** One cost tool: description + zod args shape + execute. */
48
48
  export interface CostTool<Args extends z.ZodRawShape = typeof costArgs> {
49
49
  description: string
50
50
  args: Args
@@ -62,7 +62,7 @@ const costArgs = {
62
62
  .min(1)
63
63
  .max(365)
64
64
  .optional()
65
- .describe('Number of days of delegation history to include (default 7).'),
65
+ .describe('Number of days of cost history to include (default 7).'),
66
66
  } satisfies z.ZodRawShape
67
67
 
68
68
  /** Return the safe, isolated state DB name for an OpenCode version. */
@@ -239,7 +239,7 @@ export function createCostCommand(options?: CostCommandOptions): CostCommand {
239
239
  return {
240
240
  pantheon_cost: {
241
241
  description:
242
- 'Report delegation cost + token usage by agent over the last N days, read from opencode.db (read-only, no writes).',
242
+ 'Report cost + token usage by agent over the last N days, read from opencode.db (read-only, no writes).',
243
243
  args: costArgs,
244
244
  execute,
245
245
  },
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Read-Only Enforcement (Phase 4) — deny mutating tools inside sessions that
3
- * were delegated as read-only (advisory `read_only: true` on
4
- * pantheon_delegate, or the agent ∈ `readOnlyAgents` from routing.yml).
3
+ * were delegated as read-only (advisory `read_only: true` on the native
4
+ * `task` delegate, or the agent ∈ `readOnlyAgents` from routing.yml).
5
5
  *
6
6
  * OpenCode hook: `tool.execute.before`. The hook shape is
7
7
  * `(input, output) => Promise<void>`; THROWING from the hook denies the tool
@@ -18,11 +18,11 @@
18
18
  * - `task` is blocked too, which hard-enforces depth-2: a read-only agent
19
19
  * cannot spawn its own subagents.
20
20
  *
21
- * Unknown sessions are allowed for ordinary tools. Delegation tools are
22
- * fail-closed when the runtime matrix is wired: missing agent identity or
21
+ * Unknown sessions are allowed for ordinary tools. The runtime matrix is
22
+ * fail-closed when wired: missing agent identity or
23
23
  * target metadata is denied rather than inferred.
24
24
  *
25
- * The registry is populated by delegation.ts at delegate time: the CHILD
25
+ * The registry is populated at delegate time: the CHILD
26
26
  * session is registered when the delegate call is read-only.
27
27
  *
28
28
  * @module delegation-enforce
@@ -147,7 +147,6 @@ export function isDelegationAllowed(
147
147
  function targetFromTool(tool: string, args: unknown): string | undefined {
148
148
  if (args === null || typeof args !== 'object') return undefined
149
149
  const record = args as Record<string, unknown>
150
- if (tool === 'pantheon_delegate') return normalizeDelegationAgent(record.agent)
151
150
  if (tool === 'task') {
152
151
  return normalizeDelegationAgent(record.subagent_type ?? record.subagentType)
153
152
  }
@@ -236,7 +235,7 @@ export function zeusReadGuard(tool: string, args: unknown, agent: string | undef
236
235
  // ─── Registry ──────────────────────────────────────────────────────────
237
236
 
238
237
  /**
239
- * Read-only session registry. `createDelegationTools` registers child
238
+ * Read-only session registry. The plugin's delegate wiring registers child
240
239
  * sessions here; the plugin's `tool.execute.before` guard consults it.
241
240
  * Process-wide singleton for plugin wiring + factory for test isolation.
242
241
  */
@@ -291,19 +290,19 @@ export function createEnforcementGuard(input: {
291
290
  options?: EnforcementGuardOptions
292
291
  }): ToolExecuteBeforeHandler {
293
292
  const blockedTools = input.options?.blockedTools ?? DEFAULT_BLOCKED_TOOLS
294
- const prefix = input.options?.messagePrefix ?? 'pantheon_delegate guard'
293
+ const prefix = input.options?.messagePrefix ?? 'delegation guard'
295
294
 
296
295
  return async (hook: ToolExecuteBeforeInput, output?: ToolExecuteBeforeOutput): Promise<void> => {
297
- const isDelegationTool = hook.tool === 'task' || hook.tool === 'pantheon_delegate'
296
+ const isDelegationTool = hook.tool === 'task'
298
297
  if (isDelegationTool && input.options?.isChildSession?.(hook.sessionID) === true) {
299
298
  throw new Error(
300
299
  `${prefix}: session ${hook.sessionID} is a child session — delegation tools are denied ` +
301
300
  'to prevent nested delegation',
302
301
  )
303
302
  }
304
- // pantheon_delegate has the authoritative ToolContext.agent at execution
305
- // time, so its matrix check lives in delegation.ts. The hook only has the
306
- // session-scoped agent learned from chat.params for native task().
303
+ // The native task() delegate has the authoritative ToolContext.agent at
304
+ // execution time, so its matrix check lives in dispatch-guard.ts. The hook
305
+ // only has the session-scoped agent learned from chat.params.
307
306
  if (
308
307
  hook.tool === 'task' &&
309
308
  input.options?.isRootSession !== undefined &&
@@ -336,7 +335,7 @@ export function createEnforcementGuard(input: {
336
335
  `This session was delegated for investigation only (read-only agent); it cannot ` +
337
336
  `modify files, run commands, or spawn subagents. ` +
338
337
  `If a write result is needed, dispatch a write-capable agent ` +
339
- `(e.g. hermes, aphrodite) with pantheon_delegate instead.`,
338
+ `(e.g. hermes, aphrodite) with the native task() tool instead.`,
340
339
  )
341
340
  }
342
341
  }
@@ -17,11 +17,11 @@
17
17
  import { z } from 'zod'
18
18
 
19
19
  import type { BackgroundJobBoard } from './background-job-board.ts'
20
- import type { ToolContextLike } from './delegation.ts'
21
20
  import { GoalStore } from './goal-store.ts'
22
21
  import { createPantheonLogger } from './logger.ts'
23
22
  import { safeSessionPath } from './session-guard.ts'
24
23
  import type { TodoEnforcerMessage } from './todo-enforcer.ts'
24
+ import type { ToolContextLike } from './tool-context.ts'
25
25
 
26
26
  // Silence-by-default TUI policy (pantheon-hooks L42-58): warn → hooks.log,
27
27
  // console echo opt-in via PANTHEON_HOOKS_LOG=1. `deps.logger` stays for tests.
@@ -103,7 +103,7 @@ const goalUpdateArgs = {
103
103
 
104
104
  const goalGetArgs = {} satisfies z.ZodRawShape
105
105
 
106
- /** One structural goal tool: description + zod args shape + execute (delegation.ts shape). */
106
+ /** One structural goal tool: description + zod args shape + execute. */
107
107
  export type GoalTool<Args extends z.ZodRawShape> = {
108
108
  description: string
109
109
  args: Args
@@ -15,7 +15,7 @@
15
15
  import { mkdir, readFile, rename, writeFile } from 'node:fs/promises'
16
16
  import { join } from 'node:path'
17
17
 
18
- import { assertSafeParentSessionID } from './delegation-finalize.ts'
18
+ import { assertSafeParentSessionID } from './tool-context.ts'
19
19
 
20
20
  export type GoalStatus = 'pending' | 'in_progress' | 'done'
21
21
 
@@ -2,8 +2,8 @@
2
2
  * Hashline edit tool (Wave 2, PR #46) — structural `hashline_edit` tool that
3
3
  * anchors edits to stable sha256 content tags instead of fragile line numbers.
4
4
  *
5
- * Tool shape matches the delegation tools (`{description, args, execute}`,
6
- * zod-validated — same import pattern as delegation.ts).
5
+ * Tool shape follows the plugin tool convention (`{description, args, execute}`,
6
+ * zod-validated) used across the Pantheon toolset.
7
7
  *
8
8
  * Safety model (council-approved):
9
9
  * 1. ALL refs are validated against the ORIGINAL file snapshot BEFORE any