@aeondave/pi-persona 1.16.3 → 1.17.1
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 +22 -3
- package/CHANGELOG.md +56 -0
- package/README.md +18 -2
- package/docs/ARCHITECTURE.md +58 -7
- package/docs/REFERENCE.md +125 -3
- package/docs/TELEMETRY.md +8 -0
- package/package.json +2 -2
- package/src/core/config.ts +1 -1
- package/src/core/settings.ts +251 -0
- package/src/engine/adapter.ts +1 -1
- package/src/engine/async.ts +53 -13
- package/src/engine/child.ts +1 -1
- package/src/engine/errors.ts +1 -0
- package/src/engine/inproc.ts +3 -3
- package/src/engine/stream.ts +20 -1
- package/src/extension/companion-settings.ts +29 -0
- package/src/extension/hooks.ts +47 -12
- package/src/extension/persona-model-settings.ts +318 -0
- package/src/extension/persona-settings.ts +459 -0
- package/src/extension.ts +257 -50
- package/src/orchestration/sdk.ts +2 -0
- package/src/persona/config-store.ts +6 -195
- package/src/persona/controller.ts +16 -3
- package/src/persona/model-participants.ts +1 -1
- package/src/persona/settings-store.ts +636 -0
- package/src/telemetry/contract.ts +7 -5
- package/src/tools/delegate-tool.ts +6 -6
- package/src/tools/delegate.ts +3 -1
- package/src/tools/exocom.ts +14 -1
- package/src/ui/persona-settings.ts +322 -0
- package/src/persona/state.ts +0 -28
package/AGENTS.md
CHANGED
|
@@ -10,6 +10,9 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
|
|
|
10
10
|
|
|
11
11
|
- Typecheck (must stay clean): `npm run typecheck` (`tsc --noEmit`, strict)
|
|
12
12
|
- All tests: `npm test` · unit only: `npm run test:unit`
|
|
13
|
+
- Settings SDK smoke (isolated profile, no provider/network requests):
|
|
14
|
+
`node --import tsx scripts/settings-smoke.mjs [absolute-pi-package-entry]`.
|
|
15
|
+
Omitting the argument uses the development SDK; pass an installed host entry to qualify that version.
|
|
13
16
|
- One file: `node --import tsx --import ./test/setup/hermetic-env.ts --test test/unit/core/frontmatter.test.ts`
|
|
14
17
|
- The second `--import` is the hermeticity choke point: it strips the whole `PI_PERSONA_*`
|
|
15
18
|
namespace and pins `PI_AGENT_DIR` at a throwaway dir before any test module loads, so a
|
|
@@ -115,8 +118,9 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
|
|
|
115
118
|
never double-reported; snapshots leave running children active. In interactive sessions `delegate`
|
|
116
119
|
is background-by-default (`sync: true` opts a call out; headless `pi -p` defaults to sync so the
|
|
117
120
|
single turn carries the result). An explicit `async` flag takes precedence over `sync` and the default.
|
|
118
|
-
Periodic async status
|
|
119
|
-
|
|
121
|
+
Periodic async status and each newly detected stall episode are durable, expandable operator-only
|
|
122
|
+
entries. Interactive stalls never wake the model; headless sessions get at most one stall wake per run
|
|
123
|
+
lifetime. Completions, asks, and unread bus messages keep their existing actionable paths.
|
|
120
124
|
Message ids and run ids are separate: `intercom message { messageId }` retrieves retained bus
|
|
121
125
|
text, `intercom result { to: runId }` retrieves a settled run. Both explicit and automatic inbox
|
|
122
126
|
drains retain bounded history (256 messages / 256,000 body characters). Ask settlement clears
|
|
@@ -233,7 +237,7 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
|
|
|
233
237
|
- `src/engine/` — `child.ts`, `inproc.ts` (default), `adapter.ts`, `async.ts` (async tracker/peek), `worktree.ts` (git-worktree isolation), `stream.ts` (event→state).
|
|
234
238
|
- `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`).
|
|
235
239
|
- `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.
|
|
236
|
-
- `src/persona/` — `persona.ts` (parse + `expandCouncilPreset`), `controller.ts`, `gating.ts`, `orchestrate.ts`, `config-store.ts
|
|
240
|
+
- `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).
|
|
237
241
|
- `src/tools/` — `delegate.ts`, `intercom.ts`, `exocom.ts`. `src/ui/` — agent-tree/overlay, model-picker, `presentation.ts` (the collapsed-card compaction/sanitization helpers), `usage.ts`. `src/extension.ts` — the single ExtensionFactory (wires tools/commands/hooks/engines).
|
|
238
242
|
- Bundled data-driven assets (discovery precedence builtin < user `~/.pi/agent/persona` < project `.pi/`):
|
|
239
243
|
`personas/*.md`, `agents/*.md` (personas+agents share a folder, split by `persona: true` — a
|
|
@@ -249,6 +253,21 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
|
|
|
249
253
|
|
|
250
254
|
## Adding a new X (data-driven — usually no core change)
|
|
251
255
|
|
|
256
|
+
Settings use `/persona-settings`, a full-page registry-driven UI independent of Pi's `/settings`.
|
|
257
|
+
The only active preferences file is `<agentDir>/persona/settings.json` (version, sparse preferences,
|
|
258
|
+
per-persona model assignments, last selection). `src/core/settings.ts` owns row metadata and validation;
|
|
259
|
+
add/remove public preferences there rather than special-casing UI fields. Route every write through
|
|
260
|
+
`patchPersonaSettings`; exact null patches remove overrides without erasing concurrent edits.
|
|
261
|
+
The retired `config.json` and `state.json` are migration inputs only, archived as `.migrated` after
|
|
262
|
+
the canonical file commits. Malformed files remain untouched; never add a truncating fallback writer.
|
|
263
|
+
Scalar preferences apply after a Pi restart or native `/reload`, not `/new` (never auto-reload live workers).
|
|
264
|
+
Model edits apply to future runs through the existing participant resolver. `/persona reload` only
|
|
265
|
+
refreshes resources, not startup preferences. Native Pi settings and compaction are not owned here.
|
|
266
|
+
Mind/Flow contribute supported current values through `pi-persona:settings:collect:v1` (`{ add(id, values) }`);
|
|
267
|
+
their five preferences share the same registry/file. Do not hard-import a companion or start services
|
|
268
|
+
while collecting settings. Flow port/idle changes are for the next shared-service start, never a restart
|
|
269
|
+
of a service other Pi sessions are using. Skill Optimizer remains independent.
|
|
270
|
+
|
|
252
271
|
1. **Strategy**: add `src/orchestration/strategies/<name>.ts` (export a `Strategy`), register it in `strategy.ts` `BUILTINS`, add a unit test.
|
|
253
272
|
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.
|
|
254
273
|
3. **Agent**: `agents/<name>.md` — optional `tools`, `model`, `isolation: worktree`, `mcp: true`
|
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,62 @@ used in its [GitHub releases](https://github.com/AeonDave/pi-persona/releases).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.17.1](https://github.com/AeonDave/pi-persona/releases/tag/v1.17.1) - 2026-10-20
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Add `/persona-settings`, a dedicated TUI/RPC editor for pi-persona preferences, persona model
|
|
14
|
+
assignments, and diagnostics, plus `/persona-settings show` for a read-only headless report. The
|
|
15
|
+
full-page TUI supports filtering, resetting a saved override, and opening model settings.
|
|
16
|
+
- Persist preferences, per-persona model assignments, and the remembered persona in one versioned
|
|
17
|
+
`<agentDir>/persona/settings.json`. On first migration, the retired model and state files are
|
|
18
|
+
imported and unchanged originals are archived as `.migrated` when safe; failed or unsafe
|
|
19
|
+
migration keeps the source files and reports a warning.
|
|
20
|
+
- Let users select a model-settings owner and profile explicitly without activating it. Model
|
|
21
|
+
assignments affect future runs; inline pins remain read-only, and resetting removes only the
|
|
22
|
+
saved override. Public environment overrides retain startup precedence; scalar preference changes
|
|
23
|
+
wait for a Pi restart or native `/reload` (not `/new`) and are never auto-reloaded.
|
|
24
|
+
- Keep persona-selection revisions separate from unrelated settings saves so companion memory scopes
|
|
25
|
+
can follow explicit re-selections without mistaking model edits for persona switches.
|
|
26
|
+
- Include the loaded Mind/Flow companions in the same panel and preferences file, using optional
|
|
27
|
+
public-bus discovery rather than hard plugin dependencies. Keep Skill Optimizer separate and
|
|
28
|
+
preserve per-run `--no-flow` and the existing shared service's lifetime.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- Count streamed textual tool output as child liveness without adding tool output to the assistant
|
|
33
|
+
transcript. Queued delegates start their stall window only after concurrency admission.
|
|
34
|
+
- Keep interactive stall episodes operator-only and expandable. Headless runs receive at most one
|
|
35
|
+
successfully delivered stall wake per run lifetime; real progress still re-arms operator episodes.
|
|
36
|
+
- Reject malformed UTF-8 settings and migration inputs rather than silently replacing bytes during
|
|
37
|
+
a save. Preserve invalid originals and keep concurrent preference/model edits in one safe store.
|
|
38
|
+
|
|
39
|
+
## [1.17.0](https://github.com/AeonDave/pi-persona/releases/tag/v1.17.0) - 2026-10-19
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
|
|
43
|
+
- `/persona models [council-persona]` refreshes the host catalog and reopens model selection for
|
|
44
|
+
the active caller's council participants, preserving cancelled choices, unrelated assignments,
|
|
45
|
+
and explicit inline model pins. No supervisor switch or model request is required.
|
|
46
|
+
- A hermetic installed-host Pi 1.3.0 qualification script covers real command dispatch, assignment
|
|
47
|
+
persistence, custom-message starts and missing-auth council recovery without network requests.
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
|
|
51
|
+
- Publish terminal progress for single delegates before removing their tree node, preserving `done`
|
|
52
|
+
status in Flow and other telemetry consumers.
|
|
53
|
+
- Preserve Exocom reply references and optional target-correlated transport IDs while keeping each
|
|
54
|
+
queued/terminal telemetry row stable; retain bounded broadcast delivery receipts.
|
|
55
|
+
- Report an exact acknowledged broadcast receipt as delivered even when failures for other peers
|
|
56
|
+
exceed the retained sample; recipients without exact evidence remain conservatively unknown.
|
|
57
|
+
- Classify Pi's `No API key found for <provider>` diagnostic as a provider failure in both engines,
|
|
58
|
+
allowing the existing single main-model recovery for councils/strategies/flows. Ordinary delegate
|
|
59
|
+
provider pins remain strict; aborts, timeouts, contract and agent failures remain terminal.
|
|
60
|
+
- Report a refused persona model switch instead of silently recording an override when Pi rejects
|
|
61
|
+
it for missing authentication; keep the actual session model and restoration state intact.
|
|
62
|
+
- Remove a timing race from the supervisor-ask telemetry test: verify the persisted timeout
|
|
63
|
+
transition history rather than polling a transient 20 ms state through asynchronous disk writes.
|
|
64
|
+
|
|
9
65
|
## [1.16.3](https://github.com/AeonDave/pi-persona/releases/tag/v1.16.3) - 2026-10-13
|
|
10
66
|
|
|
11
67
|
### Fixed
|
package/README.md
CHANGED
|
@@ -39,9 +39,9 @@ your customizations.
|
|
|
39
39
|
| Install option | Command |
|
|
40
40
|
|---|---|
|
|
41
41
|
| This project only | `pi install -l npm:@aeondave/pi-persona` |
|
|
42
|
-
| Pin this release | `pi install npm:@aeondave/pi-persona@1.
|
|
42
|
+
| Pin this release | `pi install npm:@aeondave/pi-persona@1.17.1` |
|
|
43
43
|
| Update an unpinned install | `pi update npm:@aeondave/pi-persona` |
|
|
44
|
-
| Git alternative | `pi install git:github.com/AeonDave/pi-persona@v1.
|
|
44
|
+
| Git alternative | `pi install git:github.com/AeonDave/pi-persona@v1.17.1` |
|
|
45
45
|
|
|
46
46
|
Restart Pi after updating. For a pinned install, install the new version or tag explicitly.
|
|
47
47
|
If switching from a Git install, remove that source first with
|
|
@@ -91,9 +91,15 @@ the worker has acted on it.
|
|
|
91
91
|
| `/peek` | Show a compact progress summary |
|
|
92
92
|
| `/persona list` | List installed personas |
|
|
93
93
|
| `/persona off` | Turn off the active persona |
|
|
94
|
+
| `/persona models [council-persona]` | Refresh the catalog and reselect council models for the active persona |
|
|
95
|
+
| `/persona-settings` | Open pi-persona's settings in the TUI or RPC UI |
|
|
96
|
+
| `/persona-settings show` | Show a read-only settings report, including in headless sessions |
|
|
94
97
|
| `/models <query>` | Find an available model |
|
|
95
98
|
| `/doctor` | Check configuration and available capabilities |
|
|
96
99
|
|
|
100
|
+
The settings panel also includes Mind and Flow when those updated companions are loaded; all three
|
|
101
|
+
use one `persona/settings.json`. Skill Optimizer keeps its separate configuration.
|
|
102
|
+
|
|
97
103
|
For time-based work, ask “remind me in ten minutes.” For an event, ask “let me know when this build
|
|
98
104
|
finishes.” Keep Pi open while timers and monitors are running; they are not restored after a restart.
|
|
99
105
|
See [timers and monitors](docs/MONITORS.md) for examples.
|
|
@@ -151,6 +157,8 @@ Strategies are not restricted to the similarly named persona: `council` can sele
|
|
|
151
157
|
custom role-based groups without team files. Model selection includes external arbiters. In councils
|
|
152
158
|
and flows, a provider failure or unavailable model can recover once on the supervisor's model, with
|
|
153
159
|
the switch visible and both attempts accounted; ordinary delegates keep explicit provider pins strict.
|
|
160
|
+
To replace old council assignments without changing supervisors, run `/persona models magi`
|
|
161
|
+
(or `/persona models` for the active council). Cancel a choice to keep its previous value.
|
|
154
162
|
See [the reference](docs/REFERENCE.md) for an inline council example and recovery limits.
|
|
155
163
|
|
|
156
164
|
## Make it yours
|
|
@@ -163,6 +171,12 @@ only when you intend to discard customizations to those files.
|
|
|
163
171
|
|
|
164
172
|
For optional long-term memory, add [pi-persona-mind](https://github.com/AeonDave/pi-persona-mind).
|
|
165
173
|
|
|
174
|
+
`/persona-settings` is separate from Pi's `/settings`: it edits pi-persona preferences and saved
|
|
175
|
+
persona model assignments, not native Pi or compaction settings. In the TUI, `/` filters settings,
|
|
176
|
+
`r` resets the selected saved override, and `m` opens model assignment editing. Scalar preference
|
|
177
|
+
changes apply after restarting Pi or Pi's native `/reload`, not `/new`; `/persona reload` only
|
|
178
|
+
refreshes persona definitions. Model changes apply to future runs. See [configuration and settings](docs/REFERENCE.md#configuration-and-data).
|
|
179
|
+
|
|
166
180
|
## Documentation
|
|
167
181
|
|
|
168
182
|
| Guide | What's inside |
|
|
@@ -187,6 +201,8 @@ npm test
|
|
|
187
201
|
```
|
|
188
202
|
|
|
189
203
|
Pi loads the TypeScript extension directly; there is no build step.
|
|
204
|
+
To qualify a separately installed Pi 1.3.0 host without cloud calls or your profile, run
|
|
205
|
+
`node --import tsx scripts/qualify-host.mjs <absolute-path-to-pi-coding-agent-package>`.
|
|
190
206
|
The [CI workflow](https://github.com/AeonDave/pi-persona/actions/workflows/test.yml) runs strict
|
|
191
207
|
typechecking, dependency auditing and the test suite on Linux and Windows. The OpenSSF badge links to the project's
|
|
192
208
|
scored supply-chain checks; it is not a certification that the code is free of vulnerabilities.
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -200,7 +200,8 @@ engine, telemetry, UI, and tool surfaces; it is not part of the transport/domain
|
|
|
200
200
|
lifecycle metadata only, never an agent-message router or control surface. See
|
|
201
201
|
[`TELEMETRY.md`](./TELEMETRY.md) for privacy, retention, writer leases, and shutdown behavior.
|
|
202
202
|
- **`src/persona/`** — identity: `persona.ts` (parse + `expandCouncilPreset` + `composeSystemPrompt`),
|
|
203
|
-
`controller.ts`, `gating.ts`, `orchestrate.ts`, `config-store.ts
|
|
203
|
+
`controller.ts`, `gating.ts`, `orchestrate.ts`, `config-store.ts` (pure model helpers),
|
|
204
|
+
`settings-store.ts` (canonical preferences, per-persona models and last-selected persona),
|
|
204
205
|
`spine.ts` (the shared behavioral layer's SOURCE resolution — docs/SPINE.md; composition sits in
|
|
205
206
|
`persona.ts` for supervisor turns and in the engines for delegated legs).
|
|
206
207
|
- **`src/tools/`** — `delegate.ts`, `intercom.ts`, `exocom.ts` (the `exocom_list`/`exocom_send`
|
|
@@ -300,6 +301,54 @@ inline model pins taking precedence. If distinct full roles share a short displa
|
|
|
300
301
|
keeps the hint (with `#N` suffixes for repeated node keys) but omits the uncertain model label rather
|
|
301
302
|
than borrowing another role's choice. Routing still resolves the full role key, not the display hint.
|
|
302
303
|
|
|
304
|
+
**Model assignment repair is configuration, not execution recovery.** `/persona models [profile]`
|
|
305
|
+
is an explicit user edit in the Pi adapter: it reuses `resolveCouncilInvocation`,
|
|
306
|
+
`collectModelParticipants` and the canonical locked settings writer, without adding another roster,
|
|
307
|
+
model store or provider-routing policy. The active caller owns saved assignments even when borrowing
|
|
308
|
+
another council profile. Automatic discovery stays never-nag; explicit editing may replace saved or
|
|
309
|
+
agent defaults, but not inline pins. Host catalog refresh has a 20-second cooperative deadline;
|
|
310
|
+
reported cancellation/errors or a caller/session change leave assignments untouched. Selection uses
|
|
311
|
+
the refreshed host availability snapshot rather than treating all catalog entries as authenticated.
|
|
312
|
+
Cancelled rows preserve their old choices; accepted choices merge without clearing other personas.
|
|
313
|
+
Running engines retain their captured assignments. Missing credentials are classified at the engine
|
|
314
|
+
adapter boundary; only the SDK decides whether a main-model recovery is admissible. This separation
|
|
315
|
+
avoids a global reset or automatic repinning that could silently change billing and panel diversity.
|
|
316
|
+
|
|
317
|
+
**Unified settings.** `/persona-settings` is independent of Pi's `/settings`: full-page TUI, native
|
|
318
|
+
RPC dialogs, and a read-only `show` report. `core/settings.ts` is the public preference registry and
|
|
319
|
+
validator; the UI and environment precedence consume it rather than maintaining duplicate field lists.
|
|
320
|
+
All persistent Persona preferences live in `<agentDir>/persona/settings.json`, version 1: sparse
|
|
321
|
+
`preferences`, `personas` model maps and `lastPersona`. `settings-store.ts` owns bounded validated reads,
|
|
322
|
+
cross-process locked field patches and atomic replacement. Null removes an exact override; unknown
|
|
323
|
+
top-level and per-persona fields survive unrelated edits. Malformed/unsupported files are never
|
|
324
|
+
overwritten: activation warns and falls back, while editing fails closed. Fresh read-only inspection
|
|
325
|
+
does not materialize defaults.
|
|
326
|
+
|
|
327
|
+
`selectionRevision` is a non-negative counter updated only by explicit `lastPersona` patches,
|
|
328
|
+
including re-selection of the same name. Model/preference saves never advance it. Companion scope
|
|
329
|
+
readers must use this semantic marker, not the settings file's mtime, as evidence of a selection gesture.
|
|
330
|
+
|
|
331
|
+
Legacy `config.json` and `state.json` are imported only if the canonical file is absent, then archived
|
|
332
|
+
as exact independent `.migrated` copies after commit. Archive conflicts preserve the original and warn;
|
|
333
|
+
an existing canonical file is never reimported. `PI_PERSONA_STATE_FILE` only selects a legacy import
|
|
334
|
+
source. No active legacy writer remains. Explicit public environment values retain startup precedence;
|
|
335
|
+
internal child/bus guards are not preferences. Definitions, credentials and native Pi settings remain
|
|
336
|
+
with their existing owners.
|
|
337
|
+
|
|
338
|
+
Scalar preferences are activation-scoped: saving marks differences pending until a Pi restart or
|
|
339
|
+
Pi's native `/reload`, not `/new`; the panel never reloads automatically. `/persona reload` only refreshes resources.
|
|
340
|
+
The Models section selects the assignment owner independently of the viewed council/orchestration
|
|
341
|
+
profile, supports exact-key resets and keeps inline pins immutable. It patches the same file and updates
|
|
342
|
+
the resolver cache for future runs, never changing an already-running worker. Native compaction is untouched.
|
|
343
|
+
|
|
344
|
+
Mind/Flow settings use optional synchronous discovery on Pi's public event bus
|
|
345
|
+
(`pi-persona:settings:collect:v1`). The owning companion reports its current startup values; the same
|
|
346
|
+
central registry validates owner/type and renders only supported fields. Persona alone writes their
|
|
347
|
+
preferences in the canonical file; companions independently read their known fields, retaining
|
|
348
|
+
standalone operation with no hard runtime dependency on Persona. No collection call performs I/O,
|
|
349
|
+
starts services or wakes a model. Flow's desired port and idle grace apply to the next shared-service
|
|
350
|
+
startup, never to a daemon other sessions are already using. Skill Optimizer is outside this contract.
|
|
351
|
+
|
|
303
352
|
### MCP (and other `session_start`-scoped extensions) in sub-agents
|
|
304
353
|
|
|
305
354
|
**A sub-agent does NOT share the supervisor's MCP session, and an in-process sub-agent gets NO MCP at
|
|
@@ -644,12 +693,14 @@ a local process able to modify that directory is already inside the trust bounda
|
|
|
644
693
|
if delayed input hooks outlast the active run; no supported post-admission ordering guarantee
|
|
645
694
|
has been established. The supervisor otherwise returns control and
|
|
646
695
|
goes idle until a wake; the **peek watchdog** fires while async children run but stays SILENT unless
|
|
647
|
-
there is something to act on — a healthy background run should not interrupt.
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
696
|
+
there is something to act on — a healthy background run should not interrupt. Every newly detected stall
|
|
697
|
+
episode (`STALL_FLAG_MS`, 90s) appends a durable, expandable operator-only warning entry, including while
|
|
698
|
+
the supervisor is busy. Interactive stalls never wake the model. In headless sessions, the first stall
|
|
699
|
+
episode may produce one focused patience-first model wake per run lifetime (ask the leg, don't probe its
|
|
700
|
+
environment); later stall episodes for that run do not re-arm the model-wake budget. Unread messages to the
|
|
701
|
+
supervisor retain their existing wake path. The **slow routine status card** (`PI_PERSONA_CHECKIN_MS`,
|
|
702
|
+
~5 min, `0` disables) is a durable, expandable operator-only session entry with the compact ProgressView
|
|
703
|
+
digest — never full transcripts — and does not start a model turn. Live supervisor asks
|
|
653
704
|
are derived from the exact engine handle's optional `isWaitingForSupervisor` predicate: tree/F9/peek
|
|
654
705
|
show waiting, and the watchdog suppresses false stalls until the ask settles. Parent clocks advance
|
|
655
706
|
with child engine events (liveness, not proof of useful work); parents are waiting only when every
|
package/docs/REFERENCE.md
CHANGED
|
@@ -188,6 +188,106 @@ files are seed sources. A fresh install has no installed personas until `/person
|
|
|
188
188
|
| Contract | `contracts/*.contract.json` | structured output fields requested by name and pinned per run |
|
|
189
189
|
| Preset | `presets/*.preset.json` | reusable council strategy, roster, and parameter bundle |
|
|
190
190
|
|
|
191
|
+
### Unified pi-persona settings
|
|
192
|
+
|
|
193
|
+
`/persona-settings` opens pi-persona's own settings editor in the TUI or RPC UI. It is a separate
|
|
194
|
+
extension command; it does not replace Pi's native `/settings` or edit native Pi preferences such
|
|
195
|
+
as compaction. The TUI is a full-page, filterable panel (`/` to search, `r` to reset the selected
|
|
196
|
+
saved override, `m` for model assignments, `d` for diagnostics); the RPC UI offers the same
|
|
197
|
+
settings, model, and diagnostics flows. `/persona-settings show` emits a read-only report and is
|
|
198
|
+
available in headless sessions.
|
|
199
|
+
|
|
200
|
+
The sole active settings file is `<agentDir>/persona/settings.json` (normally
|
|
201
|
+
`~/.pi/agent/persona/settings.json`). Its version-1 top-level shape is:
|
|
202
|
+
|
|
203
|
+
```json
|
|
204
|
+
{
|
|
205
|
+
"version": 1,
|
|
206
|
+
"preferences": { "engine": "inproc", "nudge": true },
|
|
207
|
+
"personas": { "dev": { "models": { "reviewer": "provider/model-id" } } },
|
|
208
|
+
"lastPersona": "dev"
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
`preferences` contains the public extension settings; `personas.<name>.models` preserves
|
|
213
|
+
provider-qualified model assignments, and `lastPersona` remembers the selection when
|
|
214
|
+
`PI_PERSONA_PERSIST` is enabled. The preference registry groups all editable scalar settings as:
|
|
215
|
+
|
|
216
|
+
| Group | Preference IDs |
|
|
217
|
+
|---|---|
|
|
218
|
+
| Discovery | `extraDirs`, `seed` |
|
|
219
|
+
| Startup | `defaultPersona`, `persist` |
|
|
220
|
+
| Interface | `keybinding` |
|
|
221
|
+
| Delegation | `delegateDefaultAllow`, `childThinking`, `engine`, `peekEveryMs`, `checkInEveryMs`, `agentHardTimeoutMs`, `agentStartupTimeoutMs`, `nudge`, `asyncRetain`, `ledgerV2`, `changeReport` |
|
|
222
|
+
| Collaboration | `broker`, `exocom` |
|
|
223
|
+
| Prompt | `spine`, `spineLegs` |
|
|
224
|
+
| Mind (when loaded) | `mindCapture` (`auto`/`prompt`/`off`), `mindNudge` |
|
|
225
|
+
| Flow (when loaded) | `flowEnabled`, `flowPort`, `flowIdleMs` |
|
|
226
|
+
|
|
227
|
+
`disabled` and the storage path are not editable preferences. Model assignments remain scoped by
|
|
228
|
+
persona owner, rather than being promoted into global preferences.
|
|
229
|
+
`selectionRevision` is internal metadata in the same file: explicit persona-selection gestures
|
|
230
|
+
increment it, while model/preference edits leave it unchanged. Companion readers can therefore
|
|
231
|
+
distinguish a re-selection from an unrelated settings save without following whole-file timestamps.
|
|
232
|
+
The editor never reloads Pi automatically. Scalar preferences load after a Pi restart or Pi's native
|
|
233
|
+
`/reload`; `/new` alone does not reactivate Persona's extension factory. `/persona reload` reloads
|
|
234
|
+
persona definitions and does not apply preference changes. The panel shows when a saved value is
|
|
235
|
+
pending reload. Model assignments are read by the
|
|
236
|
+
existing resolver for future runs, so they do not alter workers already running.
|
|
237
|
+
|
|
238
|
+
Mind and Flow report their supported settings through Pi's public event bus; the panel does not import
|
|
239
|
+
or require either plugin. Their preferences live in the same `preferences` object above, not in new
|
|
240
|
+
plugin configuration files. Skill Optimizer remains independent. Absent companions do not expose
|
|
241
|
+
nonfunctional controls. Updated companion versions are needed to contribute settings to this panel.
|
|
242
|
+
|
|
243
|
+
`flowEnabled` controls default dashboard attachment; `--no-flow` still opts out for one run.
|
|
244
|
+
`flowPort` is the desired port for the next shared service start, not a command to move an existing
|
|
245
|
+
service. `flowIdleMs` is the advanced shared-service idle grace (50–60000 ms): it applies only with
|
|
246
|
+
no Pi registrations **and** no browser SSE clients. Saving it never restarts another Pi's service.
|
|
247
|
+
|
|
248
|
+
Explicit public `PI_PERSONA_*` environment values retain startup precedence over saved preferences.
|
|
249
|
+
The panel marks an environment-controlled setting as locked; resetting its saved value only removes
|
|
250
|
+
that saved override and does not defeat the environment. `PI_PERSONA_DISABLE` is an internal
|
|
251
|
+
process guard and is not an editable setting.
|
|
252
|
+
|
|
253
|
+
When no canonical `settings.json` exists, startup imports the retired `config.json` model store and
|
|
254
|
+
`state.json` persona state (or the path supplied by `PI_PERSONA_STATE_FILE`) once. Successfully
|
|
255
|
+
migrated, unchanged legacy files are archived as `<file>.migrated`; if validation, safe archival, or
|
|
256
|
+
concurrency checks fail, the legacy source is kept and a warning is reported. Once `settings.json`
|
|
257
|
+
exists, it is the only active store: legacy files are not dual-read. An invalid or unsafe canonical
|
|
258
|
+
file is reported rather than overwritten. `PI_PERSONA_STATE_FILE` now only selects a legacy state
|
|
259
|
+
file to import when the canonical file does not yet exist; it does not move or redirect active
|
|
260
|
+
settings storage.
|
|
261
|
+
|
|
262
|
+
The model editor asks you to choose an owner persona and then its current or a named council
|
|
263
|
+
profile; it never activates that persona. It lists the roster and strategy-declared auxiliary
|
|
264
|
+
participants using the runtime model precedence described below. The searchable model picker uses
|
|
265
|
+
Pi's currently available provider-qualified models; opening the editor does not refresh provider
|
|
266
|
+
catalogs, and refresh is an explicit action. Saving or removing an assignment affects future runs.
|
|
267
|
+
Reset removes only that saved key (`null` in a settings patch), revealing lower-precedence sources
|
|
268
|
+
such as a bare agent assignment; inline model pins remain read-only. “Other saved assignments” lets
|
|
269
|
+
you remove keys outside the selected profile without exposing unsafe legacy key text.
|
|
270
|
+
|
|
271
|
+
The existing `/persona models [council-persona]` shortcut remains available for the active caller.
|
|
272
|
+
It refreshes the model catalog before editing, and a named council profile does not change which
|
|
273
|
+
persona owns the saved assignments. Use the Models action in `/persona-settings` when you need to
|
|
274
|
+
choose the owner explicitly.
|
|
275
|
+
|
|
276
|
+
#### Companion settings adapter contract
|
|
277
|
+
|
|
278
|
+
The optional synchronous bus channel `pi-persona:settings:collect:v1` receives
|
|
279
|
+
`{ add(id, values) }`. A loaded supervisor companion responds with `add("mind", { mindCapture,
|
|
280
|
+
mindNudge })` or `add("flow", { flowEnabled, flowPort, flowIdleMs })`, using its current startup
|
|
281
|
+
snapshot. Each may report a supported subset. Persona validates ownership/types against the same
|
|
282
|
+
registry used by the editor and displays only reported fields; an unrelated plugin cannot contribute
|
|
283
|
+
an optimizer or native Pi setting through this channel. Contributors must not read credentials,
|
|
284
|
+
refresh providers, write files, wake the model or start a service in response to collection.
|
|
285
|
+
|
|
286
|
+
Persona alone patches the canonical settings file; companions read their own known fields and
|
|
287
|
+
preserve their standalone operation and environment overrides. They must release/re-arm their
|
|
288
|
+
listener with the owning extension lifecycle. Add a new control by updating registry metadata,
|
|
289
|
+
validation, the owning consumer and contract tests—not by adding another settings writer.
|
|
290
|
+
|
|
191
291
|
`tools` accepts an allowlist such as `[read, grep]`, an `allow`/`deny` object, or `[]` for no tools.
|
|
192
292
|
Entries are plain tool names or `*` patterns; Pi's `+name`/`-name` default-tool modifier
|
|
193
293
|
syntax is not an allowlist and is rejected. Use the `deny` field to remove tools. Omit `tools` to
|
|
@@ -303,10 +403,28 @@ With an active persona, UI, and at least two configured models, unassigned parti
|
|
|
303
403
|
picked and saved for the active persona, even when borrowing another persona's council profile.
|
|
304
404
|
Dismissing a picker suppresses another prompt for that participant during the session, not for
|
|
305
405
|
later teams with different participants. Headless runs never prompt.
|
|
406
|
+
|
|
407
|
+
Run `/persona models` to explicitly reselect the active council's models, or `/persona models magi`
|
|
408
|
+
to edit the MAGI panel while keeping another supervisor active. The optional name selects an
|
|
409
|
+
installed council persona, not a strategy or team. The command refreshes the host catalog first,
|
|
410
|
+
then offers each editable participant, including previously dismissed choices and saved or agent
|
|
411
|
+
defaults. One available model is enough for this explicit edit. Choices are saved under the **active
|
|
412
|
+
caller's** persona, just as for `council({ persona: "magi" })`; it never activates the borrowed
|
|
413
|
+
profile. Cancelled choices, unrelated assignments and other personas remain unchanged. Inline
|
|
414
|
+
`members[].model` pins still win and are not editable here. TUI/RPC UI is required; no model call
|
|
415
|
+
is made. Changes apply to future runs, not workers already running. `/persona magi` still switches
|
|
416
|
+
the supervisor; `/persona reload` reloads definitions without resetting saved models.
|
|
417
|
+
Refresh is bounded to 20 seconds cooperatively; provider errors, cancellation, or a persona/session
|
|
418
|
+
change cancel the edit without replacing assignments. The list uses the host's refreshed availability,
|
|
419
|
+
not every model in its catalog.
|
|
420
|
+
|
|
306
421
|
An unavailable choice is not overwritten: a provider or unknown-model failure may recover once
|
|
307
422
|
on the main model, with the switch reported and both attempts accounted. This does not relax
|
|
308
423
|
ordinary delegate provider pins. The MAGI persona retains its canonical core team; the Judge
|
|
309
424
|
persona retains impartial arbitration. Other personas choose whichever strategy fits the task.
|
|
425
|
+
The exact Pi diagnostic `No API key found for <provider>` counts as a provider failure in both
|
|
426
|
+
engines, so it can use this same bounded recovery. If the main model is the failing model too,
|
|
427
|
+
recovery cannot help: use `/login` or change `/model`, then reselect with `/persona models`.
|
|
310
428
|
|
|
311
429
|
**A delegation policy on any persona** — fields are generic and are never keyed to a persona name.
|
|
312
430
|
The runtime rejects incomplete briefs before a model call, supplies a missing contract, rejects
|
|
@@ -420,8 +538,9 @@ test; the data-driven definitions above require no core change.
|
|
|
420
538
|
**Keys** — `f8` cycles persona; `f9` or `/agents` opens the agent overlay: ↑↓ navigate, ⏎ open, `x`
|
|
421
539
|
stop, `s` steer, and Esc close.
|
|
422
540
|
|
|
423
|
-
**Commands** — `/persona [name|off|list|reload|seed|restore
|
|
424
|
-
`/orchestrate <task>` · `/flow <name> <task>` ·
|
|
541
|
+
**Commands** — `/persona [name|off|list|reload|seed|restore|models [council-persona]]` ·
|
|
542
|
+
`/persona-settings [show]` · `/models [query]` · `/orchestrate <task>` · `/flow <name> <task>` ·
|
|
543
|
+
`/peek [id]` · `/exocom` · `/doctor`.
|
|
425
544
|
|
|
426
545
|
`/doctor` reports the cross-process broker's lifecycle on one line: `broker: on — endpoint …` once
|
|
427
546
|
the host is listening, `broker: on — (starting…)` mid-attempt, or
|
|
@@ -462,11 +581,14 @@ from a different cwd. Pi owns `--model <provider/id>`, `--thinking
|
|
|
462
581
|
| `PI_PERSONA_KEY` | `f8` | keybinding that cycles installed personas |
|
|
463
582
|
| `PI_PERSONA_PERSIST` | on | `off` stops remembering the last-selected persona across sessions |
|
|
464
583
|
| `PI_PERSONA_DELEGATE_DEFAULT` | allow | `deny` (or an off-word) makes an unlisted delegate target default-deny instead of default-allow |
|
|
465
|
-
| `PI_PERSONA_STATE_FILE` | a global default path | overrides where the last-selected-persona state is stored |
|
|
466
584
|
| `PI_PERSONA_ASYNC_RETAIN` | 25 | how many settled-but-uncollected async runs are retained before FIFO-evicting the oldest |
|
|
467
585
|
| `PI_PERSONA_LEDGER_V2` | off | `on` widens the delegation-ledger retry-veto key to also include role/tools/isolation, not just agent+model+task |
|
|
468
586
|
| `PI_PERSONA_LEG_CHANGE_REPORT` | on | `off` disables the non-worktree files-changed report (two `git status` spawns per leg) |
|
|
469
587
|
|
|
588
|
+
`PI_PERSONA_STATE_FILE` is only a migration input for the retired standalone state file; it no
|
|
589
|
+
longer selects an active persistence path. The canonical store is always
|
|
590
|
+
`<agentDir>/persona/settings.json`.
|
|
591
|
+
|
|
470
592
|
## Development
|
|
471
593
|
|
|
472
594
|
```bash
|
package/docs/TELEMETRY.md
CHANGED
|
@@ -8,6 +8,14 @@ waiting from tool arguments, output text or a quiet clock.
|
|
|
8
8
|
|
|
9
9
|
Telemetry is a vendor-neutral v2 envelope. `producerId` and `producerVersion` identify the emitting plugin; `version` identifies the wire schema. `seq` is monotonic only within `(producerId, sessionId)`, and `id` is deduplicated within that same scope.
|
|
10
10
|
|
|
11
|
+
Message payload `id` is the stable lifecycle-row key: queued and terminal updates keep it unchanged.
|
|
12
|
+
Optional `wireId` identifies the actual transport message, and `replyTo` references that transport's
|
|
13
|
+
original ID. Exocom sends attach `wireId` only after an exact target-correlated successful receipt;
|
|
14
|
+
broadcast receipts are bounded and omitted mappings remain unknown. Do not replace the queued row's
|
|
15
|
+
`id` with a wire ID, infer a mapping by timestamp/alias, or merge observations from different streams.
|
|
16
|
+
Single delegates publish their terminal progress before tree removal, so a completed worker remains
|
|
17
|
+
`done` in the telemetry instead of being mistaken for a stopped in-flight leg.
|
|
18
|
+
|
|
11
19
|
The pi-persona producer writes semantic projections under `telemetry/v2/<workspace>/<producerId>/`. `<workspace>` always identifies the Pi process's actual cwd; joining another Exocom scope does not rewrite telemetry identity. It never persists task/prompt text, tool arguments/activity, model output, paths, secrets, or message bodies. Known pi-persona event payloads are allowlisted; an unreviewed producer event retains only its envelope/type (payload `{}`) at the producer and consumer boundary. Future producers must add a reviewed allowlist/schema before publishing data intended for a consumer.
|
|
12
20
|
|
|
13
21
|
JSONL compaction is atomic and hysteretic. It preserves the initial `instance.started` anchor and complete records; the configured byte limit is therefore a soft bound for an anchor plus one complete event. The `.previous` backup is recovered after an interrupted swap.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aeondave/pi-persona",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Supervised multi-agent orchestration for Pi — async workers, live steering, cross-session collaboration, and switchable personas.",
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"typescript": "^7.0.2"
|
|
105
105
|
},
|
|
106
106
|
"pi": {
|
|
107
|
-
"image": "https://raw.githubusercontent.com/AeonDave/pi-persona/v1.
|
|
107
|
+
"image": "https://raw.githubusercontent.com/AeonDave/pi-persona/v1.17.1/assets/banner.png",
|
|
108
108
|
"video": "https://cdn.jsdelivr.net/gh/AeonDave/pi-persona@6655d281ce7965a75303dd704bd29db73db04070/assets/demo1.mp4",
|
|
109
109
|
"extensions": [
|
|
110
110
|
"./src/extension.ts"
|
package/src/core/config.ts
CHANGED
|
@@ -15,7 +15,7 @@ export interface PiPersonaConfig {
|
|
|
15
15
|
persist: boolean;
|
|
16
16
|
delegateDefaultAllow: boolean;
|
|
17
17
|
seed: boolean;
|
|
18
|
-
/**
|
|
18
|
+
/** Legacy selection-file import path; ongoing persistence uses persona/settings.json. */
|
|
19
19
|
stateFile?: string;
|
|
20
20
|
/** Thinking level forced on delegated children (else the supervisor's level).
|
|
21
21
|
* Spawned children must carry an *explicit* level or they fall into the model's
|