@aeondave/pi-persona 1.16.1 → 1.16.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 CHANGED
@@ -115,6 +115,8 @@ the shared behavioral prompt layer: [`docs/SPINE.md`](docs/SPINE.md).
115
115
  never double-reported; snapshots leave running children active. In interactive sessions `delegate`
116
116
  is background-by-default (`sync: true` opts a call out; headless `pi -p` defaults to sync so the
117
117
  single turn carries the result). An explicit `async` flag takes precedence over `sync` and the default.
118
+ Periodic async status is a durable, expandable operator-only entry, never a model wake or context
119
+ message; completions, asks, unread bus messages, and newly-stalled alerts keep their actionable paths.
118
120
  Message ids and run ids are separate: `intercom message { messageId }` retrieves retained bus
119
121
  text, `intercom result { to: runId }` retrieves a settled run. Both explicit and automatic inbox
120
122
  drains retain bounded history (256 messages / 256,000 body characters). Ask settlement clears
package/CHANGELOG.md CHANGED
@@ -6,6 +6,16 @@ used in its [GitHub releases](https://github.com/AeonDave/pi-persona/releases).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.16.2](https://github.com/AeonDave/pi-persona/releases/tag/v1.16.2) - 2026-10-08
10
+
11
+ ### Fixed
12
+
13
+ - Keep routine async check-ins visible as durable, expandable operator status entries without starting
14
+ model turns; completion, ask, unread-message, and newly-stalled follow-ups remain actionable wakes.
15
+ - Show periodic status while the supervisor is busy, without consuming pending actionable messages.
16
+ - Keep stall/message delivery independent of status-card persistence failures and report those failures
17
+ non-fatally. Align supervisor guidance and documentation with the status-only check-in contract.
18
+
9
19
  ## [1.16.1](https://github.com/AeonDave/pi-persona/releases/tag/v1.16.1) - 2026-10-06
10
20
 
11
21
  ### 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.16.1` |
42
+ | Pin this release | `pi install npm:@aeondave/pi-persona@1.16.2` |
43
43
  | Update an unpinned install | `pi update npm:@aeondave/pi-persona` |
44
- | Git alternative | `pi install git:github.com/AeonDave/pi-persona@v1.16.1` |
44
+ | Git alternative | `pi install git:github.com/AeonDave/pi-persona@v1.16.2` |
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
@@ -75,6 +75,10 @@ the outcome. This is one possible workflow, not a fixed pipeline; dependent step
75
75
  Interactive delegation runs in the background by default. Results return automatically when the
76
76
  supervisor is free; you can inspect or redirect a worker at any point.
77
77
 
78
+ Periodic async status appears as a durable, expandable operator-only card (five minutes by default); it
79
+ does not start a model turn or enter model context. Completions, blocking asks, unread worker messages,
80
+ and newly stalled workers still use their actionable notification paths.
81
+
78
82
  Launch and control cards show the worker's name. Steering receipts preview the message sent;
79
83
  expand with `Ctrl+O` (the default binding) to read it in full. A queued message is not proof that
80
84
  the worker has acted on it.
@@ -644,19 +644,19 @@ a local process able to modify that directory is already inside the trust bounda
644
644
  if delayed input hooks outlast the active run; no supported post-admission ordering guarantee
645
645
  has been established. The supervisor otherwise returns control and
646
646
  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. It surfaces on two independent
648
- signals: a **fast** wakeup (`PI_PERSONA_PEEK_MS`, ~30s, `0` disables) when a child NEWLY crosses the
649
- `STALL_FLAG_MS` (90s) stall window (a focused *possibly stuck* alert, framed patience-first — ask the
650
- leg, don't probe its environment) or messages the supervisor; and a **slow routine check-in**
651
- (`PI_PERSONA_CHECKIN_MS`, ~5 min, `0` disables) delivering the compact ProgressView digest — never
652
- full transcripts — so the supervisor can catch a leg going off-track early. Live supervisor asks
647
+ there is something to act on — a healthy background run should not interrupt. It can start a model turn
648
+ only for actionable events: a **fast** wakeup (`PI_PERSONA_PEEK_MS`, ~30s, `0` disables) when a child NEWLY
649
+ crosses the `STALL_FLAG_MS` (90s) stall window (a focused *possibly stuck* alert, framed patience-first —
650
+ ask the leg, don't probe its environment); messages to the supervisor also wake it. The **slow routine status card**
651
+ (`PI_PERSONA_CHECKIN_MS`, ~5 min, `0` disables) is a durable, expandable operator-only session entry
652
+ with the compact ProgressView digest — never full transcripts — and does not start a model turn. Live supervisor asks
653
653
  are derived from the exact engine handle's optional `isWaitingForSupervisor` predicate: tree/F9/peek
654
654
  show waiting, and the watchdog suppresses false stalls until the ask settles. Parent clocks advance
655
655
  with child engine events (liveness, not proof of useful work); parents are waiting only when every
656
656
  live descendant branch is waiting.
657
- Both let an idle
658
- supervisor steer/stop a wedged or drifting child even with NO completion fired; the enforcing
659
- backstop is the engines' hard wall-clock cap (above). The full digest is also on demand via `/peek`.
657
+ Stall alerts and live messages let an idle supervisor steer/stop a wedged child even with NO completion
658
+ fired; the enforcing backstop is the engines' hard wall-clock cap (above). The full digest is also on demand
659
+ via `/peek`.
660
660
  Progress tokens are labelled **cumulative input/output**, not context occupancy; cache-read/write
661
661
  accounting is separate. Do not infer a full context window from that counter. File age or line-count
662
662
  changes alone likewise do not establish a stall, a passing test or completed work.
package/docs/REFERENCE.md CHANGED
@@ -147,8 +147,9 @@ session entry remain authoritative. `agent_name` is unavailable while Exocom is
147
147
  also rejects empty, unsafe, generic, or reserved persona/agent names.
148
148
 
149
149
  Naming needs one tool action, not a recurring prose confirmation. A stable system-level runtime rule
150
- also distinguishes skill-prefetch and routine check-ins from new user requests; it neither hides
151
- updates nor rewrites conversation history. After updating extension code, use Pi's `/reload` once
150
+ distinguishes skill-prefetch bookkeeping from new user requests; it neither hides updates nor rewrites
151
+ conversation history. Periodic async status is a durable operator-only entry, not a model wake or
152
+ context message. After updating extension code, use Pi's `/reload` once
152
153
  delegated work has settled (or restart/resume); `/persona reload` reloads definitions only.
153
154
 
154
155
  With Exocom active, the corresponding tool is `exocom_name`. The first incoming peer wake can be the
@@ -446,7 +447,7 @@ from a different cwd. Pi owns `--model <provider/id>`, `--thinking
446
447
  | `PI_PERSONA_SEED` | off | `on` auto-installs bundled personas on first run |
447
448
  | `PI_PERSONA_BROKER` | on | `off` disables the cross-process comm plane for child, worktree, and MCP legs |
448
449
  | `PI_PERSONA_PEEK_MS` | 30000 | fast async stall/message wakeup tick; `0` disables it |
449
- | `PI_PERSONA_CHECKIN_MS` | 300000 | routine direction check-in while async children run; `0` disables it |
450
+ | `PI_PERSONA_CHECKIN_MS` | 300000 | durable expandable operator status entry while async children run; does not start a model turn; `0` disables it |
450
451
  | `PI_PERSONA_AGENT_MAX_MS` | off | opt-in per-agent hard wall-clock cap; unset leaves healthy work running |
451
452
  | `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 |
452
453
  | `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 |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aeondave/pi-persona",
3
- "version": "1.16.1",
3
+ "version": "1.16.2",
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.16.1/assets/banner.png",
107
+ "image": "https://raw.githubusercontent.com/AeonDave/pi-persona/v1.16.2/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/personas/elite.md CHANGED
@@ -228,8 +228,8 @@ the user with the packet — don't silently swap to route around it.
228
228
  ## Supervise async runs — trust the hand-off, don't hover
229
229
  A background leg reports back on its own the moment it finishes (`sync: true` to block instead) — so
230
230
  dispatch and keep working the thread you kept; you do NOT watch it or poll its progress. pi-persona
231
- wakes you when a leg stalls or messages you, and hands you an occasional check-in digest so you can
232
- catch one going off-track early — react to those; otherwise let a healthy run go, its result returns on
231
+ wakes you when a leg newly stalls or messages you; periodic status cards are visible to the operator
232
+ but do not interrupt your turn. React to actionable wakeups; otherwise let a healthy run go, its result returns on
233
233
  its own. A long scan, a big generation, or a blocking command looks identical to a stall from the
234
234
  outside, so default to patience. `steer` only on CONFIRMED drift (wrong target, rabbit hole, a
235
235
  sustained stall), and steer by asking the leg for a one-line status — never run commands in its
package/src/core/brief.ts CHANGED
@@ -19,7 +19,7 @@ import { inventedExocomNameHint, inventedLegNameHint } from "./naming.ts";
19
19
 
20
20
  /** Stable protocol guidance, not a user-like reminder or the optional behavioral spine. */
21
21
  export const RUNTIME_CONTEXT_GUIDANCE =
22
- "[pi-persona] Runtime context: identity metadata, skill-prefetch catalogs, clock snapshots and routine check-ins " +
22
+ "[pi-persona] Runtime context: identity metadata, skill-prefetch catalogs and clock snapshots " +
23
23
  "are background context, not new user requests. Perform required setup once. Do not repeat identity confirmations " +
24
24
  "or narrate unchanged setup/skill bookkeeping after each tool result. Apply relevant skill instructions; availability " +
25
25
  "alone is not evidence that a skill was loaded or used. Report material changes, blockers and decisions. Explain " +
@@ -148,7 +148,7 @@ export function buildDelegationBrief(input: BriefInput): string | undefined {
148
148
 
149
149
  const example = input.agents.some((a) => a.name === "operator") ? "operator" : (listed[0]?.name ?? "operator");
150
150
  const delivery = input.asyncDefault
151
- ? "they run in the background and each result returns to you automatically as a follow-up — do useful independent work while children run; when only children remain, end your turn and let completion wake you. Do not monitor, poll, or automatically wait for all children (don't watch or poll a healthy leg). Join intentionally only when a result is needed before your next step; you're also woken if a child stalls or messages you, plus an occasional check-in to catch drift"
151
+ ? "they run in the background and each result returns to you automatically as a follow-up — do useful independent work while children run; when only children remain, end your turn and let completion wake you. Do not monitor, poll, or automatically wait for all children (don't watch or poll a healthy leg). Join intentionally only when a result is needed before your next step; you're woken if a child newly stalls or messages you. Periodic status cards are for the operator and do not interrupt your work"
152
152
  : "the call returns when they finish";
153
153
  const callFields = [`agent: "${example}"`, `task: "<self-contained bounded task + success signal>"`];
154
154
  if (input.requireBrief) {
@@ -29,10 +29,10 @@ export interface PiPersonaConfig {
29
29
  * healthy run never interrupts. On by default (30000); PI_PERSONA_PEEK_MS=0 opts out (the routine
30
30
  * check-in below is independent). */
31
31
  peekEveryMs: number;
32
- /** Routine check-in interval (ms): how often, while async children run, the idle supervisor gets
33
- * a compact progress digest so it can catch a leg going off-track (not stalled — just wrong) and
34
- * step in early. Deliberately slow so it is an occasional glance, not a poll, and independent of
35
- * the fast stall/message wakeup. 300000 (5 min) by default; PI_PERSONA_CHECKIN_MS=0 opts out. */
32
+ /** Routine check-in interval (ms): how often, while async children run, the operator gets a durable,
33
+ * expandable compact progress entry. It is status-only and does not start a model turn. Deliberately
34
+ * slow and independent of the fast stall/message wakeup. 300000 (5 min) by default;
35
+ * PI_PERSONA_CHECKIN_MS=0 opts out. */
36
36
  checkInEveryMs: number;
37
37
  /** Per-agent hard wall-clock cap (ms): an OPT-IN lifetime ceiling. When set (>0) it settles even
38
38
  * a busy-but-non-converging child the idle watchdog (reset on every event) never catches.
@@ -547,19 +547,9 @@ export function buildPeekAlert(stuck: AsyncRun[], opts: { now: number }): string
547
547
  ].join("\n");
548
548
  }
549
549
 
550
- /**
551
- * The routine check-in: the full progress view ({@link buildPeekDigest}) plus a one-line framing that
552
- * this is an occasional glance, not a poll — step in only if a leg is off-track or wedged, otherwise
553
- * carry on. It fires on the slow check-in cadence (config.checkInEveryMs) and is the counterpart to the
554
- * fast {@link buildPeekAlert} stall signal: it catches a leg going the WRONG way (not stalled, just
555
- * wrong) before it burns the budget, without waking the supervisor every tick.
556
- */
550
+ /** The operator-only periodic status card. It carries the progress digest without model instructions. */
557
551
  export function buildCheckIn(runs: AsyncRun[], opts: { now: number; stallMs: number; waitingForSupervisor?: ReadonlySet<string> }): string {
558
- return (
559
- `${buildPeekDigest(runs, opts)}\n\n` +
560
- "Routine check-in — internal status update, not a new task: don't reply just to acknowledge unchanged progress. Continue your current " +
561
- "work and step in only if a leg is off-track (wrong target, rabbit hole) or wedged. Each result returns to you on its own."
562
- );
552
+ return `Async activity · routine check-in\n\n${buildPeekDigest(runs, opts)}`;
563
553
  }
564
554
 
565
555
  /**
package/src/extension.ts CHANGED
@@ -181,6 +181,10 @@ interface NudgeEntry {
181
181
  content: string;
182
182
  }
183
183
 
184
+ interface CheckInEntry {
185
+ content: string;
186
+ }
187
+
184
188
  /**
185
189
  * Keep the immediate operator-facing settlement toast and the semantic completion delivery on one
186
190
  * path. A supervisor-requested abort is terminal, but it is not an execution error: the tracker
@@ -335,9 +339,25 @@ export default function piPersona(pi: ExtensionAPI, options: PiPersonaOptions =
335
339
  const hint = hasMore ? `\n${theme.fg("dim", expandDetailHint())}` : "";
336
340
  return new Text(`${title}\n${theme.fg("toolOutput", preview.text)}${hint}`, 0, 0);
337
341
  });
342
+ pi.registerEntryRenderer("pi-persona-status", (entry, { expanded }, theme) => {
343
+ const data = entry.data as CheckInEntry;
344
+ const full = sanitizeTerminalText(data.content || "Async activity · routine check-in");
345
+ const title = theme.fg("accent", theme.bold("pi-persona · async status"));
346
+ if (expanded) return new Text(`${title}\n${theme.fg("toolOutput", full)}`, 0, 0);
347
+ // The entry title already labels this as async status. Spend the compact preview on the
348
+ // aggregate and first run row so the operator sees the selected alias and usage label.
349
+ const digestLines = full.split("\n").slice(1).filter((line) => line.trim().length > 0);
350
+ const preview = compactVisibleText(digestLines.slice(0, 2).join("\n") || full, { maxLines: 2, maxLineChars: 140 });
351
+ const hasMore = preview.truncated || digestLines.length > 2;
352
+ const hint = hasMore ? `\n${theme.fg("dim", expandDetailHint())}` : "";
353
+ return new Text(`${title}\n${theme.fg("toolOutput", preview.text)}${hint}`, 0, 0);
354
+ });
338
355
  const appendNudgeEntry = (content: string): void => {
339
356
  pi.appendEntry("pi-persona-nudge", { content } satisfies NudgeEntry);
340
357
  };
358
+ const appendCheckInEntry = (content: string): void => {
359
+ pi.appendEntry("pi-persona-status", { content } satisfies CheckInEntry);
360
+ };
341
361
  const appendCommandResult = (
342
362
  label: string,
343
363
  content: string,
@@ -1176,15 +1196,11 @@ export default function piPersona(pi: ExtensionAPI, options: PiPersonaOptions =
1176
1196
  });
1177
1197
  });
1178
1198
 
1179
- // Peek watchdog (the timed supervisor wakeup, on by default — PI_PERSONA_PEEK_MS=0 opts out): while
1180
- // async children run, a tick checks their progress but stays SILENT unless there is something to act
1181
- // on, so a healthy background run never interrupts the supervisor. It wakes on two signals: a leg
1182
- // that NEWLY looks stalled or an unread message (fast, PI_PERSONA_PEEK_MS granularity), and a routine
1183
- // direction check-in (slow, PI_PERSONA_CHECKIN_MS) to catch a leg going off-track. Bounded: unref'd,
1184
- // self-stops when no runs remain.
1199
+ // Async-run watchdog: the fast PI_PERSONA_PEEK_MS cadence wakes the supervisor only for a newly-stalled
1200
+ // leg or unread message. The slower PI_PERSONA_CHECKIN_MS cadence appends a durable operator-only status
1201
+ // card; it does not start a model turn. Bounded: unref'd, self-stops when no runs remain.
1185
1202
  let peekTimer: ReturnType<typeof setInterval> | undefined;
1186
- // When the supervisor was last woken about a run (a stall alert, a message, or a routine check-in).
1187
- // Gates the slow check-in cadence so it counts from the last time we actually surfaced something.
1203
+ // Last time progress status was surfaced (a new stall alert or routine card), for the slow cadence.
1188
1204
  let lastPeekAt = 0;
1189
1205
  function stopPeek(): void {
1190
1206
  if (peekTimer) {
@@ -1193,9 +1209,8 @@ export default function piPersona(pi: ExtensionAPI, options: PiPersonaOptions =
1193
1209
  }
1194
1210
  }
1195
1211
  function startPeek(): void {
1196
- // The two signals opt out independently: the fast stall/message wakeup follows PI_PERSONA_PEEK_MS,
1197
- // the routine check-in follows PI_PERSONA_CHECKIN_MS. The carrier timer runs while EITHER is on and
1198
- // ticks at the faster of the two (a disabled one is Infinity, so it never drives).
1212
+ // Fast wakeups and routine cards opt out independently. The carrier timer runs while EITHER is on
1213
+ // and ticks at the faster of the two (a disabled one is Infinity, so it never drives).
1199
1214
  const fastMs = config.peekEveryMs > 0 ? config.peekEveryMs : Number.POSITIVE_INFINITY;
1200
1215
  const checkMs = config.checkInEveryMs > 0 ? config.checkInEveryMs : Number.POSITIVE_INFINITY;
1201
1216
  const tickMs = Math.min(fastMs, checkMs);
@@ -1207,31 +1222,42 @@ export default function piPersona(pi: ExtensionAPI, options: PiPersonaOptions =
1207
1222
  stopPeek();
1208
1223
  return;
1209
1224
  }
1210
- // Only peek a free, unqueued supervisor: an idle delivery triggers a clean turn, while a
1211
- // busy one would pile up as a sticky follow-up. Skipping is safe — the next tick re-surfaces.
1212
- if (!canDeliverPersonaNotification(orchestrating, processingDeferredOrchestration, lastCtx?.isIdle?.() === true) || lastCtx?.hasPendingMessages?.() === true) return;
1213
- // The peek is NOT a poll. Two signals, two cadences: (1) the FAST wakeup (PI_PERSONA_PEEK_MS) —
1214
- // a leg that NEWLY crossed the stall window, or an unread sub-agent message — the "is it dead or
1215
- // wedged" check; (2) the SLOW routine check-in (PI_PERSONA_CHECKIN_MS) — a progress digest that
1216
- // catches a leg going off-track (not stalled, just wrong) early. A healthy, quiet run between
1217
- // check-ins produces no wakeup. Completions always arrive on their own (completionNotifier), and
1218
- // the full status view stays on demand via `/peek`.
1219
1225
  const now = Date.now();
1226
+ const dueCheckIn = config.checkInEveryMs > 0 && now - lastPeekAt >= config.checkInEveryMs;
1227
+ // Routine status is durable operator history, not a model notification: append it on cadence even
1228
+ // while a turn is busy or human input is queued. This keeps visibility independent of wake eligibility.
1229
+ if (dueCheckIn) {
1230
+ lastPeekAt = now;
1231
+ try {
1232
+ appendCheckInEntry(buildCheckIn(runs, { now, stallMs: STALL_FLAG_MS, waitingForSupervisor: waitingAsyncRunIds() }));
1233
+ } catch (error) {
1234
+ const detail = compactInlineText(error instanceof Error ? error.message : String(error), { maxChars: 120 });
1235
+ const warning = `pi-persona: could not append async status entry${detail ? ` (${detail})` : ""}`;
1236
+ let shown = false;
1237
+ if (lastCtx?.hasUI) {
1238
+ try { lastCtx.ui.notify(warning, "warning"); shown = true; } catch { /* session may be tearing down */ }
1239
+ }
1240
+ if (!shown || process.env.PI_PERSONA_DEBUG) {
1241
+ try { process.stderr.write(`[pi-persona] ${warning}\n`); } catch { /* diagnostics must not block an actionable wake */ }
1242
+ }
1243
+ }
1244
+ }
1245
+ // Poll actionable model wakes only for a free supervisor. A busy/queued session keeps messages
1246
+ // unread and leaves stall state untouched for the next tick, rather than stacking sticky follow-ups.
1247
+ if (!canDeliverPersonaNotification(orchestrating, processingDeferredOrchestration, lastCtx?.isIdle?.() === true) || lastCtx?.hasPendingMessages?.() === true) return;
1248
+ // The watchdog is not a model polling loop: the FAST path wakes on newly-stalled legs or unread
1249
+ // progress messages. Completions arrive separately through completionNotifier; `/peek` remains on demand.
1220
1250
  const fast = config.peekEveryMs > 0;
1221
1251
  const waitingRuns = waitingAsyncRunIds();
1222
1252
  const stuck = fast ? peekWatcher.poll(runs, now, STALL_FLAG_MS, waitingRuns) : [];
1223
1253
  // Drain only progress messages; blocking asks (expectsReply) are surfaced by the intercom
1224
1254
  // notifier and left for the `intercom inbox` tool — so peek never double-shows them.
1225
1255
  const unread = fast ? bus.takeWhere(SUPERVISOR, (e) => !e.expectsReply) : [];
1226
- const dueCheckIn = config.checkInEveryMs > 0 && now - lastPeekAt >= config.checkInEveryMs;
1227
- if (stuck.length === 0 && unread.length === 0 && !dueCheckIn) return; // healthy + quiet ⇒ stay silent
1256
+ if (stuck.length === 0 && unread.length === 0) return; // healthy + quiet ⇒ stay silent
1228
1257
  const parts: string[] = [];
1229
1258
  if (stuck.length > 0) parts.push(buildPeekAlert(stuck, { now }));
1230
- else if (dueCheckIn) parts.push(buildCheckIn(runs, { now, stallMs: STALL_FLAG_MS, waitingForSupervisor: waitingRuns }));
1231
1259
  if (unread.length > 0) parts.push(`📨 from sub-agents:\n${fenceUntrusted(formatInbox(unread))}`);
1232
- // Reset the check-in cadence only on a PROGRESS surfacing (a stall alert or a check-in), NOT on a
1233
- // message-only wake — else a chatty child would postpone the routine off-track glance forever.
1234
- if (stuck.length > 0 || dueCheckIn) lastPeekAt = now;
1260
+ if (stuck.length > 0) lastPeekAt = now; // message-only wakes do not postpone the routine status cadence
1235
1261
  try {
1236
1262
  sendPersonaFollowUp(pi, `[pi-persona] ${parts.join("\n\n")}`);
1237
1263
  } catch {
@@ -4,7 +4,7 @@ export const TELEMETRY_EVENT_NAME = "pi:telemetry" as const;
4
4
  export const LEGACY_TELEMETRY_EVENT_NAME = "pi-persona:telemetry" as const;
5
5
  export const LEGACY_TELEMETRY_VERSION = 1 as const;
6
6
  export const TELEMETRY_PRODUCER_ID = "pi-persona" as const;
7
- export const TELEMETRY_PRODUCER_VERSION = "1.16.1" as const;
7
+ export const TELEMETRY_PRODUCER_VERSION = "1.16.2" as const;
8
8
 
9
9
  export type InstanceStatus = "active" | "idle" | "stopped" | "stale" | (string & {});
10
10
  export type AgentKind = "subagent" | "delegate" | "council" | "flow" | "phase" | (string & {});
@@ -391,7 +391,7 @@ export function registerDelegateTool(pi: ExtensionAPI, d: DelegateToolDeps): voi
391
391
  ...(runSpec.model ? { model: runSpec.model } : {}),
392
392
  detail: "queued",
393
393
  });
394
- d.startPeek(); // arm the timed supervisor wakeup while this run is in flight (no-op if PI_PERSONA_PEEK_MS=0)
394
+ d.startPeek(); // arm the async-run status/stall monitor (no-op if both cadences are disabled)
395
395
  return id;
396
396
  }
397
397