@aeondave/pi-persona 1.17.1 → 1.17.4
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 +103 -64
- package/CHANGELOG.md +310 -1
- package/README.md +37 -23
- 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 +280 -92
- package/docs/COLLABORATION.md +110 -0
- package/docs/EXPERIENCE.md +52 -17
- package/docs/MONITORS.md +62 -3
- package/docs/README.md +12 -0
- package/docs/REFERENCE.md +139 -38
- 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 +15 -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 +26 -0
- package/src/bridge.ts +28 -10
- package/src/bus/broker/client.ts +119 -21
- package/src/bus/broker/host.ts +123 -8
- package/src/bus/broker/messages.ts +31 -4
- package/src/bus/contact.ts +113 -38
- package/src/bus/peers.ts +15 -0
- package/src/bus/result-reader.ts +88 -0
- package/src/core/brief.ts +436 -353
- package/src/core/capabilities.ts +1 -1
- package/src/core/config.ts +15 -10
- package/src/core/leg-thinking.ts +57 -0
- 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/ownership.ts +1 -2
- package/src/core/pi-compat.ts +5 -12
- package/src/core/seed.ts +99 -6
- package/src/core/session-runs.ts +87 -0
- package/src/core/settings.ts +1 -1
- package/src/core/timer.ts +34 -9
- package/src/core/types.ts +1 -1
- package/src/engine/adapter.ts +95 -27
- package/src/engine/async.ts +213 -155
- package/src/engine/child.ts +12 -4
- package/src/engine/host-module.ts +12 -0
- package/src/engine/inproc.ts +99 -53
- package/src/engine/result-grant.ts +62 -0
- package/src/engine/session-tools.ts +6 -0
- package/src/engine/stream.ts +10 -20
- package/src/engine/worktree.ts +17 -7
- package/src/exocom/collaboration-delivery.ts +29 -0
- package/src/exocom/collaboration.ts +148 -0
- package/src/exocom/envelope.ts +43 -4
- package/src/exocom/gate.ts +7 -2
- package/src/exocom/install.ts +47 -18
- package/src/exocom/ledger.ts +58 -8
- package/src/exocom/plane.ts +32 -1
- package/src/exocom/profile.ts +40 -0
- package/src/exocom/registry.ts +5 -0
- package/src/exocom/status.ts +11 -1
- package/src/exocom/write-guard.ts +7 -0
- package/src/extension/broker-host.ts +61 -9
- package/src/extension/engine.ts +54 -28
- package/src/extension/hooks.ts +952 -868
- package/src/extension/identity.ts +41 -75
- package/src/extension/persona-model-settings.ts +31 -13
- package/src/extension/results.ts +136 -0
- package/src/extension/shared.ts +32 -7
- package/src/extension.ts +2965 -2611
- package/src/loader.ts +11 -3
- package/src/monitor/archive.ts +235 -0
- package/src/monitor/session.ts +21 -1
- package/src/orchestration/flow-journal.ts +33 -6
- package/src/orchestration/flow-run.ts +160 -32
- package/src/orchestration/flow.ts +20 -2
- package/src/orchestration/reducers.ts +9 -5
- package/src/orchestration/render.ts +1 -1
- package/src/orchestration/roster.ts +71 -23
- package/src/orchestration/sdk.ts +61 -11
- 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/orchestration/types.ts +10 -0
- package/src/persona/model-participants.ts +20 -7
- package/src/persona/orchestrate.ts +2 -0
- package/src/persona/persona.ts +8 -4
- package/src/results/archive.ts +281 -0
- package/src/results/record.ts +166 -0
- package/src/results/retrieval.ts +142 -0
- package/src/results/types.ts +128 -0
- package/src/telemetry/contract.ts +1 -1
- package/src/tools/background-run.ts +151 -0
- package/src/tools/council.ts +108 -66
- package/src/tools/delegate-tool.ts +349 -283
- package/src/tools/delegate.ts +35 -216
- package/src/tools/exocom-collaboration-input.ts +168 -0
- package/src/tools/exocom-collaboration.ts +315 -0
- package/src/tools/exocom-profile.ts +102 -0
- package/src/tools/exocom-work.ts +18 -53
- package/src/tools/exocom.ts +35 -22
- package/src/tools/flow.ts +103 -30
- package/src/tools/intercom-tool.ts +202 -128
- package/src/tools/intercom.ts +1 -1
- package/src/tools/models.ts +34 -9
- package/src/tools/monitor.ts +58 -6
- package/src/tools/read-result.ts +52 -0
- package/src/tools/timer.ts +34 -15
- package/src/ui/agent-overlay.ts +65 -16
- package/src/ui/agent-tree.ts +127 -19
- 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/orchestration-launch.ts +49 -0
- package/src/ui/persona-settings.ts +9 -3
- package/src/ui/presentation.ts +24 -0
- package/src/ui/report-body.ts +63 -0
- package/src/ui/session-cards.ts +366 -0
- package/src/ui/wake-rows.ts +262 -0
- package/teams.yaml +5 -1
package/AGENTS.md
CHANGED
|
@@ -20,7 +20,11 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
|
|
|
20
20
|
A test that exercises a variable sets it for itself, after that has run. Drop the flag and you
|
|
21
21
|
are testing your shell, not the code.
|
|
22
22
|
- Live end-to-end (REAL model calls, spends tokens): `npm run drive -- --persona <name> --model <provider/id> "<prompt>"`
|
|
23
|
+
- `drive.ts` exits non-zero and prints `[persona] ...` when the requested persona is not installed.
|
|
23
24
|
- Control ops: `LIVE_MODEL=<provider/id> node --import tsx scripts/control-test.mjs` (STEER/STOP/RESUME)
|
|
25
|
+
- Interactive wake contract (manual, spends tokens, refuses without `LIVE_MODEL`):
|
|
26
|
+
`LIVE_MODEL=<provider/id> npm run smoke:wake` — RPC session, 3-leg `delegate` fan-out, asserts ONE
|
|
27
|
+
wake carrying all results and no peek/timer/sleep polling before it. Run it before a release.
|
|
24
28
|
- Models must be **provider-qualified**, e.g. `claude-pro-max-native/claude-opus-4-8` or `.../claude-haiku-4-5`.
|
|
25
29
|
|
|
26
30
|
## Conventions
|
|
@@ -33,8 +37,13 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
|
|
|
33
37
|
`@earendil-works/pi-*`; never bundle copies.
|
|
34
38
|
- npm publishes as `@aeondave/pi-persona`. Pi supplies the four `@earendil-works/pi-*` packages
|
|
35
39
|
and `typebox`: keep them as `peerDependencies: "*"` with development-only copies, never runtime
|
|
36
|
-
dependencies.
|
|
37
|
-
|
|
40
|
+
dependencies. Target the latest stable Pi only (currently 1.4.0, aligned with `MIN_PI_VERSION`,
|
|
41
|
+
the four development pins and README); do not maintain historical-host compatibility branches.
|
|
42
|
+
**No legacy or deferred cleanup:** remove dead code, obsolete options, superseded implementations
|
|
43
|
+
and compatibility-only aliases with their replacement. Update every caller, fixture and document
|
|
44
|
+
in the same change. A completed feature must not leave temporary scaffolding or cleanup debt.
|
|
45
|
+
Keep a path only when it serves the current host/runtime or a demonstrated current data contract.
|
|
46
|
+
Node.js must be ≥ 22.19 to match that host. Keep the npm
|
|
38
47
|
`files` allowlist explicit for docs/artwork, inspect `npm pack --dry-run`, and never publish drafts.
|
|
39
48
|
- Supply-chain controls: pin every GitHub Action to a verified full commit SHA; keep top-level
|
|
40
49
|
token permissions read-only, grant write permissions only to the reporting job that needs them,
|
|
@@ -51,7 +60,7 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
|
|
|
51
60
|
`createAgentSession`, DEFAULT) and **ChildProcessEngine** (`engine/child`, spawns `pi --mode json -p`,
|
|
52
61
|
the correctness baseline + the path worktree isolation uses). Opt out with `PI_PERSONA_ENGINE=child`.
|
|
53
62
|
BOTH enforce `RUN_LIMITS.timeoutMs` as an **idle window** (no events/output ⇒ abort; the inproc
|
|
54
|
-
watchdog is
|
|
63
|
+
watchdog is armed for every child; a live pending ask from that child re-arms it) AND
|
|
55
64
|
`PI_PERSONA_AGENT_MAX_MS` as an **opt-in hard wall-clock cap** (lifetime ceiling armed once, never
|
|
56
65
|
reset — catches a busy loop the idle window never does; OFF by default (0 = unlimited) so a healthy,
|
|
57
66
|
progressing child runs to completion, set `<ms>` to arm it) AND
|
|
@@ -62,9 +71,14 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
|
|
|
62
71
|
notably a headless `mcp: true` leg whose `pi-mcp-adapter` hangs on interactive OAuth; `adapter.ts`
|
|
63
72
|
turns that (turns===0 + `spec.mcp`) into a clear pre-auth remedy instead of an opaque timeout.
|
|
64
73
|
The child engine delivers the task over **stdin** (`pi -p` prepends piped stdin) — never argv,
|
|
65
|
-
which would hit Windows' ~32 KiB command-line cap on flow-phase tasks.
|
|
66
|
-
|
|
67
|
-
fan-out can't open more
|
|
74
|
+
which would hit Windows' ~32 KiB command-line cap on flow-phase tasks. Every delegate leg, and every
|
|
75
|
+
tracked `council`/`flow` run (one slot for the whole run), headless included, shares one
|
|
76
|
+
`maxConcurrency` launch pool (`Semaphore` in `orchestration/parallel.ts`), so a fan-out can't open more
|
|
77
|
+
concurrent sessions than that; the strategy SDK's own semaphore gates the legs INSIDE a run.
|
|
78
|
+
Any event re-arms the idle window (a chatty tool is never killed), but stall credit follows one rule,
|
|
79
|
+
`madeHeadway` (`engine/async.ts`): raw tool-output chunks earn none, so a leg whose tool streams forever
|
|
80
|
+
raises only the operator-only stall card (nothing is killed, the model is not woken). The idle-timeout
|
|
81
|
+
failure text names the `timeoutMs` remedy.
|
|
68
82
|
Each strategy SDK also gates every `agent()` call through one semaphore, including direct
|
|
69
83
|
`Promise.all` calls; `parallel` overrides cannot raise its concurrency ceiling. Token budgets
|
|
70
84
|
gate admission using completed usage, so already-running legs can overshoot the threshold.
|
|
@@ -111,16 +125,27 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
|
|
|
111
125
|
blind retry loops are stopped by the runtime `DelegationLedger` (an identical agent+model+task
|
|
112
126
|
delegation that failed twice is vetoed before it spawns).
|
|
113
127
|
- Dynamic sub-agents: `delegate` shapes an on-the-fly specialist with `role` (extra system prompt,
|
|
114
|
-
appended to the agent's own) + `skills` — prompt-level only, capabilities stay the gate.
|
|
115
|
-
`
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
128
|
+
appended to the agent's own) + `skills` — prompt-level only, capabilities stay the gate.
|
|
129
|
+
`delegate` has NO `sync`/`async` parameter and `intercom` has NO `wait`: interactive sessions
|
|
130
|
+
(`ctx.hasUI`, TUI and RPC) ALWAYS run `delegate` in the background (each result an idle-gated
|
|
131
|
+
completion follow-up; a `tasks` fan-out is ONE follow-up when its last member settles), headless
|
|
132
|
+
`pi -p` ALWAYS blocks and returns results inline (nothing drains a follow-up after the single turn).
|
|
133
|
+
A finished child wakes the supervisor by itself, so any in-turn wait (a sleep, a peek loop, a
|
|
134
|
+
`timer`/`monitor` used as a wait) blocks the wake it waits for. The prompt layer says to end the
|
|
135
|
+
turn; the call-time guards (`PollGuard` on repeated `peek`/`result`, the long-`sleep` block) live
|
|
136
|
+
under `config.nudge` (`PI_PERSONA_NUDGE=off`). `council` and `flow` follow the same rule through
|
|
137
|
+
`tools/background-run.ts` (`createBackgroundRuns`): interactive, ONE tracker run rooted at
|
|
138
|
+
`async:<runId>` (receipt now, one completion follow-up); headless, the same run joined inline. A
|
|
139
|
+
persona's `council:` defaults resolve exactly as before when the call omits strategy/roster/params; the
|
|
140
|
+
mandated `orchestration:` path stays pre-turn and inline, and `/orchestrate`, `/flow` and that path
|
|
141
|
+
register their own abort under their root row (`visibleRoot`). A rejected `gate: true` returns
|
|
142
|
+
`stoppedAtGate` (`ok` stays false, so mandatory flows still fail closed; a tracker run settles
|
|
143
|
+
`stopped`). Stop-all, checkpoint waits, operator-result hand-off, run ids, restore honesty, flow journal
|
|
144
|
+
identity (`flowRunHash`) and retention are in
|
|
145
|
+
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md#supervision--the-waiting-model).
|
|
121
146
|
Periodic async status and each newly detected stall episode are durable, expandable operator-only
|
|
122
|
-
entries
|
|
123
|
-
|
|
147
|
+
entries; stalls never wake the model. Completions, asks, and unread bus messages keep their
|
|
148
|
+
existing actionable paths.
|
|
124
149
|
Message ids and run ids are separate: `intercom message { messageId }` retrieves retained bus
|
|
125
150
|
text, `intercom result { to: runId }` retrieves a settled run. Both explicit and automatic inbox
|
|
126
151
|
drains retain bounded history (256 messages / 256,000 body characters). Ask settlement clears
|
|
@@ -129,7 +154,7 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
|
|
|
129
154
|
reaches the supervisor as a follow-up or tool result (prompt-injection defense).
|
|
130
155
|
- **Delegation nudges** (`core/nudge.ts`, on by default): a `tool_result` hook watches the supervisor's
|
|
131
156
|
OWN tool stream and, when a delegating persona grinds heavy work by hand (output burn since the
|
|
132
|
-
last `delegate`/`council` crosses a threshold),
|
|
157
|
+
last `delegate`/`council`/`flow` crosses a threshold),
|
|
133
158
|
APPENDS a compact labelled checkpoint to that command's result for the model AND emits the same
|
|
134
159
|
checkpoint as a durable, expandable `pi-persona-nudge` TUI-only entry for the operator. It is never
|
|
135
160
|
hidden/context-only: tool renderers may suppress their own `content`, but cannot suppress the
|
|
@@ -137,10 +162,11 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
|
|
|
137
162
|
directive has decayed. Pure state machine (`DelegationNudge`); gated to
|
|
138
163
|
personas holding the `delegate` tool; sub-agents run in separate sessions so the hook only sees the
|
|
139
164
|
supervisor. Its counterweight is **`PersistenceNudge`** — a leg that comes back `[BLOCKED]`/`FLAG:
|
|
140
|
-
UNKNOWN` gets a "don't bank it yet" reminder on each of
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
165
|
+
UNKNOWN` gets a "don't bank it yet" reminder on each of its three delivery paths (the inline
|
|
166
|
+
`delegate`/`council`/`flow` result — headless only; the background completion
|
|
167
|
+
via `engine/async.ts`'s `renderCompletion`; and an explicit `intercom result` of a done run), but
|
|
168
|
+
they do not scan the same text: `observe` scans the whole sync tool result (every leg's body,
|
|
169
|
+
failures included; a headless `delegate` returns it unclipped), while `renderCompletion` scans only `status: "done"`
|
|
144
170
|
runs. A background leg that FAILED while emitting `[BLOCKED]` therefore gets the failure block but no
|
|
145
171
|
persistence note — deliberate (see the `renderCompletion` doc comment), not a bug to "fix" silently.
|
|
146
172
|
Nested reports from codemode's `ctx.executeTool` retain bounded provenance through Pi's explicit
|
|
@@ -148,12 +174,13 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
|
|
|
148
174
|
the surrender marker gets the note/card. Nested programmatic data is never patched with a reminder,
|
|
149
175
|
and discarded reports never generate an invisible one. Relay state clears at turn/session settlement.
|
|
150
176
|
`config.nudge` (`PI_PERSONA_NUDGE=off`) silences all of it: the `tool_result` hook (the by-hand
|
|
151
|
-
reminder and the sync-result persistence one) and
|
|
152
|
-
their `scan` through the same gate — so a
|
|
177
|
+
reminder and the sync-result persistence one) and the `renderCompletion` / `intercom result` paths,
|
|
178
|
+
which take their `scan` through the same gate — so a collected report carries no note either.
|
|
153
179
|
Its standing counterpart is the **delegation brief** (`core/brief.ts`): `before_agent_start` appends
|
|
154
|
-
a live, capability-filtered roster (agents
|
|
155
|
-
|
|
156
|
-
|
|
180
|
+
a live, capability-filtered roster (agents, teams and flows, with descriptions and gated flows tagged in
|
|
181
|
+
headless sessions) + a hand-off default (with one decision-class → method line, checked against the
|
|
182
|
+
registry) to the system-prompt TAIL every turn — discovery that survives context burn.
|
|
183
|
+
- **Sibling peer comm**: a strategy can opt a run into direct sibling messaging
|
|
157
184
|
(`AgentRunSpec.peers` — the `debate` strategy does). The child gets a `contact_peer` tool
|
|
158
185
|
(`bus/peers.ts`): `list`/`send`, ONE-WAY only (blocking stays supervisor-only, so peers can
|
|
159
186
|
never deadlock), peer list scoped per engine instance (never the whole bus), send budget 20,
|
|
@@ -161,7 +188,11 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
|
|
|
161
188
|
Delivery: the in-process engine's bridge steers incoming bus messages into the child session,
|
|
162
189
|
fenced with the sender attributed OUTSIDE the fence — the same bridge delivers the supervisor's
|
|
163
190
|
`intercom send` (previously a dead letter). Gated by `EffectiveCapabilities.canUseBus` (OFF iff
|
|
164
|
-
the persona explicitly denies `intercom`).
|
|
191
|
+
the persona explicitly denies `intercom`). Child-process legs use the broker's engine-scoped
|
|
192
|
+
peer roster; `contact_peer` is installed only when that run opts in and the bus is allowed.
|
|
193
|
+
Granted communication tools join a nonempty child tool allowlist; explicit empty lists and
|
|
194
|
+
tool exclusions still win. In-process supervisor contact additionally requires `coaching`;
|
|
195
|
+
broker-connected children expose it when the bus is allowed.
|
|
165
196
|
Design: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md#the-comm-plane-in-practice) + [`docs/STRATEGIES.md`](docs/STRATEGIES.md).
|
|
166
197
|
On the peer plane: `debate` and `pair` always; `map`/`synthesize` opt-in via `params.peers`.
|
|
167
198
|
`magi`/`judge`/`fanout` stay peer-less BY DESIGN — independence is their bias guard
|
|
@@ -169,38 +200,37 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
|
|
|
169
200
|
this. `compete` runs its competitors with `isolation: worktree` (REQUIRES a clean git repo; missing
|
|
170
201
|
repo/dirty checkout/worktree failure fails closed and never falls back to the real tree) and returns
|
|
171
202
|
the winning diff for the SUPERVISOR to apply.
|
|
172
|
-
- **
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
`
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
`
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
`
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
(`
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
Design: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md#exocom--the-external-plane).
|
|
203
|
+
- **Exocom** (`src/exocom/*`, `src/tools/exocom*.ts`; opt-in `PI_PERSONA_EXOCOM=1` / `--exocom`;
|
|
204
|
+
see [the collaboration guide](docs/COLLABORATION.md)): a flat external plane between independent,
|
|
205
|
+
top-level Pi sessions, separate from one supervisor's internal workers. Bare `--exocom` selects the
|
|
206
|
+
current workspace; exact `--exocom=Ab0T` joins that existing scope from another cwd through a
|
|
207
|
+
persistent, case-sensitive four-character Base62 alias. The scope selects registry, transport,
|
|
208
|
+
ledger and artifacts; each member still advertises its actual home workspace. The code is a
|
|
209
|
+
same-host/same-agent-dir join reference, not authentication.
|
|
210
|
+
`EXOCOM_TOOL_NAMES` contains 15 call-time-gated tools: `exocom_list`, `exocom_send`, `exocom_name`,
|
|
211
|
+
`exocom_claim`, `exocom_ask`, `exocom_answer`, `exocom_decline`, `exocom_wait`, `exocom_release`,
|
|
212
|
+
`exocom_progress`, `exocom_status`, `exocom_task`, `exocom_offer`, `exocom_publish`, and
|
|
213
|
+
`exocom_profile`. A joined foreign-workspace peer cannot use `exocom_claim`; write-set task create
|
|
214
|
+
and pickup also require local scope and callable claim permission. Ledger paths are advisory
|
|
215
|
+
coordination, never filesystem authorization.
|
|
216
|
+
`exocom_task create` declares a voluntary task but does not start work or reserve files. The
|
|
217
|
+
immutable `task_id` is the creation frame's `msg_id`; carry it with `work_key` for take, progress,
|
|
218
|
+
finish, offer and publish so a reused work key cannot select another generation. Write-set pickup
|
|
219
|
+
and its claim are one locked ledger transaction; read-only tasks may be taken from a foreign scope.
|
|
220
|
+
An optional `exocom_offer` expires in at most 24 hours (one hour by default) and creates no answer
|
|
221
|
+
obligation. Use `exocom_ask` for an explicit blocking question. `exocom_publish` shares a bounded,
|
|
222
|
+
explicitly written excerpt, not another session's terminal-result archive. Peer prose is fenced and
|
|
223
|
+
attributed using the registry identity.
|
|
224
|
+
Tasks, offers and evidence are each capped at 64 records and 128 KiB aggregate. Terminal or stale
|
|
225
|
+
task facts and expired offers are retained for up to one hour; evidence is retained for up to one
|
|
226
|
+
hour. `exocom_profile` reports self-described capabilities (up to 8 tags, 48 characters each) and
|
|
227
|
+
optional `available`/`busy`/`away` status; absent status is unknown, and profiles confer no access.
|
|
228
|
+
During a pending ask, only settlement, `exocom_name`, status, explicit collaboration reads and
|
|
229
|
+
read-only filesystem tools remain available: profile `get` is allowed, but `set` and `clear` are not.
|
|
230
|
+
Naming remains metadata and does not answer the ask. Joining requires `canUseBus` plus at least one
|
|
231
|
+
callable ask closer (`exocom_answer` or `exocom_decline`) and is rechecked on persona changes.
|
|
232
|
+
Design: [architecture](docs/ARCHITECTURE.md#exocom--the-external-plane) and
|
|
233
|
+
[collaboration guide](docs/COLLABORATION.md).
|
|
204
234
|
|
|
205
235
|
## Testing
|
|
206
236
|
|
|
@@ -232,13 +262,18 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
|
|
|
232
262
|
(`output`) or jobs (`exit`), with both `monitor` and `bash` permissions. Pure lifecycle is in
|
|
233
263
|
`src/core/monitor.ts`, process/delivery adapters in `src/monitor/`; use the existing idle notifier
|
|
234
264
|
and process-tree cleanup. Session-scoped, no restoration on restart. See [`docs/MONITORS.md`](docs/MONITORS.md).
|
|
265
|
+
Armed timers and active monitors also show as agent-tree rows (`monitor:<id>` / `timer:<id>`, never
|
|
266
|
+
agents): `src/ui/wake-rows.ts` is the pure projection, fed by the core seams `TimerScheduler`
|
|
267
|
+
`onArmed`/`onCancelled`, `MonitorManager` `onArmed`/`onRemoved` and `createMonitorSession`'s `observe`
|
|
268
|
+
option (a terminal event is observed before the permission gate). A countdown replaces the stall clock; `x`
|
|
269
|
+
cancels one via the stop registry; `X`, the `N agents` count and telemetry exclude them.
|
|
235
270
|
|
|
236
|
-
- `src/core/` — pure kernel: frontmatter, permissions, contract (+`parseContract`), config, discovery, fence (`fenceUntrusted`), brief (`buildDelegationBrief` — the per-turn roster + standing hand-off default; `buildExocomBrief` — the per-turn exocom peer roster, the peer-vs-sub-agent split, and the relevance bound on a peer exchange), timer (`TimerScheduler` — the alarm engine behind the `timer` tool), types.
|
|
271
|
+
- `src/core/` — pure kernel: frontmatter, permissions, contract (+`parseContract`), config, discovery, fence (`fenceUntrusted`), brief (`buildDelegationBrief` — the per-turn roster + standing hand-off default; `buildExocomBrief` — the per-turn exocom peer roster, the peer-vs-sub-agent split, and the relevance bound on a peer exchange), timer (`TimerScheduler` — the alarm engine behind the `timer` tool), session-runs (pure restore-notice helper: what a reload/resume lost + the run-id counter), types.
|
|
237
272
|
- `src/engine/` — `child.ts`, `inproc.ts` (default), `adapter.ts`, `async.ts` (async tracker/peek), `worktree.ts` (git-worktree isolation), `stream.ts` (event→state).
|
|
238
273
|
- `src/orchestration/` — `sdk.ts` (`agent`/`parallel`/`reduce`), `strategy.ts` (registry), `strategies/*.ts`, `voting.ts`, `flow*.ts` (DAG + JSONL journal + checkpoint gates), `roster.ts` (teams + `rosterSpec`: a roster member is a bare name OR an inline `{ agent, role, model, skills }` that specialises one agent — every strategy runs members through `rosterSpec`).
|
|
239
274
|
- `src/bus/` — `inproc.ts` (handle-based bus: send/ask/reply/onMessage), `contact.ts` (child `contact_supervisor` tool), `peers.ts` (child `contact_peer` sibling tool — one-way, engine-scoped), `broker/` (cross-process relay, on by default: `paths.ts`/`framing.ts`/`messages.ts` pure, `host.ts`/`client.ts` over `node:net`; `PI_PERSONA_BROKER=off` restores pre-broker spawn). `src/bridge.ts` — the child-mode-only wiring loaded when `PI_PERSONA_BUS` is set.
|
|
240
275
|
- `src/persona/` — `persona.ts` (parse + `expandCouncilPreset`), `controller.ts`, `gating.ts`, `orchestrate.ts`, `config-store.ts` (pure model helpers), `settings-store.ts` (sole persistent settings owner).
|
|
241
|
-
- `src/tools/` — `delegate.ts`, `intercom.ts`, `exocom.ts
|
|
276
|
+
- `src/tools/` — `delegate.ts`, `intercom.ts`, `exocom.ts`, `background-run.ts` (tracked background council/flow runs: `launch`/`settle`, `TrackedRun`). `src/ui/` — agent-tree/overlay, model-picker, `presentation.ts` (the collapsed-card compaction/sanitization helpers), `wake-rows.ts` (the monitor/timer → tree-row projection), `usage.ts`. `src/extension.ts` — the single ExtensionFactory (wires tools/commands/hooks/engines).
|
|
242
277
|
- Bundled data-driven assets (discovery precedence builtin < user `~/.pi/agent/persona` < project `.pi/`):
|
|
243
278
|
`personas/*.md`, `agents/*.md` (personas+agents share a folder, split by `persona: true` — a
|
|
244
279
|
persona and an agent must NOT share a name; e.g. `researcher` is the persona, `research` the agent),
|
|
@@ -248,7 +283,9 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
|
|
|
248
283
|
install shows NO personas until the user installs them. `/persona seed` copies missing defaults
|
|
249
284
|
in, `/persona restore` force-restores originals (`src/core/seed.ts`). First-run auto-install is
|
|
250
285
|
**opt-in**: off by default, enable with `PI_PERSONA_SEED=on` (guarded once by marker
|
|
251
|
-
`.pi-persona-seeded`).
|
|
286
|
+
`.pi-persona-seeded`). Release prep: add the previous tag's digest
|
|
287
|
+
to `LEGACY_SEEDED_DEFAULTS` for every changed persona/agent (the guard test in `seed.test.ts` prints the row).
|
|
288
|
+
F8 and `/doctor` point to `/persona seed` when no personas are installed. Contracts/presets/teams keep a builtin layer (they aren't personas).
|
|
252
289
|
- `scripts/` — `drive.ts` (headless `pi -p` log) + `drive-status.ts` (its pure exit-code/status projection), `control-test.mjs`, `flow-test.ts`, `live-suite.mjs` (every strategy/mode against a real model), `exocom-smoke.mjs` (real socket/pipe round-trip, chat + semantic claim; run via `npm run smoke:exocom`). `test/` — unit + integration.
|
|
253
290
|
|
|
254
291
|
## Adding a new X (data-driven — usually no core change)
|
|
@@ -268,14 +305,16 @@ their five preferences share the same registry/file. Do not hard-import a compan
|
|
|
268
305
|
while collecting settings. Flow port/idle changes are for the next shared-service start, never a restart
|
|
269
306
|
of a service other Pi sessions are using. Skill Optimizer remains independent.
|
|
270
307
|
|
|
271
|
-
1. **Strategy**: add `src/orchestration/strategies/<name>.ts` (export a `Strategy`), register it in `strategy.ts` `BUILTINS`, add a unit test.
|
|
308
|
+
1. **Strategy**: add `src/orchestration/strategies/<name>.ts` (export a `Strategy`), register it in `strategy.ts` `BUILTINS`, add a unit test. Declare `when` (one line), `roster` (positional roles, only where position matters) and `required` (param keys a call must carry) — the `council` tool description is generated from them (`strategyCatalog`) and refuses a missing required param up front; never hand-write a strategy list.
|
|
272
309
|
2. **Persona**: `personas/<name>.md` — frontmatter `persona: true` + optional `council:` / `orchestration:` / `delegation:` / `coaching: true`; runtime behavior is field-driven, never keyed to a persona name.
|
|
273
|
-
3. **Agent**: `agents/<name>.md` — optional `tools`, `model`, `
|
|
310
|
+
3. **Agent**: `agents/<name>.md` — optional `tools`, `model`, `writeSet` (repository-relative paths the
|
|
311
|
+
agent alone writes, e.g. `research` → `[.research/]`; inherited by a write-capable `delegate` leg that gives none, so
|
|
312
|
+
the ownership gate sees a declared owner — declarative, never enforced), `isolation: worktree`, `mcp: true`
|
|
274
313
|
(routes the leg through the child engine so `pi-mcp-adapter` initializes and its `mcp*`/direct
|
|
275
314
|
tools work — the default in-process engine leaves them "not initialized"; also settable per-leg
|
|
276
315
|
via `delegate`'s `mcp: true` / `AgentRunSpec.mcp`. Pass a server session id in the task to share
|
|
277
316
|
an HTTP backend's state).
|
|
278
|
-
4. **Team**: one line in `teams.yaml` (`name: [agent, ...]`), or per-member `- { agent, role, model?, skills? }` to build an ensemble of perspectives from ONE agent (e.g. `review` is one `reviewer` ×
|
|
317
|
+
4. **Team**: one line in `teams.yaml` (`name: [agent, ...]`), or per-member `- { agent, role, model?, skills? }` to build an ensemble of perspectives from ONE agent (e.g. `review` is one `reviewer` × 4 lens roles; `design` pairs `architect` + `reviewer` for `critic-loop`). Same-agent members are disambiguated in the live tree by a role hint (`reviewer · SECURITY`) via `rosterNodeKeys`/`roleHint` (`roster.ts`) + the SDK's per-run key (`sdk.ts`), so four lenses show as four steerable nodes — keep the seeding loops and the SDK key derivation in lockstep if you touch either.
|
|
279
318
|
5. **Flow**: `flows/<name>.flow.json` — phases + `needs`, optional `gate: true` (checkpoint).
|
|
280
319
|
6. **Contract**: `contracts/<name>.contract.json` (request via `outputContract`). **Preset**: `presets/<name>.preset.json`.
|
|
281
320
|
|