@aeondave/pi-persona 1.17.0 → 1.17.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/AGENTS.md +79 -29
- package/CHANGELOG.md +264 -0
- package/README.md +27 -12
- package/agents/architect.md +21 -0
- package/agents/balthasar.md +17 -22
- package/agents/casper.md +17 -23
- package/agents/evidence-verifier.md +31 -16
- package/agents/melchior.md +17 -22
- package/agents/operator.md +15 -55
- package/agents/research.md +14 -48
- package/agents/reviewer.md +20 -39
- package/agents/scout.md +14 -15
- package/agents/verifier.md +15 -16
- package/docs/ARCHITECTURE.md +223 -57
- package/docs/EXPERIENCE.md +19 -9
- package/docs/MONITORS.md +62 -3
- package/docs/REFERENCE.md +189 -35
- package/docs/SPINE.md +2 -2
- package/docs/STRATEGIES.md +23 -8
- package/docs/TELEMETRY.md +1 -0
- package/flows/deep-review.flow.json +1 -1
- package/package.json +9 -8
- package/personas/audit.md +28 -17
- package/personas/dev.md +30 -32
- package/personas/elite.md +223 -221
- package/personas/judge.md +25 -19
- package/personas/magi.md +26 -29
- package/personas/planner.md +31 -24
- package/personas/researcher.md +25 -26
- package/personas/swarm.md +35 -25
- package/personas/verify.md +30 -19
- package/src/agents/agent.ts +20 -0
- package/src/bridge.ts +3 -2
- package/src/core/brief.ts +429 -356
- package/src/core/config.ts +16 -11
- package/src/core/model-catalog.ts +171 -0
- package/src/core/model-tier.ts +89 -0
- package/src/core/models.ts +13 -4
- package/src/core/monitor-output.ts +85 -0
- package/src/core/monitor.ts +34 -2
- package/src/core/nudge.ts +176 -23
- package/src/core/seed.ts +99 -6
- package/src/core/session-runs.ts +87 -0
- package/src/core/settings.ts +251 -0
- package/src/core/timer.ts +34 -9
- package/src/engine/adapter.ts +12 -8
- package/src/engine/async.ts +195 -136
- package/src/engine/child.ts +1 -1
- package/src/engine/host-module.ts +12 -0
- package/src/engine/inproc.ts +11 -6
- package/src/engine/stream.ts +3 -0
- package/src/exocom/install.ts +2 -1
- package/src/extension/companion-settings.ts +29 -0
- package/src/extension/engine.ts +43 -16
- package/src/extension/hooks.ts +106 -36
- package/src/extension/persona-model-settings.ts +336 -0
- package/src/extension/persona-settings.ts +459 -0
- package/src/extension/shared.ts +15 -7
- package/src/extension.ts +642 -267
- package/src/monitor/archive.ts +235 -0
- package/src/monitor/session.ts +21 -1
- package/src/orchestration/flow-journal.ts +26 -5
- package/src/orchestration/flow-run.ts +38 -13
- package/src/orchestration/flow.ts +9 -2
- package/src/orchestration/reducers.ts +9 -5
- package/src/orchestration/render.ts +1 -1
- package/src/orchestration/sdk.ts +17 -3
- package/src/orchestration/strategies/compete.ts +5 -1
- package/src/orchestration/strategies/council-rounds.ts +2 -0
- package/src/orchestration/strategies/critic-loop.ts +3 -0
- package/src/orchestration/strategies/debate.ts +2 -0
- package/src/orchestration/strategies/fanout.ts +3 -2
- package/src/orchestration/strategies/judge.ts +5 -1
- package/src/orchestration/strategies/magi.ts +40 -23
- package/src/orchestration/strategies/map.ts +13 -3
- package/src/orchestration/strategies/pair.ts +2 -0
- package/src/orchestration/strategies/pipeline.ts +2 -0
- package/src/orchestration/strategies/synthesize.ts +27 -7
- package/src/orchestration/strategy.ts +31 -0
- package/src/persona/config-store.ts +6 -195
- package/src/persona/model-participants.ts +1 -1
- package/src/persona/persona.ts +7 -3
- package/src/persona/settings-store.ts +636 -0
- package/src/telemetry/contract.ts +1 -1
- package/src/tools/background-run.ts +151 -0
- package/src/tools/council.ts +77 -52
- package/src/tools/delegate-tool.ts +315 -285
- package/src/tools/delegate.ts +22 -210
- package/src/tools/exocom-work.ts +18 -53
- package/src/tools/exocom.ts +15 -19
- package/src/tools/flow.ts +85 -28
- package/src/tools/intercom-tool.ts +108 -118
- package/src/tools/intercom.ts +1 -1
- package/src/tools/models.ts +19 -9
- package/src/tools/monitor.ts +39 -6
- package/src/tools/timer.ts +11 -13
- package/src/ui/agent-overlay.ts +55 -14
- package/src/ui/agent-tree.ts +84 -18
- package/src/ui/compact-widget.ts +25 -0
- package/src/ui/failure-summary.ts +55 -0
- package/src/ui/literal-tool-result.ts +24 -0
- package/src/ui/model-picker.ts +158 -81
- package/src/ui/persona-settings.ts +328 -0
- package/src/ui/presentation.ts +24 -0
- package/src/ui/report-body.ts +63 -0
- package/src/ui/session-cards.ts +189 -0
- package/src/ui/wake-rows.ts +262 -0
- package/teams.yaml +5 -1
- package/src/persona/state.ts +0 -28
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -33,12 +33,17 @@ Persona names are data, never dispatch keys. Optional `delegation:` fields apply
|
|
|
33
33
|
builtin, user, or project persona: `requireBrief`, `outputContract`, `requireDisjointWrites`,
|
|
34
34
|
`requireFreshVerification`, and `verificationAgents`. Council behavior remains independently
|
|
35
35
|
declarative through `council: { strategy, roster, params }`; a custom persona can compose any installed
|
|
36
|
-
strategy/team without a core change.
|
|
36
|
+
strategy/team without a core change. Ownership intent follows the agent, not the caller: an agent definition
|
|
37
|
+
can declare the area it alone writes (`writeSet`, e.g. `research` → `.research/`), and a write-capable delegate leg that
|
|
38
|
+
names no `writeSet` inherits it before the gates run, so the disjoint-ownership and overlap checks see a
|
|
39
|
+
declared owner; a leg's own set wins, and the field stays declarative (nothing enforces paths at runtime).
|
|
40
|
+
Legs restricted to read-only tools do not inherit ownership defaults, so parallel readers do not conflict.
|
|
41
|
+
The gates use effective agent/tool capabilities, conservatively
|
|
37
42
|
treat shell-capable, MCP-enabled, or unknown tools as potential writers, and enforce the requested fan-out
|
|
38
|
-
concurrency
|
|
43
|
+
concurrency on the single launch path (interactive background or headless inline). A serialized verifier is accepted only
|
|
39
44
|
after every material writer in that batch; otherwise the call fails before a child starts. The rule
|
|
40
45
|
also holds ACROSS calls: a verifier launched while a material-writer background run is still live is
|
|
41
|
-
rejected
|
|
46
|
+
rejected, naming the mutating run ids, so a later call cannot slip past the in-batch ordering.
|
|
42
47
|
|
|
43
48
|
### The effort ladder (make the simple case simple; complexity is opt-in)
|
|
44
49
|
|
|
@@ -56,7 +61,9 @@ rejected with the run id to wait on, so a later call cannot slip past the in-bat
|
|
|
56
61
|
You climb only when you want determinism, structure, or reuse. Nothing forces the higher tiers.
|
|
57
62
|
The `council` tool is a gateway to all installed strategies, not a universal instruction to vote on
|
|
58
63
|
routine work. Choose a strategy when its topology adds value; MAGI and Judge retain their specialized
|
|
59
|
-
persona focus.
|
|
64
|
+
persona focus. The tool description lists every strategy with its `when`, positional roster and required
|
|
65
|
+
params, generated from the registry (`strategyCatalog`), and a call missing a required param is refused
|
|
66
|
+
before any run exists. A caller can supply ephemeral `members` with inline roles/models/skills instead of a
|
|
60
67
|
named team, without persisting a team or switching personas.
|
|
61
68
|
|
|
62
69
|
## Binding invariants (I1–I7)
|
|
@@ -100,7 +107,10 @@ These are the guardrails a contributor must not violate. They are enforced in co
|
|
|
100
107
|
- **I5 — Flows are the top tier.** A declarative DAG (statically verified: acyclicity, references
|
|
101
108
|
resolve, join reducers valid) above strategies. The flow engine stays thin — parse, verify,
|
|
102
109
|
schedule, persist, resume — and a flow node may call any strategy. Journaled: finished nodes replay
|
|
103
|
-
from disk with no re-spend.
|
|
110
|
+
from disk with no re-spend. A resume matches only the same flow, the same task and the same project
|
|
111
|
+
(`flowRunHash` = flow + task + cwd); another task starts from scratch. A `gate: true` phase shows its
|
|
112
|
+
output and its dependents to the operator; a rejection returns `stoppedAtGate` (not a failure, though
|
|
113
|
+
`ok` stays false so mandatory orchestration still fails closed).
|
|
104
114
|
- **I6 — Spawning is opportunistic by default; mandatory only when the persona declares it.** Two
|
|
105
115
|
first-class cases: *opportunistic* (`mode: solo` / no block — the supervisor MAY delegate by its own
|
|
106
116
|
judgement; never forced) and *mandatory* (`mode: strategy|flow|parallel|pipeline` with a roster —
|
|
@@ -161,8 +171,9 @@ engine, telemetry, UI, and tool surfaces; it is not part of the transport/domain
|
|
|
161
171
|
`peerDependencies`, `/doctor`'s `pi:` line, and the README's stated floor trace back to this
|
|
162
172
|
constant), `models`, `brief` (`buildDelegationBrief` — the per-turn delegation brief: live roster +
|
|
163
173
|
standing hand-off default; and `buildExocomBrief` — the per-turn peer brief: live peers, the
|
|
164
|
-
peer-vs-sub-agent split, and the relevance bound on an exchange), `nudge` (the
|
|
165
|
-
runtime-reinforcement state machines
|
|
174
|
+
peer-vs-sub-agent split, and the relevance bound on an exchange), `nudge` (the
|
|
175
|
+
runtime-reinforcement state machines `DelegationNudge` + `PersistenceNudge`, and the call-time wake
|
|
176
|
+
guards `PollGuard` + `longWaitSeconds`), `display-label`
|
|
166
177
|
(`sanitizeDisplayLabel` — an untrusted name reduced to bounded metadata before interpolation
|
|
167
178
|
outside a fence), `timer` (`TimerScheduler` — the pure alarm engine behind the `timer` tool), `time`
|
|
168
179
|
(`formatDuration` / `peerSentLabel` / `sessionElapsedLabel` / `buildSessionAnchor` — the elapsed-time
|
|
@@ -200,11 +211,12 @@ engine, telemetry, UI, and tool surfaces; it is not part of the transport/domain
|
|
|
200
211
|
lifecycle metadata only, never an agent-message router or control surface. See
|
|
201
212
|
[`TELEMETRY.md`](./TELEMETRY.md) for privacy, retention, writer leases, and shutdown behavior.
|
|
202
213
|
- **`src/persona/`** — identity: `persona.ts` (parse + `expandCouncilPreset` + `composeSystemPrompt`),
|
|
203
|
-
`controller.ts`, `gating.ts`, `orchestrate.ts`, `config-store.ts
|
|
214
|
+
`controller.ts`, `gating.ts`, `orchestrate.ts`, `config-store.ts` (pure model helpers),
|
|
215
|
+
`settings-store.ts` (canonical preferences, per-persona models and last-selected persona),
|
|
204
216
|
`spine.ts` (the shared behavioral layer's SOURCE resolution — docs/SPINE.md; composition sits in
|
|
205
217
|
`persona.ts` for supervisor turns and in the engines for delegated legs).
|
|
206
218
|
- **`src/tools/`** — `delegate.ts`, `intercom.ts`, `exocom.ts` (the `exocom_list`/`exocom_send`
|
|
207
|
-
tools), `exocom-work.ts` (claim/ask/answer/decline/wait/release/progress). **`src/ui/`** — agent tree/overlay, model picker, `presentation.ts` (the shared
|
|
219
|
+
tools), `exocom-work.ts` (claim/ask/answer/decline/wait/release/progress). **`src/ui/`** — agent tree/overlay, model picker, `wake-rows.ts` (the monitor/timer → tree-row projection), `presentation.ts` (the shared
|
|
208
220
|
card-compaction/sanitization helpers behind the projection rules below), `usage.ts`
|
|
209
221
|
(token/usage formatting, `ChildUsageLedger` / `toToolUsage` — sub-agent spend is
|
|
210
222
|
attached as Pi `toolResult.usage` so the footer and pi-theme-1337's frame count it;
|
|
@@ -302,7 +314,7 @@ than borrowing another role's choice. Routing still resolves the full role key,
|
|
|
302
314
|
|
|
303
315
|
**Model assignment repair is configuration, not execution recovery.** `/persona models [profile]`
|
|
304
316
|
is an explicit user edit in the Pi adapter: it reuses `resolveCouncilInvocation`,
|
|
305
|
-
`collectModelParticipants` and the
|
|
317
|
+
`collectModelParticipants` and the canonical locked settings writer, without adding another roster,
|
|
306
318
|
model store or provider-routing policy. The active caller owns saved assignments even when borrowing
|
|
307
319
|
another council profile. Automatic discovery stays never-nag; explicit editing may replace saved or
|
|
308
320
|
agent defaults, but not inline pins. Host catalog refresh has a 20-second cooperative deadline;
|
|
@@ -313,6 +325,49 @@ Running engines retain their captured assignments. Missing credentials are class
|
|
|
313
325
|
adapter boundary; only the SDK decides whether a main-model recovery is admissible. This separation
|
|
314
326
|
avoids a global reset or automatic repinning that could silently change billing and panel diversity.
|
|
315
327
|
|
|
328
|
+
The extension owns the derived candidate cache, keyed by session and base provider/model. Ordinary
|
|
329
|
+
turns reuse it; explicit catalog refresh invalidates the initiating key even after partial provider
|
|
330
|
+
failure. The settings UI supplies the refresh deadline and reporting, while the extension's refresh
|
|
331
|
+
adapter captures the key before awaiting the host. Briefs and nudges share the same callable-`models`
|
|
332
|
+
gate. Automatic model setup for tools, commands and mandated orchestration shares the checkpoint
|
|
333
|
+
dialog queue; each run registers its stop handle before entering that queue. Aborting setup discards
|
|
334
|
+
its unsaved choices and removes only prompt markers created by that attempt, so it can be retried.
|
|
335
|
+
|
|
336
|
+
**Unified settings.** `/persona-settings` is independent of Pi's `/settings`: full-page TUI, native
|
|
337
|
+
RPC dialogs, and a read-only `show` report. `core/settings.ts` is the public preference registry and
|
|
338
|
+
validator; the UI and environment precedence consume it rather than maintaining duplicate field lists.
|
|
339
|
+
All persistent Persona preferences live in `<agentDir>/persona/settings.json`, version 1: sparse
|
|
340
|
+
`preferences`, `personas` model maps and `lastPersona`. `settings-store.ts` owns bounded validated reads,
|
|
341
|
+
cross-process locked field patches and atomic replacement. Null removes an exact override; unknown
|
|
342
|
+
top-level and per-persona fields survive unrelated edits. Malformed/unsupported files are never
|
|
343
|
+
overwritten: activation warns and falls back, while editing fails closed. Fresh read-only inspection
|
|
344
|
+
does not materialize defaults.
|
|
345
|
+
|
|
346
|
+
`selectionRevision` is a non-negative counter updated only by explicit `lastPersona` patches,
|
|
347
|
+
including re-selection of the same name. Model/preference saves never advance it. Companion scope
|
|
348
|
+
readers must use this semantic marker, not the settings file's mtime, as evidence of a selection gesture.
|
|
349
|
+
|
|
350
|
+
Legacy `config.json` and `state.json` are imported only if the canonical file is absent, then archived
|
|
351
|
+
as exact independent `.migrated` copies after commit. Archive conflicts preserve the original and warn;
|
|
352
|
+
an existing canonical file is never reimported. `PI_PERSONA_STATE_FILE` only selects a legacy import
|
|
353
|
+
source. No active legacy writer remains. Explicit public environment values retain startup precedence;
|
|
354
|
+
internal child/bus guards are not preferences. Definitions, credentials and native Pi settings remain
|
|
355
|
+
with their existing owners.
|
|
356
|
+
|
|
357
|
+
Scalar preferences are activation-scoped: saving marks differences pending until a Pi restart or
|
|
358
|
+
Pi's native `/reload`, not `/new`; the panel never reloads automatically. `/persona reload` only refreshes resources.
|
|
359
|
+
The Models section selects the assignment owner independently of the viewed council/orchestration
|
|
360
|
+
profile, supports exact-key resets and keeps inline pins immutable. It patches the same file and updates
|
|
361
|
+
the resolver cache for future runs, never changing an already-running worker. Native compaction is untouched.
|
|
362
|
+
|
|
363
|
+
Mind/Flow settings use optional synchronous discovery on Pi's public event bus
|
|
364
|
+
(`pi-persona:settings:collect:v1`). The owning companion reports its current startup values; the same
|
|
365
|
+
central registry validates owner/type and renders only supported fields. Persona alone writes their
|
|
366
|
+
preferences in the canonical file; companions independently read their known fields, retaining
|
|
367
|
+
standalone operation with no hard runtime dependency on Persona. No collection call performs I/O,
|
|
368
|
+
starts services or wakes a model. Flow's desired port and idle grace apply to the next shared-service
|
|
369
|
+
startup, never to a daemon other sessions are already using. Skill Optimizer is outside this contract.
|
|
370
|
+
|
|
316
371
|
### MCP (and other `session_start`-scoped extensions) in sub-agents
|
|
317
372
|
|
|
318
373
|
**A sub-agent does NOT share the supervisor's MCP session, and an in-process sub-agent gets NO MCP at
|
|
@@ -399,8 +454,9 @@ decides how precise each may be is a **prompt-cache** rule, not a taste one:
|
|
|
399
454
|
- **Tail surfaces are free.** A tool result or a delivered message is written once and never re-sent
|
|
400
455
|
as the cached prefix, so precision costs nothing there. An inbound peer delivery dates itself
|
|
401
456
|
(`[rune] — reply · sent 20m ago`), and every settled leg reports its wall time on every
|
|
402
|
-
tracker-backed path — the done/failed/stopped report,
|
|
403
|
-
settled line of a peek digest
|
|
457
|
+
tracker-backed path — the done/failed/stopped report, `intercom result`, and each
|
|
458
|
+
settled line of a peek digest; a running line ends its turns/tokens parenthesis with
|
|
459
|
+
`· running for <duration>` (not shown while queued).
|
|
404
460
|
- **The system prompt is not.** It is re-composed and re-sent every turn and IS the cached prefix,
|
|
405
461
|
so a minute-granular value there rewrites it every minute and throws away the provider's cache of
|
|
406
462
|
everything before it. The **session anchor** therefore reads on a deliberately coarse ladder —
|
|
@@ -435,7 +491,7 @@ never simultaneously a telemetry event, a routed message, and a UI source of tru
|
|
|
435
491
|
a source of truth. The `f9` agent tree and `peek` digest are ProgressViews.
|
|
436
492
|
|
|
437
493
|
Steering is a supervisor-to-child control action, distinct from semantic Bus messages; requesting
|
|
438
|
-
steering does not establish that
|
|
494
|
+
steering does not establish that a blocking headless delegate call has been interrupted. The peek digest is
|
|
439
495
|
always a read-only ProgressView.
|
|
440
496
|
|
|
441
497
|
External telemetry is not a fourth communication plane: it is a generic observer/export contract that
|
|
@@ -488,36 +544,88 @@ for the supervisor and for explicit retrieval; the default TUI projection is del
|
|
|
488
544
|
Oversized or evicted messages return an unavailable diagnostic — retention is not durable evidence
|
|
489
545
|
storage;
|
|
490
546
|
- collapsed delegate/intercom/council/flow cards show state, identity, a short sanitized preview, and
|
|
491
|
-
Pi's expand-key hint, each surfacing failure at the top in its own shape: the delegate card
|
|
492
|
-
failed
|
|
493
|
-
`intercom wait` card leads with the `N settled — X done, Y failed` tally (per-leg causes sit in the
|
|
494
|
-
body, below the preview cut, so `wait`'s own success doesn't get a `failed` prefix);
|
|
547
|
+
Pi's expand-key hint, each surfacing failure at the top in its own shape: the delegate card
|
|
548
|
+
names each failed leg on its own line, and a failed council/flow card leads with the cause in its title;
|
|
495
549
|
- async launch cards and targeted Intercom call headers use the worker's canonical alias/model,
|
|
496
550
|
matching the tree rather than promoting its routing ID to display identity. Launch/control receipts
|
|
497
551
|
persist identity snapshots for history rendering; aliases never become routing keys. Colliding
|
|
498
552
|
aliases carry a secondary ID, and legacy receipts without a recoverable name retain their ID fallback.
|
|
499
553
|
Accepted steering receipts retain the exact sent message: collapsed cards preview it, expansion
|
|
500
554
|
shows all sanitized text and the diagnostic ID. A queued receipt does not prove the worker acted;
|
|
555
|
+
- async failures append a `pi-persona-run-failure` entry in TUI mode, with alias, agent/model,
|
|
556
|
+
elapsed time and a concise cause. The entry stores the original diagnostic for expanded history
|
|
557
|
+
rendering; it is operator-only and adds no model context or wake. Other modes, or an append
|
|
558
|
+
failure, retain a bounded notification. The semantic completion follows its existing single-wake path;
|
|
501
559
|
- follow-up cards (`pi-persona`, exocom) retain their complete semantic content but render a bounded
|
|
502
560
|
preview until expanded; terminal escape/control sequences are removed from the visible projection;
|
|
503
|
-
-
|
|
561
|
+
- custom follow-ups and operator-only entries share `ui/session-cards.ts`: glyph-free generated
|
|
562
|
+
headings, explicit textual state, one width-aware layout and semantic theme backgrounds. Neutral
|
|
563
|
+
information/unknown state uses `customMessageBg`, verified completion `toolSuccessBg`, attention
|
|
564
|
+
(nudge/stall/stopped) `toolPendingBg`, and verified failure `toolErrorBg`. Only runtime-owned status
|
|
565
|
+
evidence selects chrome, never peer/child prose. Colors are resolved from the active theme at render
|
|
566
|
+
time (including pi-theme-1337); normal tools keep Pi's own shell rather than gaining a duplicate box.
|
|
567
|
+
Expanded prose reports use the native Markdown projection in `ui/report-body.ts` (including visible
|
|
568
|
+
trust blockquotes); receipts, live output, monitor/timer notices and raw diagnostics stay literal.
|
|
569
|
+
Source payloads and fences remain intact. The native Markdown component is retained per report and
|
|
570
|
+
invalidated for theme/layout changes, without a global transcript cache. Rendering never rewrites
|
|
571
|
+
stored or model-facing payloads, nor creates a wake;
|
|
572
|
+
- literal control receipts and fallback errors share `ui/literal-tool-result.ts`: bounded collapsed
|
|
573
|
+
text, an expansion hint only when detail is hidden, and full sanitized expansion. Tool errors use
|
|
574
|
+
the host's `ToolRenderContext.isError`, not a presumed result field; semantic negative peer answers
|
|
575
|
+
remain successful retrievals. Retained `exocom_wait` answers are prose reports and render Markdown
|
|
576
|
+
when expanded. Native tool shells remain host-owned;
|
|
577
|
+
- the sticky agent and exocom widgets have fixed physical-row budgets: the shared width-aware
|
|
578
|
+
`ui/compact-widget.ts` clips each already-budgeted row instead of letting native Text wrap it.
|
|
579
|
+
F9/`/agents` and paginated
|
|
504
580
|
`exocom_list({ offset, limit })` are the explicit detail surfaces, so a wide fan-out cannot push the
|
|
505
581
|
editor off screen or dump an entire peer registry into model context. Agent-tree deltas share one
|
|
506
582
|
16 ms widget composition per terminal frame; identical lines/status are not republished, hierarchy
|
|
507
583
|
rendering uses one adjacency index, and the F9 overlay rebuilds lazily when Pi paints rather than
|
|
508
584
|
once per streamed token;
|
|
509
|
-
- `/flow` and `/orchestrate` append durable, TUI-only expandable result
|
|
510
|
-
|
|
585
|
+
- `/flow` and `/orchestrate` append a durable, TUI-only expandable result card rather than a large
|
|
586
|
+
notification; the supervisor gets the same text (fenced, 12k-bounded) once, as a passive next-turn message;
|
|
587
|
+
- an interactive `tasks` fan-out of two or more legs gets one container row, `delegate · N legs`
|
|
588
|
+
(`k/N settled`), that never counts as an in-flight agent and leaves with its last leg;
|
|
589
|
+
- `X` is not a directed key: it acts on the whole stoppable set of leaf rows after a confirmation that
|
|
590
|
+
states how many agents it covers, and a changed set is re-confirmed. The set is every agent leaf (wake
|
|
591
|
+
rows excepted) plus any run root with a stop handle (council/flow/mandated runs), and `x` on such a
|
|
592
|
+
root stops the whole run.
|
|
593
|
+
`intercom stop` / `stop { to: "all" }` also cover tracker runs, `council` and `flow` included;
|
|
511
594
|
- the F9 overlay's *directed* keys (`x` stop, `s` steer) act only on the agent the ▸ marker still
|
|
512
595
|
shows; if that agent settles and is pruned mid-keystroke, the selection re-anchors visibly and the
|
|
513
596
|
keypress is spent re-aiming instead of aborting an agent the user never chose. ↑↓, ⏎, and the scroll
|
|
514
597
|
keys never refuse;
|
|
515
598
|
- every agent-tree node carries `startedAt`/`lastAdvanceAt`; `LiveClock` (`src/ui/live-clock.ts`)
|
|
516
599
|
repaints the sticky widget and the F9 overlay once a second while any node is running and stops
|
|
517
|
-
itself once nothing is.
|
|
600
|
+
itself once nothing is. Running/completed usage shares `formatUsage`: `↑` input and `↓` output,
|
|
601
|
+
using copied existing cumulative usage snapshots, never context occupancy. A legacy progress source
|
|
602
|
+
providing only an aggregate shows a neutral compact count without `tok` or a fabricated direction. A running row shows elapsed time until it goes `STALL_FLAG_MS` (90s) quiet,
|
|
518
603
|
then the same `⚠ stalled <duration>` badge the async peek watchdog uses. `x` marks the target
|
|
519
604
|
`stopping…` at once and is offered only when a live stop handle exists; a refusal (no handle,
|
|
520
|
-
already settled) surfaces as a one-line notice instead of silently no-op'ing
|
|
605
|
+
already settled) surfaces as a one-line notice instead of silently no-op'ing;
|
|
606
|
+
- armed timers and active monitors are **wake rows** in the same tree (`src/ui/wake-rows.ts`, ids
|
|
607
|
+
`monitor:<id>` / `timer:<id>`): rows, not agents. The countdown replaces the stall clock: a timer
|
|
608
|
+
shows `fires in <d>` only, a monitor keeps its elapsed time (`<elapsed> · deadline in <d>`), so
|
|
609
|
+
neither carries the `⚠ stalled` badge or `waiting for supervisor`. `x` cancels
|
|
610
|
+
one through the same stop registry as an agent (the `monitor cancel` / `timer cancel` effect); `s` steer
|
|
611
|
+
is never offered. They are excluded from the `X` stop-all count, confirmation and bulk stop, from the
|
|
612
|
+
`N agents` in-flight status, and from telemetry (`agent.*` events are agents only). They settle and
|
|
613
|
+
leave like an async row: the final ✓/✗/■ goes to the tree change stream (telemetry excluded), not to
|
|
614
|
+
the screen, because the update and the removal are synchronous and the widget frame is coalesced. They
|
|
615
|
+
live only in the arming session, never restored. Raw monitor stdout/stderr has a separate passive
|
|
616
|
+
observer: raw chunks feed bounded sanitized tails immediately, but full row/preview projection is
|
|
617
|
+
coalesced per dirty monitor into the existing 16 ms widget frame, before its tree snapshot. Terminal
|
|
618
|
+
events and cancellation publish the pending final tail synchronously; teardown clears pending state.
|
|
619
|
+
This updates the widget and F9 without semantic events, model wakes, event-budget consumption or
|
|
620
|
+
stall-clock credit. The same observer feeds a bounded session-native log
|
|
621
|
+
archive (`src/monitor/archive.ts`): one plain custom entry per terminal/cancelled run, no sidecars or
|
|
622
|
+
per-chunk writes. `monitor result` retrieves retained captures across reload/resume from the whole
|
|
623
|
+
session tree, including sibling conversation branches: this archive is session-wide, deliberately
|
|
624
|
+
not a projection of the active branch. Branch navigation changes neither visibility nor the shared
|
|
625
|
+
lifetime budget. Restored logs never restore processes. Activation-unique monitor ids avoid historical result collisions. A finite
|
|
626
|
+
lifetime serialized-byte/count budget includes all previous entries of the archive type, even
|
|
627
|
+
unreadable versions. Session-file deletion owns log deletion; ordinary shutdown saves diagnostics,
|
|
628
|
+
not deletes them. Operator-only expandable log entries do not create model context or extra wakes.
|
|
521
629
|
|
|
522
630
|
This is a UI invariant only: truncating a collapsed card must never be confused with truncating the
|
|
523
631
|
underlying result or changing a strategy's contract.
|
|
@@ -643,36 +751,72 @@ a local process able to modify that directory is already inside the trust bounda
|
|
|
643
751
|
|
|
644
752
|
## Supervision & the waiting model
|
|
645
753
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
- **
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
ask the leg, don't probe its environment); messages to the supervisor also wake it. The **slow routine status card**
|
|
664
|
-
(`PI_PERSONA_CHECKIN_MS`, ~5 min, `0` disables) is a durable, expandable operator-only session entry
|
|
665
|
-
with the compact ProgressView digest — never full transcripts — and does not start a model turn. Live supervisor asks
|
|
754
|
+
There is no `sync`/`async` switch on `delegate` and no `intercom wait`; the mode follows the session.
|
|
755
|
+
|
|
756
|
+
- **Headless (`ctx.hasUI !== true`, e.g. `pi -p`)** — the supervisor blocks on the delegate, council or
|
|
757
|
+
flow call and gets results inline (returned once, unclipped; progress is only a `k/N done` counter), because nothing drains a follow-up after the
|
|
758
|
+
single turn exits. A runtime constraint, not a model-facing choice. The legs are still tracked, but
|
|
759
|
+
the status monitor stays off: the model is parked in the call and nobody reads a card.
|
|
760
|
+
- **Interactive (TUI and RPC)** — delegation is ALWAYS background: the call returns run ids at once
|
|
761
|
+
and each result returns as an idle-gated completion follow-up (`intercom result { to: runId }`
|
|
762
|
+
retrieves a settled run; `peek`/`steer`/`stop` stay available, which a blocking call could never
|
|
763
|
+
offer). With only background children left, the supervisor ends its turn and goes idle until a wake;
|
|
764
|
+
it never sleeps, polls, or arms a `timer` to wait for a child or a monitor. The **peek watchdog**
|
|
765
|
+
fires while async children run but stays SILENT unless there is something to act on. A newly
|
|
766
|
+
detected stall (`STALL_FLAG_MS`, 90s) appends a durable, expandable operator-only card, even while
|
|
767
|
+
the supervisor is busy, and never wakes the model; unread messages to the supervisor keep their
|
|
768
|
+
wake path. The **slow routine status card** (`PI_PERSONA_CHECKIN_MS`,
|
|
769
|
+
~5 min, `0` disables) is a durable, expandable operator-only session entry with the compact ProgressView
|
|
770
|
+
digest — never full transcripts — and does not start a model turn. Live supervisor asks
|
|
666
771
|
are derived from the exact engine handle's optional `isWaitingForSupervisor` predicate: tree/F9/peek
|
|
667
772
|
show waiting, and the watchdog suppresses false stalls until the ask settles. Parent clocks advance
|
|
668
773
|
with child engine events (liveness, not proof of useful work); parents are waiting only when every
|
|
669
|
-
live descendant branch is waiting.
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
774
|
+
live descendant branch is waiting. The peek watchdog's clock is stricter (`madeHeadway` in
|
|
775
|
+
`engine/async.ts`): a run advances only when assistant output, tokens or turns grew or a tool call
|
|
776
|
+
completed, and raw tool-output chunks earn nothing, so a leg whose tool streams forever (`npm run dev`,
|
|
777
|
+
`tail -f`) raises the operator-only stall card. A false advisory on a legitimately noisy long tool is
|
|
778
|
+
accepted; nothing is killed and the model is not woken. A council or flow run is credited per leg. The
|
|
779
|
+
tree/F9 clocks stay event-based.
|
|
780
|
+
The operator (or a manual `/peek`) can steer/stop a silent child. The supervisor's net for one is the
|
|
781
|
+
engine idle window (`RUN_LIMITS.timeoutMs`, 180s; startup deadline 300s), which kills it and returns a
|
|
782
|
+
failed completion follow-up whose text says to raise the leg's `timeoutMs`; the opt-in hard wall-clock cap (`PI_PERSONA_AGENT_MAX_MS`, off by
|
|
783
|
+
default) catches a busy non-converging leg.
|
|
784
|
+
Two call-time guards (under `config.nudge`, `PI_PERSONA_NUDGE=off` disables both) stop the in-turn
|
|
785
|
+
waits that would block those wakes: a repeated `intercom peek`/`result` whose answer has not changed
|
|
786
|
+
(per scope; `steer`/`stop` reset it) is refused, then asks Pi to end the turn (`terminate` is a hint
|
|
787
|
+
Pi honours when the peek is the batch's only call); a leading long `sleep`/`Start-Sleep` (>= 20s) is
|
|
788
|
+
stopped while background children run or are being launched (interactive only; a sleep prepared
|
|
789
|
+
before a same-batch `delegate` is an accepted false negative). A `delegate` fan-out (`tasks`) is
|
|
790
|
+
held and delivered as ONE completion follow-up when its last member settles, with every failed leg
|
|
791
|
+
named and clipped on its own line; single legs and separate calls are unchanged. Held reports are
|
|
792
|
+
dropped at session shutdown or reload, like the running legs, and the `PI_PERSONA_ASYNC_RETAIN`
|
|
793
|
+
default (64, the `tasks` cap) covers one whole call so early finishers stay fetchable. In headless `pi -p` the
|
|
794
|
+
`timer`/`monitor` arm text says the process exits when the turn settles, so such a wake lands only
|
|
795
|
+
if it fires before then.
|
|
796
|
+
**`council` and `flow` are the same kind of run** (`tools/background-run.ts`, `createBackgroundRuns`).
|
|
797
|
+
Interactive, each is ONE tracker run rooted at `async:<runId>`: a receipt now, ONE completion follow-up
|
|
798
|
+
(`intercom result { to: runId }` for the full payload), and the same `peek`/`stop`/`stop all`/f9 reach
|
|
799
|
+
as a delegate leg. Headless, the same run is launched and joined inside the tool call. Esc no longer aborts
|
|
800
|
+
one; stop it by key. Ownership of the limits: a run holds ONE slot of the delegate `maxConcurrency` launch
|
|
801
|
+
pool for its whole life (`queued` until granted; a flow keeps it while parked at a checkpoint); the strategy
|
|
802
|
+
SDK's per-run semaphore gates the legs INSIDE it, so members never compete with delegate legs for pool
|
|
803
|
+
slots; token budgets, the child limit, the delegation ledger and the fork-bomb guard stay in the SDK and
|
|
804
|
+
engine. A flow parked at a checkpoint is blocked on the OPERATOR: the run carries `awaiting`, peek reads
|
|
805
|
+
`waiting for operator at checkpoint <id>`, the stall watchdog skips it and nothing wakes the model; a
|
|
806
|
+
rejected checkpoint settles the run `stopped` and the plan reaches the model as its partial output. A
|
|
807
|
+
persona's `council:` defaults resolve unchanged when the call omits strategy, roster and params. The
|
|
808
|
+
mandated `orchestration:` path stays PRE-turn and inline (its result is the supervisor's first answer),
|
|
809
|
+
as do the `/orchestrate` and `/flow` slash commands; those runs register their own abort under their root
|
|
810
|
+
row, so shutdown ends the whole run. Operator-run results also reach the supervisor's next turn as a
|
|
811
|
+
passive, fenced, 12k-bounded message.
|
|
673
812
|
Progress tokens are labelled **cumulative input/output**, not context occupancy; cache-read/write
|
|
674
813
|
accounting is separate. Do not infer a full context window from that counter. File age or line-count
|
|
675
814
|
changes alone likewise do not establish a stall, a passing test or completed work.
|
|
815
|
+
**Restore honesty:** `session_shutdown` records lost run ids, timers, monitors and the run-id counter
|
|
816
|
+
in a `pi-persona:runs` session entry (`core/session-runs.ts`). The next `session_start` (reload,
|
|
817
|
+
in-session resume, `pi -c`; not fork or `/new`) tells the supervisor once through a passive `nextTurn`
|
|
818
|
+
message, acknowledges it, and continues run ids so they never restart at `run-1` within a session.
|
|
819
|
+
Only ids matching a strict shape and capped counts are ever read back.
|
|
676
820
|
Async failures are ALWAYS reported; the runtime `DelegationLedger` vetoes a blind retry loop (an
|
|
677
821
|
identical agent+model+task delegation that failed twice is stopped before it spawns). Coaching is
|
|
678
822
|
gated by `coaching: on` AND `canUseBus`.
|
|
@@ -680,26 +824,42 @@ a local process able to modify that directory is already inside the trust bounda
|
|
|
680
824
|
**Runtime reinforcement of the hand-off default** comes as a standing part and a reactive part, because
|
|
681
825
|
a persona directive lives at the TOP of the prompt and its pull decays as recent tool output balloons:
|
|
682
826
|
|
|
683
|
-
- The **delegation brief** (`core/brief.ts`) is the STANDING half: live roster (agents + teams + flows
|
|
684
|
-
and the hand-off default
|
|
827
|
+
- The **delegation brief** (`core/brief.ts`) is the STANDING half: live roster (agents + teams + flows, with descriptions;
|
|
828
|
+
gated flows are tagged in headless sessions) and the hand-off default (the supervisor's role: it holds the
|
|
829
|
+
objective, the plan and the judgement, normally handing bounded independent work to supervised legs;
|
|
830
|
+
quick, trivial or tightly coupled work can stay inline when hand-off overhead would outweigh the benefit; one decision-class →
|
|
831
|
+
method line that a test checks against the strategy registry; model-sizing guidance and a cached provider
|
|
832
|
+
candidate list), appended to the system-prompt TAIL every turn, where recency wins the
|
|
685
833
|
tug-of-war a top-of-prompt line loses. It regenerates from the live registry (so it can't desync) and
|
|
686
|
-
filters to the active persona's `delegate` allowlist. It never dictates how MANY sub-agents
|
|
687
|
-
shape
|
|
834
|
+
filters to the active persona's `delegate` allowlist. It never dictates how MANY sub-agents; beyond the one class line,
|
|
835
|
+
the shape is each persona's own method.
|
|
836
|
+
The model snapshot is acquired once per session/base-model reference, refreshed on a base-model change
|
|
837
|
+
or explicit `models` call, and reused across turns. Recommendations first stay near the current
|
|
838
|
+
model's provider, textual name root and numbered major generation, then order distinct variants by
|
|
839
|
+
relative cost band and numeric version. They do not fill spare slots with older or unrelated models.
|
|
840
|
+
This affects discovery only; exact assignment and search retain the full eligible catalog.
|
|
841
|
+
Relative cost hints use host prices against an uncapped recent-provider reference, never a
|
|
842
|
+
model-name-to-tier table, and leave missing or zero-price metadata unknown. The LLM chooses task fit.
|
|
688
843
|
- The **nudges** (`core/nudge.ts`, on by default) are the REACTIVE half, landing in RECENT context on
|
|
689
844
|
the event that warrants them:
|
|
690
845
|
- **DelegationNudge** — a `tool_result` hook watches the supervisor's own tool stream and, when a
|
|
691
|
-
delegating persona grinds heavy work by hand (output burn since the last `delegate`/`council`
|
|
692
|
-
crosses a threshold), appends a compact labelled checkpoint
|
|
846
|
+
delegating persona grinds heavy work by hand (output burn since the last `delegate`/`council`/`flow`
|
|
847
|
+
crosses a threshold: 3 substantive calls and ~1k tokens), appends a compact labelled checkpoint
|
|
848
|
+
(`Trigger` / `Scope` / `Action`, with four delegate targets named in the action, those the persona's own prompt mentions first, and a
|
|
849
|
+
`Model candidates` line for the session provider) to
|
|
693
850
|
that command's result for the model and mirrors it into a durable, expandable
|
|
694
851
|
`pi-persona-nudge` custom entry for the operator. The entry is TUI-only (no duplicate model
|
|
695
852
|
context or turn) and guarantees visibility even when a built-in/custom tool renderer suppresses
|
|
696
853
|
result `content`. A successful hand-off resets the streak; a failed one keeps it and returns the
|
|
697
854
|
same visible re-dispatch checkpoint.
|
|
855
|
+
- `flow` is a hand-off beside `delegate`/`council`: a successful flow resets the by-hand streak and a
|
|
856
|
+
failed one gets no re-dispatch checkpoint (its failure text is self-describing).
|
|
698
857
|
- **PersistenceNudge** — the counterweight to premature surrender: a delegated leg's report carrying
|
|
699
|
-
`[BLOCKED]`/`FLAG: UNKNOWN` gets a "don't bank it yet" reminder.
|
|
700
|
-
(
|
|
858
|
+
`[BLOCKED]`/`FLAG: UNKNOWN` gets a "don't bank it yet" reminder. Three delivery paths carry it
|
|
859
|
+
(the inline `delegate`/`council`/`flow` result — headless only — background
|
|
860
|
+
completion, and an explicit `intercom result` of a done run), but coverage isn't identical:
|
|
701
861
|
the sync path scans the WHOLE tool result including failed legs, while `renderCompletion` scans
|
|
702
|
-
only `status === "done"` runs by design — a failed background
|
|
862
|
+
only `status === "done"` runs by design — a failed background leg already gets a failure
|
|
703
863
|
block, so a `[BLOCKED]` marker there doesn't also get the persistence note. Same marker, same leg,
|
|
704
864
|
different counterweight depending on how it was collected.
|
|
705
865
|
Nested calls through codemode's `ctx.executeTool` leave their programmatic result untouched.
|
|
@@ -707,8 +867,9 @@ a persona directive lives at the TOP of the prompt and its pull decays as recent
|
|
|
707
867
|
used to infer nesting. A bounded set of parent call ids carries report provenance through wrappers
|
|
708
868
|
only while their output relays a surrender marker; the outer model-visible result alone gets the
|
|
709
869
|
note/card. Suppressed reports produce neither, and turn/session settlement clears abandoned relay state.
|
|
710
|
-
- **The off switch covers every path.** `PI_PERSONA_NUDGE=off` silences DelegationNudge entirely
|
|
711
|
-
PersistenceNudge on
|
|
870
|
+
- **The off switch covers every path.** `PI_PERSONA_NUDGE=off` silences DelegationNudge entirely,
|
|
871
|
+
PersistenceNudge on all three delivery paths (inline result, background completion, `intercom result`),
|
|
872
|
+
and both call-time wake guards (`PollGuard`, the long-sleep block).
|
|
712
873
|
|
|
713
874
|
## Discovery & seeding
|
|
714
875
|
|
|
@@ -725,6 +886,11 @@ a persona directive lives at the TOP of the prompt and its pull decays as recent
|
|
|
725
886
|
pristine prior copy and preserves edited, linked, or unknown files. A migration can declare a bundled
|
|
726
887
|
agent dependency; that missing file is installed first with no-clobber atomic creation, or the parent
|
|
727
888
|
remains on its old bytes. Upgrades, dependency installs, and warnings are exposed in `/doctor`.
|
|
889
|
+
The legacy digest table (`LEGACY_SEEDED_DEFAULTS`) holds the LF-checkout bytes of every shipped
|
|
890
|
+
elite/swarm/MAGI-core version from v1.11.0, plus the v1.17.1 copies of every bundled persona. Release prep must add the
|
|
891
|
+
previous tag's digest for each changed persona/agent; the guard test in `seed.test.ts` prints the
|
|
892
|
+
row (and skips in CI's depth-1 checkout). With zero personas installed, F8 and `/doctor` point to
|
|
893
|
+
`/persona seed`, like `/persona list`.
|
|
728
894
|
Contracts/presets/teams keep a builtin layer (they aren't personas).
|
|
729
895
|
|
|
730
896
|
## Cross-OS constructs
|
package/docs/EXPERIENCE.md
CHANGED
|
@@ -43,27 +43,37 @@ supervisor is free. Keep the session open, and cancel a watch when its purpose e
|
|
|
43
43
|
- **F9** opens the agent tree. Queued rows have not started their clocks. Live supervisor asks show
|
|
44
44
|
`waiting for supervisor`, not a stall; running rows otherwise show elapsed time and switch to
|
|
45
45
|
`⚠ stalled <duration>` after 90 seconds without progress — a suspicion, not proof of a deadlock.
|
|
46
|
-
Council parent clocks refresh on child engine events; that indicates liveness, not useful work.
|
|
46
|
+
Council parent clocks refresh on child engine events; that indicates liveness, not useful work. For the
|
|
47
|
+
stall card and `/peek`, "stalled" is stricter: 90 seconds with no assistant output, tokens, turns or
|
|
48
|
+
completed tool call, so a tool that only streams output (`npm run dev`, `tail -f`) is flagged too. It is
|
|
49
|
+
advice only: nothing is killed.
|
|
47
50
|
A parent is waiting only when all its live descendant branches are waiting. Enter opens a selectable worker's output; `s` sends a course correction;
|
|
48
51
|
`x` requests cancellation and appears only when the run can actually be stopped, marking the row
|
|
49
52
|
`stopping…` at once; a stop that can't be applied says so instead of doing nothing. Escape goes
|
|
50
53
|
back or closes the panel.
|
|
51
54
|
- **`/peek`** gives a compact progress view. A quiet worker is a reason to inspect its last
|
|
52
55
|
progress and current activity, not to launch a duplicate immediately.
|
|
56
|
+
- **`/flow <name> <task>`** runs a flow (`/flow` alone lists them with descriptions; a `gate: true`
|
|
57
|
+
phase pauses for your approval, showing its output and what runs next). `/orchestrate <task>` runs
|
|
58
|
+
the active persona's `orchestration:` block (bundled personas declare `council:` instead, used via the
|
|
59
|
+
`council` tool); both run inline and their result also reaches the
|
|
60
|
+
supervisor's next turn. In the F9 list, `X` stops every running leaf agent after a
|
|
61
|
+
second press that states how many.
|
|
53
62
|
- **Background results arrive automatically.** A supervisor can continue independent work while
|
|
54
63
|
they run. When only background workers remain, end the turn and let completion follow-ups return
|
|
55
|
-
their results;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
64
|
+
their results; never sleep, poll, or arm a timer to wait for healthy workers (or monitors) - a
|
|
65
|
+
finished worker wakes the supervisor by itself. `intercom result { to: runId }` retrieves a settled
|
|
66
|
+
run. Interactive `delegate`, `council` and `flow` always run in the background (a receipt now, one
|
|
67
|
+
follow-up with the outcome; a flow checkpoint waits for you, not the supervisor; Esc does not abort
|
|
68
|
+
them: stop legs from F9 with `x`/`X`, or have the supervisor `intercom stop` the run); headless `pi -p` always blocks for the
|
|
69
|
+
turn and returns results inline, since nothing drains a follow-up after the process exits.
|
|
70
|
+
- **Answer a waiting worker promptly.** A coaching worker may need a decision from its
|
|
60
71
|
supervisor before it can finish. An unanswered question is actionable work.
|
|
61
72
|
- **Steering is a request.** Check the subsequent output to see whether the worker incorporated
|
|
62
73
|
it. In-process workers can receive guidance mid-run; child-engine workers (including MCP/worktree
|
|
63
74
|
runs) receive it as a queued follow-up. Neither promises to interrupt arbitrary tool work, and
|
|
64
|
-
steering
|
|
65
|
-
|
|
66
|
-
made are not undone.
|
|
75
|
+
steering is not a substitute for ending the turn. After requesting cancellation, the stopped report
|
|
76
|
+
arrives as a completion follow-up; changes already made are not undone.
|
|
67
77
|
|
|
68
78
|
Launch cards and targeted Intercom calls show the same worker alias as the live tree. A steering
|
|
69
79
|
receipt previews the message that was actually queued; expand it (`Ctrl+O` by default, or your
|
package/docs/MONITORS.md
CHANGED
|
@@ -6,7 +6,8 @@ preserving the cached system prefix. During a long run it can call `timer` with
|
|
|
6
6
|
to refresh the clock. This is sampled wall-clock time, not a continuously updated model sense.
|
|
7
7
|
|
|
8
8
|
Use `timer arm` for a known time. Use `monitor arm` when a program can report the event you care
|
|
9
|
-
about. Sub-agent completions and Exocom messages already
|
|
9
|
+
about, never one whose only job is to elapse time. Sub-agent completions and Exocom messages already
|
|
10
|
+
wake the supervisor automatically, so neither tool should wait on them.
|
|
10
11
|
|
|
11
12
|
## Background programs
|
|
12
13
|
|
|
@@ -36,13 +37,70 @@ Adapters can use native file/system subscriptions, a program's streaming API, or
|
|
|
36
37
|
polling inside the program when no subscription exists. The model does not run a polling loop.
|
|
37
38
|
Print one short event per line to stdout; send diagnostic chatter to stderr. Flush output promptly
|
|
38
39
|
(for Python, use `-u` or `flush=True`). Repeated identical lines are ignored for that watch.
|
|
39
|
-
|
|
40
|
+
Monitor stdout and stderr are captured automatically within fixed limits. For a complete, unlimited
|
|
41
|
+
transcript, keep using the program's own log file; monitor capture is bounded diagnostic evidence.
|
|
40
42
|
|
|
41
43
|
The model can continue independent work while a monitor runs. Events wait while it is busy and
|
|
42
44
|
arrive together at an idle boundary. When only the event remains, it should end its turn. Natural
|
|
43
45
|
requests such as “let me know when this build finishes” are enough; tool parameters are for the
|
|
44
46
|
model or an integration, not something the user needs to manage.
|
|
45
47
|
|
|
48
|
+
## Visibility
|
|
49
|
+
|
|
50
|
+
An armed timer or active monitor shows as a row in the agent widget and the F9 / `/agents` overlay,
|
|
51
|
+
beside the sub-agents: `◉ <label> <id> · <mode> · <elapsed> · deadline in <remaining>` for a monitor
|
|
52
|
+
(`<id> · output · k/N events` as events arrive), `⏰ <label> <id> · fires in <remaining>` for a timer
|
|
53
|
+
(just `⏰ <id> fires in <remaining>` when the timer has no label).
|
|
54
|
+
The countdown replaces the stall clock, so a quiet watch is never `⚠ stalled`. While a process runs,
|
|
55
|
+
its latest useful stdout/stderr progress is displayed on its row, including partial lines and carriage-return
|
|
56
|
+
progress updates. Tails ingest every chunk immediately; their display is updated at the existing UI
|
|
57
|
+
frame cadence instead of rebuilding the full row for every chunk. Terminal events and cancellation
|
|
58
|
+
include the final tail immediately. This is a bounded, sanitized UI projection: it does not create a
|
|
59
|
+
model wake or consume an output-event allowance. `⏎` opens the command, cwd, times, bounded live output tails and last 40 event
|
|
60
|
+
lines (monitor), or the fire time and message (timer); `x` cancels that
|
|
61
|
+
one watch like `monitor cancel` / `timer cancel`. These are rows, not agents: no steer, `X` stop-all
|
|
62
|
+
skips them (`intercom stop { to: "all" }` likewise leaves them alone; cancel with `monitor cancel` /
|
|
63
|
+
`timer cancel` or `x`), and they never count in `N agents` or reach telemetry. A finished row settles
|
|
64
|
+
and leaves like an async run: its final ✓/✗/■ goes to the tree change stream (telemetry excluded), not
|
|
65
|
+
to the screen.
|
|
66
|
+
|
|
67
|
+
## Session-owned logs and results
|
|
68
|
+
|
|
69
|
+
`monitor { action: "result" }` lists retained captures, including completed jobs; add `id` to read one.
|
|
70
|
+
The default read shows a short tail; `full: true` reads the complete **retained** capture, not bytes
|
|
71
|
+
already discarded by the capture limit. This is retrieval, not a wait: do not poll it for completion.
|
|
72
|
+
`list` still lists only active watches. IDs are activation-unique so reload cannot confuse an old log
|
|
73
|
+
with a newly launched process.
|
|
74
|
+
|
|
75
|
+
The archive belongs to the **whole session tree**, not only the active conversation branch.
|
|
76
|
+
`result` can therefore list or retrieve a log from a sibling branch that is absent from the current
|
|
77
|
+
transcript. Branch navigation changes the transcript, not archive visibility or ownership. Both
|
|
78
|
+
retention budgets below are shared across all branches and remain shared after reload.
|
|
79
|
+
|
|
80
|
+
A terminal event or cancellation saves one bounded stdout/stderr snapshot and outcome as a custom
|
|
81
|
+
entry in the owning Pi session. An expandable operator-only log card exposes it without adding the
|
|
82
|
+
raw log to model context or triggering another turn. No per-chunk session entries or sidecar files
|
|
83
|
+
are written. Shutdown/reload stops processes and saves their available diagnostics; resume can read
|
|
84
|
+
the snapshots but never restarts the processes. A hard crash can lose a running job's not-yet-saved
|
|
85
|
+
capture. In a non-persistent session, logs remain in memory only.
|
|
86
|
+
|
|
87
|
+
Deleting the owning session file removes its stored logs with it. Reload, ordinary shutdown and
|
|
88
|
+
context compaction are not deletion. Forking/copying a session can copy its historical log entries;
|
|
89
|
+
each copy then owns its own data, with no shared external file to orphan or delete accidentally.
|
|
90
|
+
Backups and exports may also retain copies; deleting the original session is not secure erasure
|
|
91
|
+
of those copies. Treat captured stdout/stderr as session data: printed credentials, signed URLs
|
|
92
|
+
and other secrets can be stored in the JSONL. Sanitize/redact sensitive output in the producing
|
|
93
|
+
program before capture. Display sanitization is not secret redaction; requesting `result` returns
|
|
94
|
+
the selected retained text to the model, even when it originated on a sibling branch.
|
|
95
|
+
|
|
96
|
+
Each capture retains the last 16,384 UTF-16 code units of stdout and stderr independently, plus at
|
|
97
|
+
most 16,384 code units of status text. Live F9 tails retain 4,000 code units per stream. The journal
|
|
98
|
+
admits at most 64 terminal records and a conservative 2 MiB cumulative serialized-data budget per
|
|
99
|
+
session (JSON escaping, metadata and envelope allowance included). Historical entries, even unknown
|
|
100
|
+
formats, consume that budget; reload does not reset it. Once exhausted, new captures remain only in
|
|
101
|
+
the bounded runtime history, and `result` explicitly reports the storage limitation. Truncation and
|
|
102
|
+
persistence failures never claim a complete or durable log.
|
|
103
|
+
|
|
46
104
|
## Lifetime and limits
|
|
47
105
|
|
|
48
106
|
- `list` shows active watches; `cancel` with the returned `id` stops the owned process tree and
|
|
@@ -56,7 +114,8 @@ model or an integration, not something the user needs to manage.
|
|
|
56
114
|
to four per batch, and reports omitted older events if a busy model cannot keep up.
|
|
57
115
|
- Keep Pi open. Watches are in memory and stop on shutdown, reload, or session replacement;
|
|
58
116
|
they are not restored on resume. A headless `pi -p` invocation that exits after its answer is
|
|
59
|
-
not a persistent monitoring service
|
|
117
|
+
not a persistent monitoring service: an alarm or event wakes it only if it lands before the single
|
|
118
|
+
turn settles, and the arm result says so instead of inviting the model to end its turn.
|
|
60
119
|
|
|
61
120
|
## Permissions and architecture
|
|
62
121
|
|