@aeondave/pi-persona 1.15.2
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 +249 -0
- package/CHANGELOG.md +260 -0
- package/LICENSE +21 -0
- package/README.md +172 -0
- package/agents/balthasar.md +32 -0
- package/agents/casper.md +33 -0
- package/agents/evidence-verifier.md +23 -0
- package/agents/melchior.md +32 -0
- package/agents/operator.md +63 -0
- package/agents/research.md +58 -0
- package/agents/reviewer.md +49 -0
- package/agents/scout.md +23 -0
- package/agents/verifier.md +21 -0
- package/assets/banner.png +0 -0
- package/assets/demo1.gif +0 -0
- package/assets/demo1.mp4 +0 -0
- package/assets/workflow.png +0 -0
- package/contracts/finding.contract.json +9 -0
- package/docs/ARCHITECTURE.md +727 -0
- package/docs/EXPERIENCE.md +96 -0
- package/docs/MONITORS.md +84 -0
- package/docs/README.md +53 -0
- package/docs/REFERENCE.md +408 -0
- package/docs/SPINE.md +152 -0
- package/docs/STRATEGIES.md +215 -0
- package/docs/TELEMETRY.md +9 -0
- package/flows/deep-review.flow.json +8 -0
- package/flows/gated-build.flow.json +9 -0
- package/package.json +106 -0
- package/personas/audit.md +29 -0
- package/personas/dev.md +52 -0
- package/personas/elite.md +256 -0
- package/personas/judge.md +32 -0
- package/personas/magi.md +41 -0
- package/personas/planner.md +37 -0
- package/personas/researcher.md +37 -0
- package/personas/swarm.md +38 -0
- package/personas/verify.md +31 -0
- package/presets/magi-rounds.preset.json +5 -0
- package/prompts/spine.md +11 -0
- package/prompts/spine.worker.md +9 -0
- package/src/agents/agent.ts +78 -0
- package/src/bridge.ts +209 -0
- package/src/bus/broker/client.ts +379 -0
- package/src/bus/broker/framing.ts +43 -0
- package/src/bus/broker/host.ts +407 -0
- package/src/bus/broker/messages.ts +87 -0
- package/src/bus/broker/paths.ts +31 -0
- package/src/bus/contact.ts +145 -0
- package/src/bus/inproc.ts +279 -0
- package/src/bus/peers.ts +114 -0
- package/src/core/brief.ts +356 -0
- package/src/core/capabilities.ts +114 -0
- package/src/core/config.ts +228 -0
- package/src/core/contract.ts +391 -0
- package/src/core/data-root.ts +260 -0
- package/src/core/discovery.ts +33 -0
- package/src/core/display-label.ts +47 -0
- package/src/core/fence.ts +151 -0
- package/src/core/format.ts +13 -0
- package/src/core/frontmatter.ts +202 -0
- package/src/core/models.ts +192 -0
- package/src/core/monitor.ts +415 -0
- package/src/core/naming.ts +42 -0
- package/src/core/nudge.ts +238 -0
- package/src/core/ownership.ts +102 -0
- package/src/core/permissions.ts +56 -0
- package/src/core/pi-compat.ts +50 -0
- package/src/core/seed.ts +770 -0
- package/src/core/session-identity.ts +89 -0
- package/src/core/time.ts +202 -0
- package/src/core/timer.ts +221 -0
- package/src/core/types.ts +28 -0
- package/src/engine/adapter.ts +257 -0
- package/src/engine/async.ts +898 -0
- package/src/engine/change-report.ts +143 -0
- package/src/engine/child.ts +532 -0
- package/src/engine/errors.ts +30 -0
- package/src/engine/fallback.ts +57 -0
- package/src/engine/handles.ts +21 -0
- package/src/engine/inproc.ts +857 -0
- package/src/engine/signals.ts +11 -0
- package/src/engine/spec-preflight.ts +33 -0
- package/src/engine/stream.ts +369 -0
- package/src/engine/worktree.ts +144 -0
- package/src/exocom/activation.ts +31 -0
- package/src/exocom/codes.ts +261 -0
- package/src/exocom/envelope.ts +180 -0
- package/src/exocom/gate.ts +6 -0
- package/src/exocom/guards.ts +45 -0
- package/src/exocom/inbound.ts +141 -0
- package/src/exocom/install.ts +970 -0
- package/src/exocom/ledger.ts +603 -0
- package/src/exocom/limits.ts +20 -0
- package/src/exocom/paths.ts +35 -0
- package/src/exocom/plane.ts +1116 -0
- package/src/exocom/registry.ts +307 -0
- package/src/exocom/scope.ts +42 -0
- package/src/exocom/status.ts +86 -0
- package/src/exocom/untrusted.ts +40 -0
- package/src/exocom/wait.ts +23 -0
- package/src/exocom/write-guard.ts +89 -0
- package/src/extension/broker-host.ts +181 -0
- package/src/extension/clock.ts +14 -0
- package/src/extension/engine.ts +321 -0
- package/src/extension/hooks.ts +796 -0
- package/src/extension/identity.ts +244 -0
- package/src/extension/shared.ts +175 -0
- package/src/extension.ts +2221 -0
- package/src/loader.ts +218 -0
- package/src/monitor/process.ts +116 -0
- package/src/monitor/session.ts +61 -0
- package/src/orchestration/flow-journal.ts +86 -0
- package/src/orchestration/flow-run.ts +301 -0
- package/src/orchestration/flow.ts +125 -0
- package/src/orchestration/judge.ts +78 -0
- package/src/orchestration/model-retry.ts +85 -0
- package/src/orchestration/parallel.ts +107 -0
- package/src/orchestration/params.ts +23 -0
- package/src/orchestration/reducers.ts +123 -0
- package/src/orchestration/render.ts +127 -0
- package/src/orchestration/roster.ts +133 -0
- package/src/orchestration/sdk.ts +326 -0
- package/src/orchestration/strategies/compete.ts +182 -0
- package/src/orchestration/strategies/council-rounds.ts +124 -0
- package/src/orchestration/strategies/critic-loop.ts +168 -0
- package/src/orchestration/strategies/debate.ts +126 -0
- package/src/orchestration/strategies/fanout.ts +20 -0
- package/src/orchestration/strategies/judge.ts +117 -0
- package/src/orchestration/strategies/magi.ts +239 -0
- package/src/orchestration/strategies/map.ts +327 -0
- package/src/orchestration/strategies/pair.ts +72 -0
- package/src/orchestration/strategies/pipeline.ts +91 -0
- package/src/orchestration/strategies/synthesize.ts +99 -0
- package/src/orchestration/strategy.ts +49 -0
- package/src/orchestration/types.ts +31 -0
- package/src/orchestration/voting.ts +126 -0
- package/src/persona/config-store.ts +215 -0
- package/src/persona/controller.ts +173 -0
- package/src/persona/gating.ts +82 -0
- package/src/persona/orchestrate.ts +83 -0
- package/src/persona/persona.ts +294 -0
- package/src/persona/spine.ts +221 -0
- package/src/persona/state.ts +28 -0
- package/src/telemetry/contract.ts +244 -0
- package/src/telemetry/paths.ts +14 -0
- package/src/telemetry/producer.ts +390 -0
- package/src/tools/council.ts +200 -0
- package/src/tools/delegate-tool.ts +637 -0
- package/src/tools/delegate.ts +661 -0
- package/src/tools/exocom-work.ts +328 -0
- package/src/tools/exocom.ts +476 -0
- package/src/tools/flow.ts +117 -0
- package/src/tools/intercom-tool.ts +292 -0
- package/src/tools/intercom.ts +181 -0
- package/src/tools/models.ts +39 -0
- package/src/tools/monitor.ts +66 -0
- package/src/tools/timer.ts +105 -0
- package/src/ui/agent-overlay.ts +526 -0
- package/src/ui/agent-tree.ts +307 -0
- package/src/ui/live-clock.ts +42 -0
- package/src/ui/model-picker.ts +160 -0
- package/src/ui/presentation.ts +170 -0
- package/src/ui/usage.ts +133 -0
- package/teams.yaml +27 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Working comfortably with Pi Persona
|
|
2
|
+
|
|
3
|
+
Choose the outcome you want, describe what counts as finished, and let the supervisor coordinate
|
|
4
|
+
the work. You can inspect or redirect individual workers without managing every hand-off.
|
|
5
|
+
|
|
6
|
+
## Choose a starting persona
|
|
7
|
+
|
|
8
|
+
| Your request | Start with | What to expect |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| Implement or fix something | `dev` | A scoped change, checks, and a concise explanation of the result |
|
|
11
|
+
| Review a change | `audit` | Prioritized, evidence-backed findings; edits only when requested |
|
|
12
|
+
| Turn an idea into an implementation plan | `planner` | Decisions, dependencies, and verifiable steps without changing application code |
|
|
13
|
+
| Investigate a question | `researcher` | Sources, conclusions, uncertainty, and durable notes when the scope warrants them |
|
|
14
|
+
| Apply one operation across many independent items | `swarm` | Explicit coverage of completed, failed, and remaining items |
|
|
15
|
+
| Repair a failing build or verify an implementation | `verify` | Fresh checks on the actual tree; repairs only when requested, with unresolved failures stated clearly |
|
|
16
|
+
|
|
17
|
+
Switch with `/persona <name>` or F8 (the default shortcut). `/persona seed` installs missing defaults. Existing customized
|
|
18
|
+
persona files remain yours; `/persona restore` replaces installed defaults, so use it only when
|
|
19
|
+
you intend to discard those customizations.
|
|
20
|
+
|
|
21
|
+
Restart Pi after updating the extension. Known, untouched defaults upgrade automatically; customized
|
|
22
|
+
copies remain unchanged and can be compared with the bundled persona before adopting individual edits.
|
|
23
|
+
|
|
24
|
+
An effective request names the intended result and its constraints. For example:
|
|
25
|
+
|
|
26
|
+
> Fix the cancellation bug. Preserve the public API and my existing edits. Delegate independent
|
|
27
|
+
> investigations, implement the fix, and run the relevant checks. Tell me what changed and what
|
|
28
|
+
> remains unverified.
|
|
29
|
+
|
|
30
|
+
## Follow the work without constant polling
|
|
31
|
+
|
|
32
|
+
Your persona describes a role; your session has its own personal handle. Pi chooses it on the first
|
|
33
|
+
task or inbound Exocom request when the naming tool is permitted. Until then it shows a distinct
|
|
34
|
+
session suffix. The name survives persona changes and resume. `agent_name` sets it in standalone
|
|
35
|
+
use; `exocom_name` sets the same identity when connected to peers. The leader can assign each
|
|
36
|
+
delegated worker a `name` before launch, which reaches both its display and its first prompt.
|
|
37
|
+
|
|
38
|
+
For a fixed-time reminder, ask for a timer. For a build finishing or a file, log, or system event,
|
|
39
|
+
ask for a monitor. Pi runs a small event-producing program and brings the result back when the
|
|
40
|
+
supervisor is free. Keep the session open, and cancel a watch when its purpose ends. See
|
|
41
|
+
[time and event wakes](MONITORS.md) for examples and limits.
|
|
42
|
+
|
|
43
|
+
- **F9** opens the agent tree. Every running row shows its elapsed time and switches to `⚠ stalled
|
|
44
|
+
<duration>` once it has gone 90 seconds without progress — the same threshold behind the
|
|
45
|
+
supervisor's stall alert. Enter opens a selectable worker's output; `s` sends a course correction;
|
|
46
|
+
`x` requests cancellation and appears only when the run can actually be stopped, marking the row
|
|
47
|
+
`stopping…` at once; a stop that can't be applied says so instead of doing nothing. Escape goes
|
|
48
|
+
back or closes the panel.
|
|
49
|
+
- **`/peek`** gives a compact progress view. A quiet worker is a reason to inspect its last
|
|
50
|
+
progress and current activity, not to launch a duplicate immediately.
|
|
51
|
+
- **Background results arrive automatically.** A supervisor can continue independent work while
|
|
52
|
+
they run. `intercom wait` joins results when the next step depends on them.
|
|
53
|
+
- **Answer a waiting worker before joining it.** A coaching worker may need a decision from its
|
|
54
|
+
supervisor before it can finish. An unanswered question is actionable work.
|
|
55
|
+
- **Steering is a request.** Check the subsequent output to see whether the worker incorporated
|
|
56
|
+
it. Check the terminal result after requesting cancellation; changes already made are not undone.
|
|
57
|
+
|
|
58
|
+
A truncated message includes a message id. The supervisor can retrieve its retained body with
|
|
59
|
+
`intercom { action: "message", messageId: "m1" }`. A worker's final report has a run id instead:
|
|
60
|
+
`intercom { action: "result", to: "run-1" }`. Retention is bounded and session-local, so save any
|
|
61
|
+
evidence needed beyond the current session as a project artifact.
|
|
62
|
+
|
|
63
|
+
For a long task, useful updates say what changed, what is blocked, and what happens next. Worker
|
|
64
|
+
names help distinguish concurrent work; the final answer should use file names and concrete
|
|
65
|
+
outcomes that make sense without remembering those names.
|
|
66
|
+
|
|
67
|
+
## Work with another Pi through Exocom
|
|
68
|
+
|
|
69
|
+
Use Intercom for this supervisor's workers and Exocom for independent Pi sessions. Ask a peer for
|
|
70
|
+
a relevant second opinion or coordinate work already in progress. A bounded implementation task
|
|
71
|
+
belongs in a worker brief with explicit ownership and a success criterion.
|
|
72
|
+
|
|
73
|
+
When Exocom is enabled, use its listed targets to keep messages attached to the right session.
|
|
74
|
+
Exchange decisions and evidence when they affect the work; acknowledgement-only conversations
|
|
75
|
+
add noise. If a peer has joined from another workspace, agree which workspace owns each artifact.
|
|
76
|
+
That peer's membership does not grant it a write claim in the selected workspace.
|
|
77
|
+
|
|
78
|
+
`exocom_status` (or `/exocom`) shows who owns what right now: your open claims, a peer's open
|
|
79
|
+
claims, and any asks waiting on either side. Claims are advisory, not a lock — if you write into a
|
|
80
|
+
path a peer has claimed, that write is blocked once with a reminder to coordinate or claim it
|
|
81
|
+
yourself first; asking again on the same path goes through, so the warning never repeats for work
|
|
82
|
+
you've already been told about.
|
|
83
|
+
|
|
84
|
+
## Read completion as an evidence statement
|
|
85
|
+
|
|
86
|
+
A useful completion tells you what changed, which checks ran against the final state, and what
|
|
87
|
+
still needs attention. A successful review, a passing mocked test, and a live integration check
|
|
88
|
+
answer different questions. Skipped checks and partial batch coverage remain visible.
|
|
89
|
+
|
|
90
|
+
A worker that did not run in its own isolated worktree has its report followed by a "files changed"
|
|
91
|
+
block: every path `git status` saw move since the worker started, flagging anything outside what it
|
|
92
|
+
was asked to touch. Treat it as a same-checkout approximation, not a private diff — a sibling
|
|
93
|
+
running at the same time can touch the same file.
|
|
94
|
+
|
|
95
|
+
The bundled persona prompts guide these habits. Tool capabilities, engine limits, and filesystem
|
|
96
|
+
isolation are enforced separately by the runtime; a persona's prose does not create a sandbox.
|
package/docs/MONITORS.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Time and event wakes
|
|
2
|
+
|
|
3
|
+
The supervisor receives a UTC and local clock snapshot when a run starts, alongside the original
|
|
4
|
+
session start and elapsed duration. The precise clock arrives as hidden model-visible context,
|
|
5
|
+
preserving the cached system prefix. During a long run it can call `timer` with `{"action":"now"}`
|
|
6
|
+
to refresh the clock. This is sampled wall-clock time, not a continuously updated model sense.
|
|
7
|
+
|
|
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 wake the supervisor automatically.
|
|
10
|
+
|
|
11
|
+
## Background programs
|
|
12
|
+
|
|
13
|
+
`monitor` starts an executable with literal arguments in the current workspace and returns an id
|
|
14
|
+
immediately. There is no implicit shell. For shell syntax, pass a script file to the appropriate
|
|
15
|
+
shell. Windows `.cmd` launchers likewise need an explicit shell; a native executable or script
|
|
16
|
+
interpreter avoids platform-specific quoting.
|
|
17
|
+
|
|
18
|
+
| Mode | When the model wakes | Typical source |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| `exit` | The launched program finishes, with its exit code and bounded output tail | Build or local job |
|
|
21
|
+
| `output` | A nonempty stdout line arrives | File watcher, filtered log tail, system-event subscription, service adapter |
|
|
22
|
+
|
|
23
|
+
For example, start an existing build script and get its completion:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{"action":"arm","command":"node","args":["scripts/build.mjs"],"label":"build finished","mode":"exit","timeoutSeconds":900}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or start an existing event adapter that prints only meaningful state changes:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{"action":"arm","command":"node","args":["scripts/watch-status.mjs"],"label":"status changed","mode":"output","timeoutSeconds":600,"maxEvents":3}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Adapters can use native file/system subscriptions, a program's streaming API, or inexpensive
|
|
36
|
+
polling inside the program when no subscription exists. The model does not run a polling loop.
|
|
37
|
+
Print one short event per line to stdout; send diagnostic chatter to stderr. Flush output promptly
|
|
38
|
+
(for Python, use `-u` or `flush=True`). Repeated identical lines are ignored for that watch.
|
|
39
|
+
Keep complete logs in the program's normal log file if they are needed later.
|
|
40
|
+
|
|
41
|
+
The model can continue independent work while a monitor runs. Events wait while it is busy and
|
|
42
|
+
arrive together at an idle boundary. When only the event remains, it should end its turn. Natural
|
|
43
|
+
requests such as “let me know when this build finishes” are enough; tool parameters are for the
|
|
44
|
+
model or an integration, not something the user needs to manage.
|
|
45
|
+
|
|
46
|
+
## Lifetime and limits
|
|
47
|
+
|
|
48
|
+
- `list` shows active watches; `cancel` with the returned `id` stops the owned process tree and
|
|
49
|
+
removes that watch's queued events. It never stops an unrelated job merely because its status
|
|
50
|
+
is being observed by an adapter.
|
|
51
|
+
- Defaults are one output event and a ten-minute deadline. Limits are eight active monitors,
|
|
52
|
+
twenty distinct output events per monitor, and twenty-four hours of lifetime.
|
|
53
|
+
- Exit, launch errors and deadline expiry produce terminal notices. Reaching the output event
|
|
54
|
+
count ends the watch immediately; the notice says the watch ended, without claiming the job succeeded.
|
|
55
|
+
- Lines and diagnostics are bounded. The session retains at most 64 pending events, delivers up
|
|
56
|
+
to four per batch, and reports omitted older events if a busy model cannot keep up.
|
|
57
|
+
- Keep Pi open. Watches are in memory and stop on shutdown, reload, or session replacement;
|
|
58
|
+
they are not restored on resume. A headless `pi -p` invocation that exits after its answer is
|
|
59
|
+
not a persistent monitoring service.
|
|
60
|
+
|
|
61
|
+
## Permissions and architecture
|
|
62
|
+
|
|
63
|
+
Starting a command requires both `monitor` and `bash` to be active and allowed by the persona.
|
|
64
|
+
Changing to a persona that removes either permission stops its monitors and discards queued
|
|
65
|
+
events. Normal Exocom pending-question gates apply to monitor calls as well.
|
|
66
|
+
|
|
67
|
+
This is command execution with the host user's access, not an OS sandbox or a read-only guarantee.
|
|
68
|
+
An extension that enforces command-specific policy through `tool_call` must inspect `monitor`
|
|
69
|
+
as well as `bash`; Pi Persona does not synthesize another extension's Bash hooks. External event
|
|
70
|
+
text is fenced as untrusted data before delivery, with runtime id, time and outcome outside the fence.
|
|
71
|
+
|
|
72
|
+
The pure `src/core/monitor.ts` owns limits and lifecycle. `src/monitor/process.ts` adapts a process
|
|
73
|
+
using the existing process-tree cleanup helper. `src/monitor/session.ts` connects bounded events
|
|
74
|
+
to the existing `IdleCoalescingNotifier` and `sendPersonaFollowUp` path. No separate wake broker,
|
|
75
|
+
public listener, durable queue, or new orchestration engine is introduced.
|
|
76
|
+
|
|
77
|
+
The design follows the background-program model described in the official
|
|
78
|
+
[Claude Monitor documentation](https://code.claude.com/docs/en/tools-reference#monitor-tool).
|
|
79
|
+
Protocol-specific integrations can be ordinary adapter programs; direct WebSocket connections
|
|
80
|
+
and persistent services are outside this tool's current scope.
|
|
81
|
+
|
|
82
|
+
For live verification, `scripts/monitor-smoke.mjs` runs a persistent Pi RPC session and checks an
|
|
83
|
+
automatic model turn after a local event. It requires an explicit `LIVE_MODEL=provider/id` because
|
|
84
|
+
it spends provider tokens. Unit and integration tests use deterministic clocks and local programs.
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# pi-persona documentation
|
|
2
|
+
|
|
3
|
+
This folder contains the long-form documentation that defines how the project is designed and run.
|
|
4
|
+
|
|
5
|
+
## Canonical docs
|
|
6
|
+
|
|
7
|
+
- [`ARCHITECTURE.md`](./ARCHITECTURE.md)
|
|
8
|
+
- Core architecture, invariants, module boundaries, and design contracts.
|
|
9
|
+
- [`STRATEGIES.md`](./STRATEGIES.md)
|
|
10
|
+
- Strategy SDK and built-in orchestration behavior.
|
|
11
|
+
- [`SPINE.md`](./SPINE.md)
|
|
12
|
+
- Shared behavioral spine prompt layer and rollout controls.
|
|
13
|
+
- [`TELEMETRY.md`](./TELEMETRY.md)
|
|
14
|
+
- Vendor-neutral observer contract, privacy boundary, persistence, and consumer conformance.
|
|
15
|
+
- [`EXPERIENCE.md`](./EXPERIENCE.md)
|
|
16
|
+
- Choosing a persona, supervising background work, and collaborating through Exocom.
|
|
17
|
+
- [`MONITORS.md`](./MONITORS.md)
|
|
18
|
+
- Clock snapshots, timers, and background event sources that wake the supervisor.
|
|
19
|
+
- [`REFERENCE.md`](./REFERENCE.md)
|
|
20
|
+
- Canonical Core API, configuration, environment variables, commands, and data-driven recipes.
|
|
21
|
+
|
|
22
|
+
## Quick map
|
|
23
|
+
|
|
24
|
+
- **For users / operators:** start from [README](../README.md) and [EXPERIENCE.md](./EXPERIENCE.md); use `REFERENCE.md` for configuration and recipes.
|
|
25
|
+
- **For contributors:** begin at `ARCHITECTURE.md`, then `REFERENCE.md` for runtime surfaces and `STRATEGIES.md` for implementation details.
|
|
26
|
+
- **For behavior-layer changes:** consult `SPINE.md` and `src/core` / `src/persona/spine.ts` together.
|
|
27
|
+
- **For telemetry producers or consumers:** start with `TELEMETRY.md` and its conformance corpus.
|
|
28
|
+
|
|
29
|
+
## Documentation maintenance notes
|
|
30
|
+
|
|
31
|
+
When touching this folder:
|
|
32
|
+
|
|
33
|
+
- Keep names stable (`ARCHITECTURE.md`, `STRATEGIES.md`, `SPINE.md`, `REFERENCE.md`) because many docs and comments link to them directly.
|
|
34
|
+
- Prefer links to this folder over copying duplicate prose into code comments.
|
|
35
|
+
- Update both this map and inbound links when adding new authoritative docs.
|
|
36
|
+
- A few factual claims are machine-checked by `test/unit/docs/doc-claims.test.ts`. Know its blind
|
|
37
|
+
spots before trusting it:
|
|
38
|
+
- **Env names.** It collects the whole `PI_*` identifiers `src/**/*.ts` actually reads and fails
|
|
39
|
+
when a documented name is not one of them, so a documented name that is merely a *prefix* of a
|
|
40
|
+
real one is caught. It still never reads `scripts/`, so a variable only that tree consumes
|
|
41
|
+
reads as undocumented-in-reverse: the check is one-directional (docs → source), and a source
|
|
42
|
+
variable nothing documents is not flagged at all.
|
|
43
|
+
- **Strategy table.** It fails when a registered strategy has anything other than exactly one row
|
|
44
|
+
in the canonical table in `STRATEGIES.md` (the one headed `| Strategy | … | Params …`), or when a
|
|
45
|
+
declared param is not backticked in a cell *after* the row's name. It still cannot tell whether
|
|
46
|
+
the *description* of a param or its default is correct.
|
|
47
|
+
- **Skip count.** It scans every `test/**/*.test.ts` for skip markers (an options-object `skip` key
|
|
48
|
+
or a `.skip` shorthand), and fails unless AGENTS.md's stated word, its `skipped N` on Windows and
|
|
49
|
+
its `skipped 0` elsewhere all match, every marker is gated on `process.platform === "win32"`, and
|
|
50
|
+
AGENTS.md names each file carrying one. It counts markers rather than running the runner, so a
|
|
51
|
+
marker on a suite of several skipped subtests would count once where the runner counts each.
|
|
52
|
+
- Everything else here is prose a reader has to check against the code — so state behavior precisely
|
|
53
|
+
enough to be falsifiable, and cite the module that settles it.
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
# pi-persona technical reference
|
|
2
|
+
|
|
3
|
+
This is the canonical technical guide for the runtime surfaces that users configure through
|
|
4
|
+
personas, agents, teams, flows, contracts, presets, and environment variables. The design contract
|
|
5
|
+
lives in [`ARCHITECTURE.md`](./ARCHITECTURE.md); strategy shapes and their complete parameter table
|
|
6
|
+
live in [`STRATEGIES.md`](./STRATEGIES.md). User-oriented orientation and operating examples start
|
|
7
|
+
in the root [`README.md`](../README.md) and [`EXPERIENCE.md`](./EXPERIENCE.md).
|
|
8
|
+
|
|
9
|
+
## Core API
|
|
10
|
+
|
|
11
|
+
The runtime is composed from a small, fixed set of primitives. A strategy is a TypeScript file
|
|
12
|
+
composing the **Strategy SDK**; a persona picks whether and how those run. `magi` is a `.md` persona
|
|
13
|
+
plus a file that calls `parallel` and `reduce.vote`.
|
|
14
|
+
|
|
15
|
+
**Strategy SDK** (`src/orchestration/sdk.ts`) — the primitives available to a strategy:
|
|
16
|
+
|
|
17
|
+
| Primitive | Does |
|
|
18
|
+
|---|---|
|
|
19
|
+
| `agent(spec)` | run one sub-agent and return a structured `AgentResult`; `spec` may carry `name`, model, tools, skills, or `outputContract` |
|
|
20
|
+
| `parallel(thunks, {concurrency})` | run many at once, bounded by the run limits; this also provides the basis of `map` |
|
|
21
|
+
| `reduce.aggregate(results)` | merge N results into one, used by fan-out |
|
|
22
|
+
| `reduce.vote(candidates, opts)` | tally the candidates' own votes and preserve `winner`, `tie`, `no_consensus`, `invalid_outputs`, and dissent |
|
|
23
|
+
| `reduce.judge(candidates, order?)` | anonymise and label candidates for an impartial judge, then map the verdict back with `pick(label)` |
|
|
24
|
+
| `roster.team(name)` | resolve the agents of a named team |
|
|
25
|
+
| `signal` · `limits` · `log` | cooperative abort, admission/runtime limits, and progress reporting |
|
|
26
|
+
| series and loops | plain `await` and `for`; strategies are TypeScript, so pipelines and critic loops are ordinary code |
|
|
27
|
+
|
|
28
|
+
The complete built-in strategy catalog and each strategy's declared parameters are maintained in
|
|
29
|
+
[`STRATEGIES.md`](./STRATEGIES.md). Parameters are declared per strategy and looked up by
|
|
30
|
+
`knownParams()`; `/doctor` exposes the same schema live. Unknown parameter keys warn but do not
|
|
31
|
+
hard-fail.
|
|
32
|
+
|
|
33
|
+
**Supervisor surface** — the tools and persona fields that drive those primitives:
|
|
34
|
+
|
|
35
|
+
| Surface | Does |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `delegate` tool | spawn one or more sub-agents; interactive calls are background-first, while `sync: true` blocks the turn |
|
|
38
|
+
| `council` tool | run the selected strategy over a roster and return its result; voting strategies preserve tally and dissent |
|
|
39
|
+
| `intercom` tool | observe and control internal runs with `peek`, `result`, `wait`, `steer`, and `stop`; `list`, `inbox`, `message`, `reply`, and `send` drive the coaching bus |
|
|
40
|
+
| `timer` tool | read the fresh clock with `now`, or schedule an idle wake with `arm`, `cancel`, and `list`; alarms are one-shot and in-memory per session |
|
|
41
|
+
| `monitor` tool | run a bounded job (`mode: exit`) or event-producing program (`mode: output`) and wake the supervisor; see [`MONITORS.md`](./MONITORS.md) |
|
|
42
|
+
| `flow` tool and `/flow` | run a journaled DAG of strategies; `gate: true` creates an approval checkpoint |
|
|
43
|
+
| `models` tool | list or search authenticated model ids in `provider/id` form; the session provider is marked |
|
|
44
|
+
| persona `mode:` | choose `solo`, `parallel`, `pipeline`, `strategy:<name>`, or `flow:<name>` |
|
|
45
|
+
| persona `coaching:` | give children `contact_supervisor` for progress and blocking decisions |
|
|
46
|
+
| persona `delegation:` | require briefs, set an output contract, schedule disjoint writes, and order fresh verification |
|
|
47
|
+
| `isolation: worktree` | run in a clean throwaway Git worktree and return an exported diff; non-Git, dirty, or oversized cases fail closed |
|
|
48
|
+
| `council: { preset }` | expand a reusable `presets/<name>.preset.json`; authored fields override the preset |
|
|
49
|
+
| `contracts/*.json` | define a hot-editable structured return requested through `outputContract` and pinned per run |
|
|
50
|
+
|
|
51
|
+
The delegate tool's optional `name` is carried into `AgentRunSpec.name` and reaches both engine
|
|
52
|
+
backends, keeping a caller-provided run label available in the live tree and runtime result.
|
|
53
|
+
|
|
54
|
+
`outputContract` takes a contract **name**, not an inline shape — `/doctor` lists what's installed
|
|
55
|
+
(the only built-in is `default`). Naming one that isn't installed is rejected before any worker
|
|
56
|
+
spawns, checked across every task in a parallel batch: `delegate: unknown output contract(s) "x" —
|
|
57
|
+
nothing was spawned. Installed contracts: default, finding` (the list is capped at 16 names; a
|
|
58
|
+
`, …` marker is appended only when more than 16 are installed).
|
|
59
|
+
|
|
60
|
+
### Supervising running sub-agents — the `intercom` plane
|
|
61
|
+
|
|
62
|
+
The supervisor's internal communication with children has three layers:
|
|
63
|
+
|
|
64
|
+
| Layer | Needs | What you get |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| **Observe and control** | any persona | `peek` watches async sub-agents; `wait` joins them; `steer` sends a soft correction; `stop` requests cancellation. The `f9` overlay provides the same controls (`s`, `x`). Cancelling a worker does not undo existing changes |
|
|
67
|
+
| **Retrieve** | any persona | `result { to }` returns one retained run payload; `message { messageId }` returns one retained bus message. History is bounded to 256 messages and 256,000 body characters, and retrieval never starts a worker |
|
|
68
|
+
| **Message bus** | `coaching: true` | children get `contact_supervisor`; progress appears in results and `intercom inbox`, while a blocking `decision` wakes the supervisor for `intercom reply` |
|
|
69
|
+
| **Sibling peer comm** | strategy opt-in | `debate` and `pair` members always get one-way `contact_peer`; `map` and `synthesize` add it with `params: { peers: true }` |
|
|
70
|
+
|
|
71
|
+
Delegated output is untrusted and is fenced before it reaches the supervisor. Async runs report
|
|
72
|
+
failures to the supervisor, and a repeated identical failed delegation is stopped by the runtime
|
|
73
|
+
ledger before another child is spawned. A run whose model's provider fails at call time (auth,
|
|
74
|
+
outage, 5xx) may retry the same model id through a fallback provider; each reroute surfaces to the
|
|
75
|
+
supervisor as a warning toast, `<agent>: <from> failed, retrying on <to>`.
|
|
76
|
+
|
|
77
|
+
Any leg that does NOT run in `isolation: worktree` shares the real checkout, so its result gets a
|
|
78
|
+
"what changed" block appended: `--- FILES CHANGED DURING THIS LEG (shared checkout; parallel legs
|
|
79
|
+
may overlap) ---` followed by one `- <path> (<M|A|D|R|?>)` line per path (capped at 40, `+N more`
|
|
80
|
+
beyond that); a changed path outside the leg's own declared `writeSet` is flagged
|
|
81
|
+
`⚠ outside declared writeSet`. This is a `git status` before/after snapshot, not a private diff — a
|
|
82
|
+
parallel sibling touching the same file can appear here too — and it is skipped when there is
|
|
83
|
+
nothing to report, or when the leg IS worktree-isolated (that path already returns a real unified
|
|
84
|
+
diff instead).
|
|
85
|
+
|
|
86
|
+
The cross-process broker is on by default for child-engine, worktree, and MCP legs. It provides the
|
|
87
|
+
same supervisor communication surface over a session-scoped POSIX socket or Windows named pipe.
|
|
88
|
+
`PI_PERSONA_BROKER=off` restores the pre-broker child spawn behavior. See the comm-plane contract in
|
|
89
|
+
[`ARCHITECTURE.md`](./ARCHITECTURE.md#the-comm-plane-in-practice).
|
|
90
|
+
|
|
91
|
+
> **MCP in sub-agents.** A normal in-process leg has no MCP connection. Set `mcp: true` in an agent
|
|
92
|
+
> definition or delegation task to route it through the child engine, which initializes MCP from
|
|
93
|
+
> `~/.pi/agent/mcp.json`. A fresh UI-less child cannot complete an interactive OAuth flow, so
|
|
94
|
+
> authenticate the server in a normal session first. A backend that keys state by a session id must
|
|
95
|
+
> receive that id in the task. A local registration, stdio process, or loopback endpoint does not
|
|
96
|
+
> prove local target egress; verify source routing with the executor and canary required by the
|
|
97
|
+
> engagement. This is a behavioral boundary, not a network sandbox.
|
|
98
|
+
|
|
99
|
+
### Identity and Exocom
|
|
100
|
+
|
|
101
|
+
An unnamed standalone session receives a provisional process/session-derived handle. On its first
|
|
102
|
+
turn where `agent_name` is callable, the runtime context asks the model to invent a
|
|
103
|
+
short handle and call `agent_name` before other work. The chosen handle is separate from the active
|
|
104
|
+
persona and role, is persisted in the session identity entry, and remains across later turns and
|
|
105
|
+
persona changes. Once chosen, it is not re-injected into every provider request; the runtime and
|
|
106
|
+
session entry remain authoritative. `agent_name` is unavailable while Exocom is active; its call-time capability check
|
|
107
|
+
also rejects empty, unsafe, generic, or reserved persona/agent names.
|
|
108
|
+
|
|
109
|
+
Naming needs one tool action, not a recurring prose confirmation. A stable system-level runtime rule
|
|
110
|
+
also distinguishes skill-prefetch and routine check-ins from new user requests; it neither hides
|
|
111
|
+
updates nor rewrites conversation history. After updating extension code, use Pi's `/reload` once
|
|
112
|
+
delegated work has settled (or restart/resume); `/persona reload` reloads definitions only.
|
|
113
|
+
|
|
114
|
+
With Exocom active, the corresponding tool is `exocom_name`. The first incoming peer wake can be the
|
|
115
|
+
first model turn in an RPC session; the context hook supplies the naming bootstrap for that custom
|
|
116
|
+
wake as well as for an ordinary user turn. A chosen Exocom handle updates the live registry while
|
|
117
|
+
its session-qualified routing target remains stable across renames. Naming metadata remains callable
|
|
118
|
+
when a pending ask permits `exocom_name`, but it does not settle that work ask.
|
|
119
|
+
|
|
120
|
+
Exocom is a flat, external plane between independent top-level Pi sessions. It provides presence,
|
|
121
|
+
fenced postcards, and a durable claim/ask ledger. `--exocom` joins the current workspace; an exact
|
|
122
|
+
`--exocom=Ab0T` joins an existing workspace scope from another cwd. The four-character code is a
|
|
123
|
+
same-host join reference, not authentication. Foreign members advertise the workspace they can
|
|
124
|
+
actually inspect and cannot claim repository-relative paths in another workspace's ledger.
|
|
125
|
+
|
|
126
|
+
`exocom_status` (a tool, taking no arguments) and `/exocom` (a command, which additionally lists
|
|
127
|
+
live peers) both render the same ownership view: your claims, peers' claims, asks waiting on you,
|
|
128
|
+
and your own open asks. A claim's `write_set` is advisory, not enforced: a supervisor's own
|
|
129
|
+
`write`/`edit` call whose path overlaps a PEER's open claim is blocked once with a reason to
|
|
130
|
+
coordinate (`exocom_ask`) or claim the path itself; calling the same tool again on the same path is
|
|
131
|
+
then allowed through (one warning per claim + normalized path, not a standing lock).
|
|
132
|
+
|
|
133
|
+
## Configuration and data
|
|
134
|
+
|
|
135
|
+
Personas and agents are Markdown files with YAML frontmatter. Teams, flows, contracts, and presets
|
|
136
|
+
are data files. Discovery precedence is builtin < user `~/.pi/agent/persona` < project `.pi/`.
|
|
137
|
+
Personas and agents are loaded from the user and project agent folders; bundled persona and agent
|
|
138
|
+
files are seed sources. A fresh install has no installed personas until `/persona seed`,
|
|
139
|
+
`/persona restore`, or opt-in first-run seeding installs them.
|
|
140
|
+
|
|
141
|
+
| Definition | Location | Purpose |
|
|
142
|
+
|---|---|---|
|
|
143
|
+
| Persona | `personas/*.md` or installed `agents/*.md` with `persona: true` | supervisor prompt, capabilities, delegation, council, orchestration, and coaching |
|
|
144
|
+
| Agent | `agents/*.md` or project `.pi/agents/*.md` | worker prompt, optional tools/model/isolation/MCP |
|
|
145
|
+
| Team | `teams.yaml` | named roster of bare agent names or inline `{ agent, role, model, skills }` members |
|
|
146
|
+
| Flow | `flows/*.flow.json` | strategy phases connected by `needs`, optionally gated |
|
|
147
|
+
| Contract | `contracts/*.contract.json` | structured output fields requested by name and pinned per run |
|
|
148
|
+
| Preset | `presets/*.preset.json` | reusable council strategy, roster, and parameter bundle |
|
|
149
|
+
|
|
150
|
+
`tools` accepts an allowlist such as `[read, grep]`, an `allow`/`deny` object, or `[]` for no tools.
|
|
151
|
+
Omit it to inherit the session tool set. `model`, `isolation: worktree`, `mcp: true`, and `purpose`
|
|
152
|
+
are optional agent metadata. The body is the agent prompt. Inline roster members specialise one
|
|
153
|
+
agent with a role, model, or skills without requiring another agent file.
|
|
154
|
+
|
|
155
|
+
### Multi-agent quick start
|
|
156
|
+
|
|
157
|
+
Follow the [installation instructions](../README.md#install), then start a coding supervisor:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
pi --persona dev
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Delegate a bounded task with the complete brief that Dev requires:
|
|
164
|
+
|
|
165
|
+
```js
|
|
166
|
+
delegate({
|
|
167
|
+
agent: "scout", name: "Login-Trace", task: "Inspect the login flow and report the root cause.",
|
|
168
|
+
brief: {
|
|
169
|
+
objective: "Explain the login failure with code evidence",
|
|
170
|
+
scopeRoe: "Read this repository only; do not contact external systems",
|
|
171
|
+
position: "Start from the current checkout and its existing tests",
|
|
172
|
+
constraints: ["Do not modify files"],
|
|
173
|
+
requiredArtifacts: ["File and line references, with a suggested minimal fix"],
|
|
174
|
+
stopConditions: ["Stop after finding the cause or report the missing evidence"]
|
|
175
|
+
}
|
|
176
|
+
})
|
|
177
|
+
intercom({ action: "peek" })
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
For independent Pi processes, open the same workspace in two terminals with `pi --exocom` and use
|
|
181
|
+
the qualified target returned by `exocom_list`:
|
|
182
|
+
|
|
183
|
+
```js
|
|
184
|
+
exocom_name({ name: "<invented from the current task>" })
|
|
185
|
+
exocom_list({})
|
|
186
|
+
exocom_send({ target: "<qualified target from exocom_list>", message: "Review the API boundary and send back concrete risks." })
|
|
187
|
+
|
|
188
|
+
exocom_claim({ work_key: "api-review", write_set: ["src/api"], slice: "Review and fix the API boundary" })
|
|
189
|
+
exocom_ask({ target: "<qualified target>", work_key: "api-review", question: "Is the transport contract safe to change?" })
|
|
190
|
+
exocom_wait({ work_key: "api-review", ask_id: "<ask_id returned above>" })
|
|
191
|
+
exocom_answer({ work_key: "api-review", ask_id: "<received ask_id>", ok: true, evidence: "Tests and file references" })
|
|
192
|
+
exocom_release({ work_key: "api-review" })
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Recipes
|
|
196
|
+
|
|
197
|
+
Everything in these examples is data. Drop files into the discovery locations above and switch
|
|
198
|
+
personas with `f8`. A brand-new strategy shape is the only case that requires a source file.
|
|
199
|
+
|
|
200
|
+
**Opportunistic delegation** — a simple persona with no orchestration block:
|
|
201
|
+
|
|
202
|
+
```markdown
|
|
203
|
+
<!-- .pi/agents/my-researcher.md -->
|
|
204
|
+
---
|
|
205
|
+
name: my-researcher
|
|
206
|
+
persona: true
|
|
207
|
+
---
|
|
208
|
+
You research thoroughly. For independent sub-questions, fan out `scout` sub-agents in ONE
|
|
209
|
+
`delegate` call (`tasks: [...]`), each with a disjoint scope, then synthesise their findings.
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**A review council and a per-call override** — `council:` is the persona default; the tool can
|
|
213
|
+
override it for one call without editing the file:
|
|
214
|
+
|
|
215
|
+
```yaml
|
|
216
|
+
# teams.yaml — one reviewer agent, three lens roles
|
|
217
|
+
review:
|
|
218
|
+
- { agent: reviewer, role: "Focus ONLY on the SECURITY lens" }
|
|
219
|
+
- { agent: reviewer, role: "Focus ONLY on the PERFORMANCE lens" }
|
|
220
|
+
- { agent: reviewer, role: "Focus ONLY on the TESTS lens" }
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
```markdown
|
|
224
|
+
<!-- .pi/agents/myaudit.md -->
|
|
225
|
+
---
|
|
226
|
+
name: myaudit
|
|
227
|
+
persona: true
|
|
228
|
+
council: { strategy: synthesize, roster: review, params: { synthesizer: reviewer, peers: true } }
|
|
229
|
+
---
|
|
230
|
+
Convene the council before sign-off, then apply its merged findings yourself.
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
```js
|
|
234
|
+
// one-off: run this decision as a debate over the same roster — no file edit
|
|
235
|
+
council({ question: "cache this or recompute?", strategy: "debate", roster: "review", params: { bestOf: 2 } })
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**A delegation policy on any persona** — fields are generic and are never keyed to a persona name.
|
|
239
|
+
The runtime rejects incomplete briefs before a model call, supplies a missing contract, rejects
|
|
240
|
+
overlapping or missing ownership for parallel writers, and refuses a declared verifier that would
|
|
241
|
+
start before or beside a material writer in the same call or while a mutating background run is in
|
|
242
|
+
flight. Only `read`, `grep`, `find`, and `ls` count as read-only; shell-capable, MCP-enabled, and
|
|
243
|
+
unknown toolsets fail closed as writers. `writeSet` is a scheduling contract, not an OS sandbox.
|
|
244
|
+
|
|
245
|
+
```markdown
|
|
246
|
+
---
|
|
247
|
+
name: my-project-lead
|
|
248
|
+
persona: true
|
|
249
|
+
delegation:
|
|
250
|
+
requireBrief: true
|
|
251
|
+
outputContract: finding
|
|
252
|
+
requireDisjointWrites: true
|
|
253
|
+
requireFreshVerification: true
|
|
254
|
+
verificationAgents: [my-checker]
|
|
255
|
+
council: { strategy: critic-loop, roster: my-repair-team, params: { rounds: 3 } }
|
|
256
|
+
---
|
|
257
|
+
Delegate bounded work, then accept completion only after fresh evidence.
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
The six required `brief` fields are `objective`, `scopeRoe`, `position`, `constraints`,
|
|
261
|
+
`requiredArtifacts`, and `stopConditions`. `verificationAgents` names ordinary installed agents;
|
|
262
|
+
there is no built-in verifier identity.
|
|
263
|
+
|
|
264
|
+
When `requireBrief` is enabled, it also applies to read-only scouts. Single-worker calls put the
|
|
265
|
+
brief alongside `agent` and `task`; parallel calls put a complete brief inside **each** `tasks[]`
|
|
266
|
+
entry. A top-level brief is not inherited by the batch, and prose in `task` does not replace these
|
|
267
|
+
fields. A missing-brief error means the batch was rejected before any worker started: correct all
|
|
268
|
+
affected entries before retrying.
|
|
269
|
+
|
|
270
|
+
**A mandatory-orchestration persona** — `orchestration:` runs automatically every turn, while
|
|
271
|
+
`council:` runs only when requested. Only `ok: true` is presented as a ruling; failures, cancellation,
|
|
272
|
+
and unresolved output remain labelled evidence to repair and verify.
|
|
273
|
+
|
|
274
|
+
```markdown
|
|
275
|
+
<!-- .pi/agents/myguard.md -->
|
|
276
|
+
---
|
|
277
|
+
name: myguard
|
|
278
|
+
persona: true
|
|
279
|
+
orchestration: { mode: strategy, strategy: magi, roster: magi, params: { reflect: false } }
|
|
280
|
+
---
|
|
281
|
+
Every turn is decided by the MAGI triarchy first (no reflection round); present and act on it.
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Coaching** — add `coaching: true` to give children `contact_supervisor`, then read and answer
|
|
285
|
+
progress or decisions with `intercom inbox` and `intercom reply`.
|
|
286
|
+
|
|
287
|
+
**A custom agent** — the body is the worker prompt and the frontmatter sets its capabilities:
|
|
288
|
+
|
|
289
|
+
```markdown
|
|
290
|
+
<!-- .pi/agents/hardener.md -->
|
|
291
|
+
---
|
|
292
|
+
name: hardener
|
|
293
|
+
description: Locks down a change's security posture — authz, input validation, secrets handling.
|
|
294
|
+
tools: [read, grep, edit, bash]
|
|
295
|
+
model: opus
|
|
296
|
+
isolation: worktree
|
|
297
|
+
---
|
|
298
|
+
You are the Hardener. Given a diff or area, find and FIX authz/access-control gaps, injection and
|
|
299
|
+
unsafe-sink risks, secrets/token mishandling, and missing input validation. Cite `file:line`.
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
**A flow with a human checkpoint** — phases are journaled and dependents wait for a `gate: true`
|
|
303
|
+
approval. Save as `.pi/flows/gated-build.flow.json`:
|
|
304
|
+
|
|
305
|
+
```json
|
|
306
|
+
{
|
|
307
|
+
"name": "gated-build",
|
|
308
|
+
"phases": [
|
|
309
|
+
{ "id": "plan", "strategy": "magi", "roster": "magi", "gate": true },
|
|
310
|
+
{ "id": "build", "strategy": "critic-loop", "roster": "repair", "needs": ["plan"] },
|
|
311
|
+
{ "id": "verify", "strategy": "fanout", "roster": "review", "needs": ["build"] }
|
|
312
|
+
]
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**A structured-return contract** — save as `.pi/contracts/ship-verdict.contract.json` so votes and
|
|
317
|
+
judges can tally fields mechanically:
|
|
318
|
+
|
|
319
|
+
```json
|
|
320
|
+
{ "name": "ship-verdict",
|
|
321
|
+
"fields": {
|
|
322
|
+
"vote": { "type": "string", "required": true },
|
|
323
|
+
"severity": { "type": "enum", "values": ["low", "medium", "high", "critical"] },
|
|
324
|
+
"confidence": { "type": "number", "min": 0, "max": 1 }
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**A preset keeps persona files to one line** — save as `.pi/presets/magi-rounds.preset.json`:
|
|
330
|
+
|
|
331
|
+
```json
|
|
332
|
+
{ "strategy": "council-rounds", "roster": "magi", "params": { "rounds": 3, "bestOf": 3 } }
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
```yaml
|
|
336
|
+
# any persona's frontmatter
|
|
337
|
+
council: { preset: magi-rounds }
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
For one-line strategy calls and the canonical parameter defaults, use the table in
|
|
341
|
+
[`STRATEGIES.md`](./STRATEGIES.md). A new vote rule or custom loop adds
|
|
342
|
+
`src/orchestration/strategies/<name>.ts`, registers it in `strategy.ts`, and gets a stub-engine unit
|
|
343
|
+
test; the data-driven definitions above require no core change.
|
|
344
|
+
|
|
345
|
+
## Commands, flags, and environment
|
|
346
|
+
|
|
347
|
+
**Keys** — `f8` cycles persona; `f9` or `/agents` opens the agent overlay: ↑↓ navigate, ⏎ open, `x`
|
|
348
|
+
stop, `s` steer, and Esc close.
|
|
349
|
+
|
|
350
|
+
**Commands** — `/persona [name|off|list|reload|seed|restore]` · `/models [query]` ·
|
|
351
|
+
`/orchestrate <task>` · `/flow <name> <task>` · `/peek [id]` · `/exocom` · `/doctor`.
|
|
352
|
+
|
|
353
|
+
`/doctor` reports the cross-process broker's lifecycle on one line: `broker: on — endpoint …` once
|
|
354
|
+
the host is listening, `broker: on — (starting…)` mid-attempt, or
|
|
355
|
+
`broker: on — (not started — no child-engine build yet)` before any child-engine build has run. A
|
|
356
|
+
bind failure reports on its own, without the `on —` prefix or a connected-children count (there is
|
|
357
|
+
neither while down): `broker: failed — <reason>` — children built while it is down spawn without a
|
|
358
|
+
bus endpoint, so they never burn connect backoff against a dead socket, and the next child-engine
|
|
359
|
+
build retries. A connected broker child's status shows `⇄ <handle>`; if that connection drops, the
|
|
360
|
+
status flips to `⇄ offline` and a fresh ask on it fails fast instead of hanging.
|
|
361
|
+
|
|
362
|
+
`/doctor` also reports the installed host's version against this extension's floor: `pi: <version>
|
|
363
|
+
(requires ≥ 0.83.0)`, with a trailing `— BELOW FLOOR` marker once an installed version fails the
|
|
364
|
+
check (`src/core/pi-compat.ts`). `pi: unknown` means the host's own `package.json` could not be
|
|
365
|
+
resolved (a non-standard install layout) — not a failed check.
|
|
366
|
+
|
|
367
|
+
**CLI flags** — `--persona <name>` starts with that installed persona and errors if it is missing;
|
|
368
|
+
`--exocom` joins this workspace's Exocom plane; `--exocom=Ab0T` joins another workspace's scope
|
|
369
|
+
from a different cwd. Pi owns `--model <provider/id>`, `--thinking
|
|
370
|
+
<off|minimal|low|medium|high|xhigh|max>`, and `--list-models`.
|
|
371
|
+
|
|
372
|
+
| Variable | Default | Effect |
|
|
373
|
+
|---|---|---|
|
|
374
|
+
| `PI_PERSONA_ENGINE` | in-process | `child` spawns each sub-agent as an isolated `pi` process |
|
|
375
|
+
| `PI_PERSONA_CHILD_THINKING` | inherited | reasoning effort for child-engine sub-agents |
|
|
376
|
+
| `PI_PERSONA_SEED` | off | `on` auto-installs bundled personas on first run |
|
|
377
|
+
| `PI_PERSONA_BROKER` | on | `off` disables the cross-process comm plane for child, worktree, and MCP legs |
|
|
378
|
+
| `PI_PERSONA_PEEK_MS` | 30000 | fast async stall/message wakeup tick; `0` disables it |
|
|
379
|
+
| `PI_PERSONA_CHECKIN_MS` | 300000 | routine direction check-in while async children run; `0` disables it |
|
|
380
|
+
| `PI_PERSONA_AGENT_MAX_MS` | off | opt-in per-agent hard wall-clock cap; unset leaves healthy work running |
|
|
381
|
+
| `PI_PERSONA_AGENT_STARTUP_MS` | 300000 | startup deadline for a child that makes no progress; `0` disables it. Like the idle window, a leg waiting on a supervisor reply is not idle: the watchdog re-arms while its ask is pending, instead of killing on a blind ceiling |
|
|
382
|
+
| `PI_PERSONA_NUDGE` | on | `off` silences delegation and persistence nudges; synchronous checkpoints stay in model-visible tool results and are mirrored to durable, expandable TUI-only cards |
|
|
383
|
+
| `PI_PERSONA_EXOCOM` | off | `1` joins the current workspace Exocom scope; cross-workspace selection is CLI-only |
|
|
384
|
+
| `PI_PERSONA_SPINE` | off | `on` or a path enables the shared behavioral layer; see [`SPINE.md`](./SPINE.md) |
|
|
385
|
+
| `PI_PERSONA_SPINE_LEGS` | follows `PI_PERSONA_SPINE` | selector for delegated legs, allowing all four spine measurement arms |
|
|
386
|
+
| `PI_PERSONA_DISABLE` | unset | any non-empty value disables the whole extension for this process (also set internally as the fork-bomb guard on delegated legs) |
|
|
387
|
+
| `PI_PERSONA_DIRS` | none | extra discovery directories (`;`/`,`-separated), searched alongside the user and project agent folders |
|
|
388
|
+
| `PI_PERSONA_DEFAULT` | none | persona activated automatically when no persona is otherwise selected |
|
|
389
|
+
| `PI_PERSONA_KEY` | `f8` | keybinding that cycles installed personas |
|
|
390
|
+
| `PI_PERSONA_PERSIST` | on | `off` stops remembering the last-selected persona across sessions |
|
|
391
|
+
| `PI_PERSONA_DELEGATE_DEFAULT` | allow | `deny` (or an off-word) makes an unlisted delegate target default-deny instead of default-allow |
|
|
392
|
+
| `PI_PERSONA_STATE_FILE` | a global default path | overrides where the last-selected-persona state is stored |
|
|
393
|
+
| `PI_PERSONA_ASYNC_RETAIN` | 25 | how many settled-but-uncollected async runs are retained before FIFO-evicting the oldest |
|
|
394
|
+
| `PI_PERSONA_LEDGER_V2` | off | `on` widens the delegation-ledger retry-veto key to also include role/tools/isolation, not just agent+model+task |
|
|
395
|
+
| `PI_PERSONA_LEG_CHANGE_REPORT` | on | `off` disables the non-worktree files-changed report (two `git status` spawns per leg) |
|
|
396
|
+
|
|
397
|
+
## Development
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
npm install
|
|
401
|
+
npm run typecheck # strict tsc --noEmit
|
|
402
|
+
npm test # node --test
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
The architecture contract is [`ARCHITECTURE.md`](./ARCHITECTURE.md), orchestration behavior is
|
|
406
|
+
[`STRATEGIES.md`](./STRATEGIES.md), the shared prompt layer is [`SPINE.md`](./SPINE.md), and the
|
|
407
|
+
observer/export contract is [`TELEMETRY.md`](./TELEMETRY.md). After updating Pi packages, run
|
|
408
|
+
`npm run typecheck`: it catches changes at the in-process session and `ThinkingLevel` seams.
|