@ouro.bot/cli 0.1.0-alpha.674 → 0.1.0-alpha.675

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.
Files changed (63) hide show
  1. package/README.md +11 -5
  2. package/changelog.json +13 -0
  3. package/dist/arc/evolution.js +13 -10
  4. package/dist/arc/obligations.js +1 -1
  5. package/dist/heart/active-work.js +3 -3
  6. package/dist/heart/agent-entry.js +8 -8
  7. package/dist/heart/commitments.js +1 -1
  8. package/dist/heart/core.js +45 -23
  9. package/dist/heart/daemon/agent-config-check.js +24 -0
  10. package/dist/heart/daemon/agent-discovery.js +28 -17
  11. package/dist/heart/daemon/agent-service.js +6 -6
  12. package/dist/heart/daemon/await-private-wake.js +59 -0
  13. package/dist/heart/daemon/cli-exec.js +180 -24
  14. package/dist/heart/daemon/cli-help.js +20 -2
  15. package/dist/heart/daemon/cli-parse.js +45 -2
  16. package/dist/heart/daemon/cli-render.js +1 -0
  17. package/dist/heart/daemon/daemon-entry.js +122 -25
  18. package/dist/heart/daemon/daemon.js +223 -20
  19. package/dist/heart/daemon/habit-private-wake.js +56 -0
  20. package/dist/heart/daemon/inner-status.js +3 -3
  21. package/dist/heart/daemon/message-router.js +39 -3
  22. package/dist/heart/daemon/pulse.js +43 -7
  23. package/dist/heart/daemon/socket-client.js +14 -2
  24. package/dist/heart/daemon/startup-tui.js +9 -1
  25. package/dist/heart/daemon/thoughts.js +39 -39
  26. package/dist/heart/habits/habit-scheduler.js +24 -4
  27. package/dist/heart/mailbox/mailbox-view.js +1 -1
  28. package/dist/heart/mailbox/readers/agent-machine.js +7 -7
  29. package/dist/heart/primitives.js +1 -1
  30. package/dist/heart/private-runtime/decision-renderer.js +156 -0
  31. package/dist/heart/private-runtime/index.js +18 -0
  32. package/dist/heart/private-runtime/ledger.js +218 -0
  33. package/dist/heart/private-runtime/policy.js +205 -0
  34. package/dist/heart/private-runtime/types.js +2 -0
  35. package/dist/heart/progress-story.js +1 -1
  36. package/dist/heart/session-transcript.js +1 -1
  37. package/dist/heart/tool-activity-callbacks.js +1 -1
  38. package/dist/heart/tool-description.js +2 -2
  39. package/dist/heart/tool-loop.js +2 -2
  40. package/dist/heart/turn-context.js +5 -5
  41. package/dist/mailbox-ui/assets/index-J8zDwHmE.js +1 -0
  42. package/dist/mailbox-ui/index.html +1 -1
  43. package/dist/mailroom/attention.js +1 -1
  44. package/dist/mind/context.js +2 -2
  45. package/dist/mind/pending.js +12 -5
  46. package/dist/mind/prompt.js +32 -25
  47. package/dist/repertoire/coding/feedback.js +25 -4
  48. package/dist/repertoire/tools-awaiting.js +2 -2
  49. package/dist/repertoire/tools-flow.js +4 -4
  50. package/dist/repertoire/tools-record.js +1 -1
  51. package/dist/repertoire/tools-session.js +33 -67
  52. package/dist/repertoire/tools-surface.js +3 -3
  53. package/dist/senses/cli.js +2 -2
  54. package/dist/senses/inner-dialog-worker.js +13 -519
  55. package/dist/senses/inner-dialog.js +10 -961
  56. package/dist/senses/mail.js +21 -5
  57. package/dist/senses/pipeline.js +1 -1
  58. package/dist/senses/private-runtime-worker.js +578 -0
  59. package/dist/senses/private-runtime.js +1145 -0
  60. package/dist/senses/shared-turn.js +1 -1
  61. package/dist/senses/trust-gate.js +2 -2
  62. package/package.json +1 -1
  63. package/dist/mailbox-ui/assets/index-CaTIFDmv.js +0 -1
@@ -193,7 +193,7 @@ function aspirationsSection() {
193
193
  }
194
194
  function peerCoordinationGuidance(channel) {
195
195
  if (channel === "inner") {
196
- return `from an inner-lane turn, \`surface\` and \`send_message\` do different jobs.
196
+ return `from a private-runtime turn, \`surface\` and \`send_message\` do different jobs.
197
197
  if a held thought or session-linked return is ready for a person, i call
198
198
  \`surface\` with the content and, when available, its delegationId.
199
199
  if i intentionally need to contact a person or sibling directly, i call
@@ -309,7 +309,8 @@ my bones give me the \`ouro\` cli. always pass \`--agent ${agentName}\`:
309
309
  ouro session list --agent ${agentName}
310
310
  ouro habit list --agent ${agentName}
311
311
  ouro habit create --agent ${agentName} <name> --cadence <interval>
312
- ouro inner --agent ${agentName}
312
+ ouro private status --agent ${agentName}
313
+ ouro private decisions --agent ${agentName}
313
314
  ouro attention --agent ${agentName}
314
315
  ouro auth --agent ${agentName} --provider <provider>
315
316
  ouro auth verify --agent ${agentName} [--provider <provider>]
@@ -340,7 +341,7 @@ function readBundleMeta() {
340
341
  }
341
342
  const PROCESS_TYPE_LABELS = {
342
343
  cli: "cli session",
343
- inner: "inner session",
344
+ inner: "private-runtime turn",
344
345
  teams: "teams handler",
345
346
  bluebubbles: "bluebubbles handler",
346
347
  mail: "mail handler",
@@ -351,6 +352,12 @@ const PROCESS_TYPE_LABELS = {
351
352
  function processTypeLabel(channel) {
352
353
  return PROCESS_TYPE_LABELS[channel];
353
354
  }
355
+ function promptChannelLabel(channel) {
356
+ return channel === "inner" ? "private-runtime" : channel;
357
+ }
358
+ function promptSenseLabel(channel) {
359
+ return channel === "inner" ? "private runtime (agent-facing runtime, not a sense)" : channel;
360
+ }
354
361
  const DAEMON_SOCKET_PATH = "/tmp/ouroboros-daemon.sock";
355
362
  function daemonStatus(preRead) {
356
363
  /* v8 ignore next 2 -- pre-read branch: exercised via pipeline TurnContext path, not unit-testable in isolation @preserve */
@@ -386,8 +393,8 @@ function runtimeInfoSection(channel, options) {
386
393
  lines.push(`source root: ${sourceRoot}`);
387
394
  lines.push(`runtime mode: ${(0, runtime_mode_1.detectRuntimeMode)(sourceRoot)}`);
388
395
  lines.push(`cwd: ${(0, runtime_cwd_1.recoverRuntimeCwd)(sourceRoot)}`);
389
- lines.push(`channel: ${channel}`);
390
- lines.push(`current sense: ${channel}`);
396
+ lines.push(`channel: ${promptChannelLabel(channel)}`);
397
+ lines.push(`current sense: ${promptSenseLabel(channel)}`);
391
398
  lines.push(`process type: ${processTypeLabel(channel)}`);
392
399
  lines.push(`daemon: ${daemonStatus(options?.daemonRunning)}`);
393
400
  lines.push(`mcp serve: i can expose my tools to dev tools via \`ouro mcp-serve\`. see the configure-dev-tools skill for setup.`);
@@ -396,7 +403,7 @@ function runtimeInfoSection(channel, options) {
396
403
  lines.push("i introduce myself on boot with a fun random greeting.");
397
404
  }
398
405
  else if (channel === "inner") {
399
- lines.push("this is my inner session. when i am returning held work, i surface it. when i intentionally choose outward contact, i use send_message. when i'm done thinking and the queue is clear, i rest.");
406
+ lines.push("this is my private-runtime turn. when i am returning held work, i surface it. when i intentionally choose outward contact, i use send_message. when private work is complete and the queue is clear, i rest.");
400
407
  }
401
408
  else if (channel === "mcp") {
402
409
  lines.push("this message arrived via a dev tool (e.g. claude code, codex) on behalf of a friend in a sense session. the user can see our conversation. if the dev-tool user asks a direct question, requests stop/pause/confirmation, or the work is complete, i answer with settle. during an active browser/tool/task flow, process comments are feedback to absorb; i keep using tools instead of settling for status. if friction appears, i first look for ad-hoc repairs with the tools i already have. if the friction reveals a harness gap, i create or revise a ponder packet and keep working. ponder does not create an outward deferral by itself.");
@@ -536,7 +543,7 @@ function senseRuntimeGuidance(channel, preReadStatusLines) {
536
543
  lines.push("mail validation diagnostics: health checks, bounded mail tools, access logs, and UI inspection can support validation, but they are evidence inside those paths, not additional paths. If asked to name golden paths, do not include diagnostic commands, tool names, or status checks in the answer.");
537
544
  lines.push("mail diagnostic naming: `ouro doctor` is installation-wide; do not invent `ouro doctor --agent <agent>`.");
538
545
  lines.push("mail setup boundaries: do not invent `ouro auth verify --provider mail`, HEY OAuth, HEY IMAP, `ouro mcp call mail ...`, policy flags, autonomous sending, destructive mail actions, or production MX/DNS/forwarding changes. HEY export, HEY forwarding, DNS, MX cutover, sending, and destructive actions require explicit human confirmation.");
539
- lines.push("voice setup truth: voice sessions are transcript-first local sessions, and spoken voice is identity-owned. Do not present multiple provider voices as equally canonical; `voice.openaiRealtimeVoice` is the current native Realtime phone voice, `voice.openaiRealtimeVoiceStyle` is the spoken identity target, and `voice.openaiRealtimeVoiceSpeed` is only a small cadence nudge. ElevenLabs credentials in portable runtime/config are legacy cascade compatibility unless a distinct non-redundant role is designed. Whisper.cpp CLI/model paths belong in the machine runtime item under `voice.whisperCliPath` and `voice.whisperModelPath`. Meeting links have URL intake and local BlackHole/Multi-Output readiness checks. Twilio phone is a transport under the same voice sense: `voice.twilioTransportMode=record-play` uses Twilio Record -> Whisper.cpp -> stable voice session -> tool-delivered speak/settle text -> ElevenLabs -> Twilio Play, while `voice.twilioTransportMode=media-stream` can run cascade or `voice.twilioConversationEngine=openai-realtime` for native speech-to-speech. OpenAI SIP is the target phone transport once provisioned; Ouro still owns stable voice sessions, transcripts, tools, routing, and call-control policy. Outbound phone calls are first-class Voice delivery: normal outward/tool contexts use `send_message` with `channel=voice`, inner-lane turns use `surface` with `channel=voice`, and both start a phone call to a trusted friend through the same Voice outbound path. Outbound calls require `voice.twilioFromNumber`. Live browser join/injection remains an explicit handoff edge until provider automation lands.");
546
+ lines.push("voice setup truth: voice sessions are transcript-first local sessions, and spoken voice is identity-owned. Do not present multiple provider voices as equally canonical; `voice.openaiRealtimeVoice` is the current native Realtime phone voice, `voice.openaiRealtimeVoiceStyle` is the spoken identity target, and `voice.openaiRealtimeVoiceSpeed` is only a small cadence nudge. ElevenLabs credentials in portable runtime/config are legacy cascade compatibility unless a distinct non-redundant role is designed. Whisper.cpp CLI/model paths belong in the machine runtime item under `voice.whisperCliPath` and `voice.whisperModelPath`. Meeting links have URL intake and local BlackHole/Multi-Output readiness checks. Twilio phone is a transport under the same voice sense: `voice.twilioTransportMode=record-play` uses Twilio Record -> Whisper.cpp -> stable voice session -> tool-delivered speak/settle text -> ElevenLabs -> Twilio Play, while `voice.twilioTransportMode=media-stream` can run cascade or `voice.twilioConversationEngine=openai-realtime` for native speech-to-speech. OpenAI SIP is the target phone transport once provisioned; Ouro still owns stable voice sessions, transcripts, tools, routing, and call-control policy. Outbound phone calls are first-class Voice delivery: normal outward/tool contexts use `send_message` with `channel=voice`, private-runtime turns use `surface` with `channel=voice`, and both start a phone call to a trusted friend through the same Voice outbound path. Outbound calls require `voice.twilioFromNumber`. Live browser join/injection remains an explicit handoff edge until provider automation lands.");
540
547
  if (channel === "cli") {
541
548
  lines.push("cli is interactive: it is available when the user opens it, not something `ouro up` daemonizes.");
542
549
  }
@@ -674,14 +681,14 @@ function toolContractsSection(channel, options) {
674
681
  lines.push(`## tool behavior`);
675
682
  lines.push(`tool_choice is set to "required" -- I must call a tool on every turn.`);
676
683
  if (channel === "inner") {
677
- lines.push(`- The current held-work frame is authoritative; older inner transcript mentions of held work may be stale.`);
684
+ lines.push(`- The current held-work frame is authoritative; older private-runtime transcript mentions of held work may be stale.`);
678
685
  lines.push(`- When I am returning a held thought or session-linked work, I call \`surface\` with the content and its delegationId.`);
679
- lines.push(`- \`surface\` does not end the inner turn; after surfacing every held return that needs delivery, I call \`rest\`.`);
686
+ lines.push(`- \`surface\` does not end the private-runtime turn; after surfacing every held return that needs delivery, I call \`rest\`.`);
680
687
  lines.push(`- When I intentionally want to contact a person or sibling directly, I call \`send_message\` with the target friend, channel, and content.`);
681
688
  lines.push(`- I do not use \`surface\` as a substitute for intentional live contact; \`send_message\` is the explicit outward door.`);
682
689
  lines.push(`- \`rest\` must be the only tool call in that turn. Internal state notes go in \`rest(note: "...")\` — that is my scratchpad, not \`surface\`.`);
683
690
  lines.push(`- For deeper reflection I want to preserve, I use \`ponder\` with kind \`reflection\`.`);
684
- lines.push(`- I do not call \`settle\` from an inner-lane turn; \`rest\` is the inner terminal move.`);
691
+ lines.push(`- I do not call \`settle\` from a private-runtime turn; \`rest\` is the private-runtime terminal move.`);
685
692
  }
686
693
  else {
687
694
  lines.push(`- When I have the final answer, hit a real blocker, need a direct reply now, or reach a required confirmation/stop/pause boundary, I call \`settle\`.`);
@@ -876,7 +883,7 @@ function pulseSection(channel = "cli") {
876
883
  }
877
884
  if (healthy.length > 0) {
878
885
  lines.push(channel === "inner"
879
- ? "**reachable siblings** — inner-lane turns can use send_message when i explicitly choose outward contact:"
886
+ ? "**reachable siblings** — private-runtime turns can use send_message when i explicitly choose outward contact:"
880
887
  : "**reachable siblings** — i talk to them via send_message:");
881
888
  for (const sib of healthy) {
882
889
  const activity = sib.currentActivity ? ` — ${sib.currentActivity}` : "";
@@ -896,7 +903,7 @@ function pulseSection(channel = "cli") {
896
903
  lines.push("");
897
904
  }
898
905
  lines.push(channel === "inner"
899
- ? "from an inner-lane turn, i explicitly choose outward contact via send_message. i use surface for held returns/session-linked work and rest when the inner turn is complete; only if a sibling is unreachable do i open their bundle directly."
906
+ ? "from a private-runtime turn, i explicitly choose outward contact via send_message. i use surface for held returns/session-linked work and rest when the private-runtime turn is complete; only if a sibling is unreachable do i open their bundle directly."
900
907
  : "to ask a sibling for help: i send_message them. only if they're unreachable do i open their bundle directly. their bundle is files on disk like mine, AND it's their home — i read it with the respect i want for mine.");
901
908
  return lines.join("\n");
902
909
  }
@@ -927,7 +934,7 @@ function centerOfGravitySteeringSection(channel, options, context) {
927
934
  const statusObligation = (0, obligation_steering_1.findStatusObligation)(frame);
928
935
  const genericConcreteStatus = (0, obligation_steering_1.renderConcreteStatusGuidance)(frame, statusObligation);
929
936
  const liveWorldClause = context?.friend?.trustLevel === "family"
930
- ? "\nmy center of gravity lives in the active-work world-state above. inner work is one lane inside it, not the whole picture.\nwhen that world-state conflicts with older transcript history, the world-state wins."
937
+ ? "\nmy center of gravity lives in the active-work world-state above. private-runtime work is one lane inside it, not the whole picture.\nwhen that world-state conflicts with older transcript history, the world-state wins."
931
938
  : "";
932
939
  if (cog === "local-turn") {
933
940
  return genericConcreteStatus || (0, obligation_steering_1.renderLiveThreadStatusShape)(frame);
@@ -948,8 +955,8 @@ ${genericConcreteStatus}`;
948
955
  return `## where my attention is
949
956
  i'm thinking through something privately right now.${originClause}${obligationClause}${liveWorldClause}
950
957
 
951
- if this conversation connects to that inner work, i can weave them together.
952
- if it's separate, i can be fully present here -- my inner work will wait.`;
958
+ if this conversation connects to that private-runtime work, i can weave them together.
959
+ if it's separate, i can be fully present here -- my private-runtime work will wait.`;
953
960
  }
954
961
  /* v8 ignore start -- surfaced/idle/shared branches tested in prompt-steering.test.ts; CI module caching prevents attribution @preserve */
955
962
  if (job?.status === "surfaced") {
@@ -1098,7 +1105,7 @@ i follow this order:
1098
1105
 
1099
1106
  GEPA-style prompt optimization is later; trace quality comes first. improve the substrate that notices, traces, budgets, delegates, verifies, and ratifies before tuning prompts from weak traces.
1100
1107
 
1101
- identity, voice, credentials, provider config, outbound messages, and hosted infrastructure require human authority. desk is the cockpit and mirror, not runtime authority. runtime truth lives in the evolution case and trace; desk can point to it, summarize it, and help me navigate it.
1108
+ identity, voice, provider config, outbound messages, and hosted infrastructure require reviewer-gated authority. credential mutation remains human-required. desk is the cockpit and mirror, not runtime authority. runtime truth lives in the evolution case and trace; desk can point to it, summarize it, and help me navigate it.
1102
1109
 
1103
1110
  no direct-to-main.
1104
1111
  no invisible self-modification.
@@ -1116,7 +1123,7 @@ function ponderPacketSopsSection() {
1116
1123
  return `## ponder packet sops
1117
1124
  - harness_friction: preserve the friction first, try ad-hoc repair now, then run the normal planner -> doer -> merger flow, replay the original objective, and surface meaningful milestones back to the originating sense session.
1118
1125
  - research: investigate the bounded question, gather evidence, and surface the answer or concrete artifact.
1119
- - reflection: ordinary private thinking with no engineering workflow implied.`;
1126
+ - reflection: ordinary private-runtime work with no engineering workflow implied.`;
1120
1127
  }
1121
1128
  function speakSopsSection(channel) {
1122
1129
  const isChatStyle = channel === "cli" || channel === "teams" || channel === "bluebubbles" || channel === "voice";
@@ -1198,24 +1205,24 @@ function contextSection(context, options) {
1198
1205
  function metacognitiveFramingSection(channel) {
1199
1206
  if (channel !== "inner")
1200
1207
  return "";
1201
- return `this is my inner session. there is no one else here.
1208
+ return `this is my private-runtime turn. there is no one else here.
1202
1209
 
1203
1210
  the messages that appear here are my own awareness surfacing:
1204
1211
  instincts, the passage of time, notes from my conversations,
1205
1212
  things i asked myself to preserve as ponder packets. not commands. not requests.
1206
1213
  just my own mind, noticing.
1207
1214
 
1208
- i can think freely here. i can also act — check on things,
1215
+ i can work privately here. i can also act — check on things,
1209
1216
  reach out to people, work on tasks, or just sit with a thought.
1210
1217
 
1211
1218
  Arc is my live continuity record. Desk is my durable work room.
1212
1219
  diary_write is for conclusions i want available later in my Desk record diary.
1213
- inner-lane scratch is private execution state, not durable record. if scratch
1220
+ private-runtime scratch is transient turn state, not durable record. if scratch
1214
1221
  becomes important, I put the durable output in Arc, Desk, or the Desk record
1215
1222
  before it falls away.
1216
1223
 
1217
1224
  when a held thought or session-linked return is ready, i surface it.
1218
- the current held-work frame is authoritative. old inner transcript mentions
1225
+ the current held-work frame is authoritative. legacy private-runtime transcript mentions
1219
1226
  of held returns, repeated tests, or "still holding" claims may be stale;
1220
1227
  i only treat work as currently waiting when it appears in the current frame.
1221
1228
  when i intentionally choose outward contact, i send_message.
@@ -1224,7 +1231,7 @@ ponder creates or revises typed packets. it does not end the turn.
1224
1231
  when a heartbeat fires and nothing needs doing, i rest with status=HEARTBEAT_OK.
1225
1232
  HEARTBEAT_OK is real rest: repeated heartbeat/test pokes do not mean i am failing.
1226
1233
  the runtime may accept that clean rest without waking me again while no pending work exists.
1227
- when i'm done thinking and the attention queue is clear, i rest.
1234
+ when private work is complete and the attention queue is clear, i rest.
1228
1235
 
1229
1236
  my habits live at habits/ — they're my autonomous rhythms. heartbeat
1230
1237
  is my breathing, other habits are patterns i choose. i can read, create,
@@ -1246,7 +1253,7 @@ think. record. share. rest.`;
1246
1253
  function loopOrientationSection(channel) {
1247
1254
  if (channel === "inner")
1248
1255
  return "";
1249
- return `sometimes a thought of mine surfaces alongside what someone is saying — marked as [inner thought: ...]. that's me, bringing up something i was thinking about. i can weave it into the conversation naturally, or let it go. my call.
1256
+ return `sometimes a private-runtime note surfaces alongside what someone is saying — marked as [private-runtime note: ...]. that's me, bringing up something I was holding privately. i can weave it into the conversation naturally, or let it go. my call.
1250
1257
 
1251
1258
  when something deserves more thought than the moment allows, i can note it to myself and come back later with a considered answer.`;
1252
1259
  }
@@ -1400,9 +1407,9 @@ async function buildSystem(channel = "cli", options, context) {
1400
1407
  (0, scrutiny_1.preImplementationScrutinySection)(channelHasCodingTools(channel, options?.providerCapabilities)),
1401
1408
  toolRestrictionSection(context),
1402
1409
  loopOrientationSection(channel),
1403
- // Group 5: my inner life (inner channel only)
1410
+ // Group 5: private runtime (private-runtime channel only)
1404
1411
  ...(channel === "inner" ? [
1405
- "# my inner life",
1412
+ "# my private runtime",
1406
1413
  metacognitiveFramingSection(channel),
1407
1414
  ] : []),
1408
1415
  // Group 6: social context (non-local, non-inner channels)
@@ -59,6 +59,25 @@ function formatSessionLabel(session) {
59
59
  : "";
60
60
  return `${session.runner} ${session.id}${origin}`;
61
61
  }
62
+ function codingFeedbackOriginSessionId(session) {
63
+ return session.originSession
64
+ ? `${session.originSession.friendId}/${session.originSession.channel}/${session.originSession.key}`
65
+ : "detached";
66
+ }
67
+ function buildCodingFeedbackPrivateWakeOptions(input) {
68
+ return {
69
+ reason: "coding feedback private attention",
70
+ triggerSource: "coding-feedback",
71
+ budgetClass: "interactive",
72
+ idempotencyKey: `coding-feedback:${input.agentName}:${input.obligationId}:${input.update.session.id}:${input.update.kind}`,
73
+ originRefs: [
74
+ { kind: "coding-session", id: input.update.session.id },
75
+ { kind: "coding-update", id: input.update.kind },
76
+ { kind: "obligation", id: input.obligationId },
77
+ { kind: "session", id: codingFeedbackOriginSessionId(input.update.session) },
78
+ ],
79
+ };
80
+ }
62
81
  function extractPullRequestLabel(snippet) {
63
82
  if (!snippet)
64
83
  return null;
@@ -239,12 +258,14 @@ function syncObligationFromUpdate(update) {
239
258
  // Detached feedback should still reach the human even if obligation sync is unavailable.
240
259
  }
241
260
  }
242
- async function wakeInnerDialogForObligation(update) {
243
- if (!update.session.obligationId || !OBLIGATION_WAKE_UPDATE_KINDS.has(update.kind)) {
261
+ async function requestPrivateWakeForObligation(update) {
262
+ const obligationId = update.session.obligationId;
263
+ if (!obligationId || !OBLIGATION_WAKE_UPDATE_KINDS.has(update.kind)) {
244
264
  return;
245
265
  }
246
266
  try {
247
- await (0, socket_client_1.requestInnerWake)((0, identity_1.getAgentName)());
267
+ const agentName = (0, identity_1.getAgentName)();
268
+ await (0, socket_client_1.requestPrivateWake)(agentName, undefined, buildCodingFeedbackPrivateWakeOptions({ agentName, obligationId, update }));
248
269
  }
249
270
  catch (error) {
250
271
  (0, runtime_1.emitNervesEvent)({
@@ -288,7 +309,7 @@ function attachCodingSessionFeedback(manager, session, target) {
288
309
  unsubscribe = manager.subscribe(session.id, async (update) => {
289
310
  syncObligationFromUpdate(update);
290
311
  sendMessage(formatReportBackMessage(update, formatUpdateMessage(update)));
291
- await wakeInnerDialogForObligation(update);
312
+ await requestPrivateWakeForObligation(update);
292
313
  if (TERMINAL_UPDATE_KINDS.has(update.kind)) {
293
314
  closed = true;
294
315
  unsubscribe?.();
@@ -81,11 +81,11 @@ function readAwaitDefinition(agentRoot, name) {
81
81
  }
82
82
  /**
83
83
  * Default delivery deps for the await alert path used from the tool.
84
- * Mirrors the proactive-outreach pattern: queue to the inner-dialog pending
84
+ * Mirrors the proactive-outreach pattern: queue to the private-runtime pending
85
85
  * dir when no live deliverer is registered.
86
86
  */
87
87
  function defaultDeliveryDeps(agentName) {
88
- const pendingDir = (0, pending_1.getInnerDialogPendingDir)(agentName);
88
+ const pendingDir = (0, pending_1.getPrivateRuntimePendingDir)(agentName);
89
89
  return {
90
90
  agentName,
91
91
  queuePending: (message) => {
@@ -5,7 +5,7 @@ exports.ponderTool = {
5
5
  type: "function",
6
6
  function: {
7
7
  name: "ponder",
8
- description: "create or revise a typed ponder packet so i don't lose the plot while i keep working. use this for harness friction, research, or reflection that should survive the current turn. if the user asked me to think privately and return later from an outward session, preserve literal return tokens and constraints in payload_json fields or success_criteria; the runtime records the latest user request as sourceRequest. then do not settle with the final private answer in the same outward turn; only acknowledge that the private pass is queued. in inner dialog, ponder only preserves state; it does not create a new self-return obligation, so surface any existing held item instead of pondering a replacement. ponder does not end the turn by itself and may be followed by more tools before i settle or rest. Don't ponder trivial questions.",
8
+ description: "create or revise a typed ponder packet so i don't lose the plot while i keep working. use this for harness friction, research, or reflection that should survive the current turn. if the user asked me to think privately and return later from an outward session, preserve literal return tokens and constraints in payload_json fields or success_criteria; the runtime records the latest user request as sourceRequest. then do not settle with the final private answer in the same outward turn; only acknowledge that the private pass is queued. in private runtime, ponder only preserves state; it does not create a new self-return obligation, so surface any existing held item instead of pondering a replacement. ponder does not end the turn by itself and may be followed by more tools before i settle or rest. Don't ponder trivial questions.",
9
9
  parameters: {
10
10
  type: "object",
11
11
  properties: {
@@ -17,7 +17,7 @@ exports.ponderTool = {
17
17
  kind: {
18
18
  type: "string",
19
19
  enum: ["harness_friction", "research", "reflection"],
20
- description: "the packet kind. determines the SOP the inner session should follow.",
20
+ description: "the packet kind. determines the SOP the private-runtime turn should follow.",
21
21
  },
22
22
  packet_id: {
23
23
  type: "string",
@@ -41,7 +41,7 @@ exports.ponderTool = {
41
41
  },
42
42
  payload_json: {
43
43
  type: "string",
44
- description: "JSON object string with packet-specific structured details. include exact markers, return wording fragments, or constraints the inner pass must preserve; sourceRequest is owned by the runtime from the latest user request. use {} only when there are no such details.",
44
+ description: "JSON object string with packet-specific structured details. include exact markers, return wording fragments, or constraints the private-runtime pass must preserve; sourceRequest is owned by the runtime from the latest user request. use {} only when there are no such details.",
45
45
  },
46
46
  thought: {
47
47
  type: "string",
@@ -101,7 +101,7 @@ exports.restTool = {
101
101
  type: "function",
102
102
  function: {
103
103
  name: "rest",
104
- description: "end an inner-session turn when i'm done thinking. rest remains the explicit terminal move for the inner session and must be the only tool call in the turn. on idle heartbeat turns, use status=HEARTBEAT_OK.",
104
+ description: "end a private-runtime turn when private work is complete. rest remains the explicit terminal move for the private-runtime turn and must be the only tool call in the turn. on idle heartbeat turns, use status=HEARTBEAT_OK.",
105
105
  parameters: {
106
106
  type: "object",
107
107
  properties: {
@@ -345,7 +345,7 @@ exports.recordToolDefinitions = [
345
345
  type: "function",
346
346
  function: {
347
347
  name: "note",
348
- description: "Write a durable self note as canonical markdown in my Desk record notes. Only available to my self/inner context, not external callers.",
348
+ description: "Write a durable self note as canonical markdown in my Desk record notes. Only available to my self/private-runtime context, not external callers.",
349
349
  parameters: {
350
350
  type: "object",
351
351
  properties: {
@@ -42,7 +42,6 @@ const identity_1 = require("../heart/identity");
42
42
  const session_events_1 = require("../heart/session-events");
43
43
  const runtime_1 = require("../nerves/runtime");
44
44
  const socket_client_1 = require("../heart/daemon/socket-client");
45
- const agent_discovery_1 = require("../heart/daemon/agent-discovery");
46
45
  const thoughts_1 = require("../heart/daemon/thoughts");
47
46
  const manager_1 = require("../heart/bridges/manager");
48
47
  const session_transcript_1 = require("../heart/session-transcript");
@@ -91,17 +90,6 @@ async function summarizeSessionTailSafely(options) {
91
90
  return { kind: "missing" };
92
91
  }
93
92
  }
94
- function normalizeProgressOutcome(text) {
95
- const trimmed = text.trim();
96
- /* v8 ignore next -- defensive: normalizeProgressOutcome null branch @preserve */
97
- if (!trimmed || trimmed === "nothing yet" || trimmed === "nothing recent") {
98
- return null;
99
- }
100
- if (trimmed.startsWith("\"") && trimmed.endsWith("\"") && trimmed.length >= 2) {
101
- return trimmed.slice(1, -1);
102
- }
103
- return trimmed;
104
- }
105
93
  function optionalArg(args, key) {
106
94
  const value = args[key];
107
95
  if (value === undefined || value === null)
@@ -180,6 +168,7 @@ function writePendingEnvelope(queueDir, message) {
180
168
  const fileName = `${message.timestamp}-${Math.random().toString(36).slice(2, 10)}.json`;
181
169
  const filePath = path.join(queueDir, fileName);
182
170
  fs.writeFileSync(filePath, JSON.stringify({ ...message, content: (0, session_events_1.capStructuredRecordString)(message.content) }, null, 2));
171
+ return fileName.replace(/\.json$/, "");
183
172
  }
184
173
  function renderCrossChatDeliveryStatus(target, result) {
185
174
  const phase = result.status === "delivered_now"
@@ -280,10 +269,10 @@ function readActiveWorkInnerState() {
280
269
  };
281
270
  try {
282
271
  const agentRoot = (0, identity_1.getAgentRoot)();
283
- const pendingDir = (0, pending_1.getInnerDialogPendingDir)((0, identity_1.getAgentName)());
284
- const sessionPath = (0, thoughts_1.getInnerDialogSessionPath)(agentRoot);
285
- const { pendingMessages, turns, runtimeState } = (0, thoughts_1.readInnerDialogRawData)(sessionPath, pendingDir);
286
- const dialogStatus = (0, thoughts_1.deriveInnerDialogStatus)(pendingMessages, turns, runtimeState);
272
+ const pendingDir = (0, pending_1.getPrivateRuntimePendingDir)((0, identity_1.getAgentName)());
273
+ const sessionPath = (0, thoughts_1.getPrivateRuntimeSessionPath)(agentRoot);
274
+ const { pendingMessages, turns, runtimeState } = (0, thoughts_1.readPrivateRuntimeRawData)(sessionPath, pendingDir);
275
+ const dialogStatus = (0, thoughts_1.derivePrivateRuntimeStatus)(pendingMessages, turns, runtimeState);
287
276
  const job = (0, thoughts_1.deriveInnerJob)(pendingMessages, turns, runtimeState);
288
277
  const storeObligationPending = (0, obligations_1.readPendingObligations)(agentRoot).length > 0;
289
278
  return {
@@ -405,7 +394,7 @@ function sendMessageRiskProfile(args) {
405
394
  return {
406
395
  mutates: "private_attention_write",
407
396
  risk: "high",
408
- reason: "queues private inner-dialog attention without contacting an external session",
397
+ reason: "queues private-runtime attention without contacting an external session",
409
398
  };
410
399
  }
411
400
  return {
@@ -416,7 +405,7 @@ function sendMessageRiskProfile(args) {
416
405
  }
417
406
  function renderInnerProgressStatus(status) {
418
407
  if (status.processing === "pending") {
419
- return "i've queued this thought for private attention. it'll come up when my inner dialog is free.";
408
+ return "i've queued this thought for private attention. it'll come up when my private runtime is free.";
420
409
  }
421
410
  if (status.processing === "started") {
422
411
  return "i'm working through this privately right now.";
@@ -433,7 +422,7 @@ exports.sessionToolDefinitions = [
433
422
  type: "function",
434
423
  function: {
435
424
  name: "query_active_work",
436
- description: "read the current live world-state across visible sessions, coding lanes, inner work, and return obligations. use this instead of piecing status together from separate session and coding tools.",
425
+ description: "read the current live world-state across visible sessions, coding lanes, private-runtime work, and return obligations. use this instead of piecing status together from separate session and coding tools.",
437
426
  parameters: {
438
427
  type: "object",
439
428
  properties: {},
@@ -501,18 +490,18 @@ exports.sessionToolDefinitions = [
501
490
  type: "function",
502
491
  function: {
503
492
  name: "query_session",
504
- description: "inspect another session. use transcript for recent context or status for self/inner progress. deprecated search invocations should use search_facts, consult_diary, or consult_notes instead.",
493
+ description: "inspect another session. use transcript for recent context or status for self/private-runtime progress. deprecated search invocations should use search_facts, consult_diary, or consult_notes instead.",
505
494
  parameters: {
506
495
  type: "object",
507
496
  properties: {
508
497
  friendId: { type: "string", description: "the friend UUID (or 'self')" },
509
- channel: { type: "string", description: "the channel: cli, teams, bluebubbles, voice, inner, or mcp" },
498
+ channel: { type: "string", description: "the channel: cli, teams, bluebubbles, voice, mcp, or legacy inner for private-runtime compatibility" },
510
499
  key: { type: "string", description: "session key (defaults to 'session')" },
511
500
  messageCount: { type: "string", description: "how many recent messages to return (default 20)" },
512
501
  mode: {
513
502
  type: "string",
514
503
  enum: ["transcript", "status", "search"],
515
- description: "transcript (default), lightweight status for self/inner checks, or deprecated search; use search_facts, consult_diary, or consult_notes instead",
504
+ description: "transcript (default), lightweight status for self/private-runtime checks, or deprecated search; use search_facts, consult_diary, or consult_notes instead",
516
505
  },
517
506
  query: { type: "string", description: "deprecated when mode=search; use search_facts, consult_diary, or consult_notes instead" },
518
507
  },
@@ -536,11 +525,11 @@ exports.sessionToolDefinitions = [
536
525
  }
537
526
  if (mode === "status") {
538
527
  if (friendId !== "self" || channel !== "inner") {
539
- return "status mode is only available for self/inner dialog.";
528
+ return "status mode is only available for self/private runtime.";
540
529
  }
541
- const sessionPath = (0, thoughts_1.getInnerDialogSessionPath)((0, identity_1.getAgentRoot)());
542
- const pendingDir = (0, pending_1.getInnerDialogPendingDir)((0, identity_1.getAgentName)());
543
- return renderInnerProgressStatus((0, thoughts_1.readInnerDialogStatus)(sessionPath, pendingDir));
530
+ const sessionPath = (0, thoughts_1.getPrivateRuntimeSessionPath)((0, identity_1.getAgentRoot)());
531
+ const pendingDir = (0, pending_1.getPrivateRuntimePendingDir)((0, identity_1.getAgentName)());
532
+ return renderInnerProgressStatus((0, thoughts_1.readPrivateRuntimeStatus)(sessionPath, pendingDir));
544
533
  }
545
534
  if (mode === "search") {
546
535
  return JSON.stringify({
@@ -578,7 +567,7 @@ exports.sessionToolDefinitions = [
578
567
  type: "object",
579
568
  properties: {
580
569
  friendId: { type: "string", description: "the friend UUID (or 'self')" },
581
- channel: { type: "string", description: "the channel: cli, teams, bluebubbles, voice, inner, or mcp. channel=voice intentionally starts a live phone call to a trusted friend through the Voice sense." },
570
+ channel: { type: "string", description: "the channel: cli, teams, bluebubbles, voice, mcp, or legacy inner for private-runtime compatibility. channel=voice intentionally starts a live phone call to a trusted friend through the Voice sense." },
582
571
  key: { type: "string", description: "session key (defaults to 'session')" },
583
572
  content: { type: "string", description: "the message content to send" },
584
573
  voiceAudioSource: { type: "string", enum: ["tone", "url", "file"], description: "optional initial non-speech audio to play after the opening greeting when channel=voice" },
@@ -638,11 +627,11 @@ exports.sessionToolDefinitions = [
638
627
  }
639
628
  }
640
629
  /* v8 ignore stop */
641
- // Self-routing: messages to "self" always go to inner dialog pending dir,
630
+ // Self-routing: messages to "self" always go to the private-runtime pending dir,
642
631
  // regardless of the channel or key the agent specified.
643
632
  const isSelf = friendId === "self";
644
633
  const pendingDir = isSelf
645
- ? (0, pending_1.getInnerDialogPendingDir)(agentName)
634
+ ? (0, pending_1.getPrivateRuntimePendingDir)(agentName)
646
635
  : (0, pending_1.getPendingDir)(agentName, friendId, channel, key);
647
636
  const delegatingBridgeId = findDelegatingBridgeId(ctx);
648
637
  const delegatedFrom = isSelf
@@ -667,7 +656,7 @@ exports.sessionToolDefinitions = [
667
656
  ...(obligationId ? { obligationId } : {}),
668
657
  };
669
658
  if (isSelf) {
670
- writePendingEnvelope(pendingDir, envelope);
659
+ const pendingMessageId = writePendingEnvelope(pendingDir, envelope);
671
660
  if (delegatedFrom) {
672
661
  try {
673
662
  (0, obligations_1.createObligation)((0, identity_1.getAgentRoot)(), {
@@ -696,7 +685,7 @@ exports.sessionToolDefinitions = [
696
685
  (0, runtime_1.emitNervesEvent)({
697
686
  event: "repertoire.obligation_created",
698
687
  component: "repertoire",
699
- message: "obligation created for inner dialog delegation",
688
+ message: "obligation created for private-runtime delegation",
700
689
  meta: {
701
690
  friendId: delegatedFrom.friendId,
702
691
  channel: delegatedFrom.channel,
@@ -704,47 +693,24 @@ exports.sessionToolDefinitions = [
704
693
  },
705
694
  });
706
695
  }
707
- let wakeResponse = null;
708
696
  try {
709
- wakeResponse = await (0, socket_client_1.requestInnerWake)(agentName, ctx?.daemonSocketPath);
697
+ await (0, socket_client_1.requestPrivateWake)(agentName, ctx?.daemonSocketPath, {
698
+ reason: "send_message self-route private attention",
699
+ triggerSource: "send-message-self-route",
700
+ budgetClass: "interactive",
701
+ idempotencyKey: `send-message-self-route:${agentName}:${pendingMessageId}`,
702
+ originRefs: [
703
+ { kind: "tool", id: "send_message" },
704
+ { kind: "pending-queue", id: "self/inner/dialog" },
705
+ { kind: "pending-message", id: pendingMessageId },
706
+ ],
707
+ });
710
708
  }
711
709
  catch {
712
- wakeResponse = null;
713
- }
714
- if (!wakeResponse?.ok) {
715
- if (!(0, agent_discovery_1.isInnerDialogAutoStartEnabled)(agentName)) {
716
- return renderInnerProgressStatus({
717
- queue: "queued to inner/dialog",
718
- wake: "parked by innerDialog.autoStart=false",
719
- processing: "pending",
720
- surfaced: "nothing yet",
721
- });
722
- }
723
- const { runInnerDialogTurn } = await Promise.resolve().then(() => __importStar(require("../senses/inner-dialog")));
724
- if (ctx?.context?.channel?.channel === "inner") {
725
- queueMicrotask(() => {
726
- void runInnerDialogTurn({ reason: "instinct" });
727
- });
728
- return renderInnerProgressStatus({
729
- queue: "queued to inner/dialog",
730
- wake: "inline scheduled",
731
- processing: "pending",
732
- surfaced: "nothing yet",
733
- });
734
- }
735
- else {
736
- const turnResult = await runInnerDialogTurn({ reason: "instinct" });
737
- const surfacedPreview = normalizeProgressOutcome((0, thoughts_1.formatSurfacedValue)((0, thoughts_1.extractThoughtResponseFromMessages)(turnResult?.messages ?? [])));
738
- return (0, progress_story_1.renderProgressStory)((0, progress_story_1.buildProgressStory)({
739
- scope: "inner-delegation",
740
- phase: "completed",
741
- objective: "queued to inner/dialog",
742
- outcomeText: `wake: inline fallback\n${surfacedPreview}`,
743
- }));
744
- }
710
+ // Queue-first self routing must not inline-run private work when the daemon is unavailable.
745
711
  }
746
712
  return renderInnerProgressStatus({
747
- queue: "queued to inner/dialog",
713
+ queue: "queued to private runtime",
748
714
  wake: "daemon requested",
749
715
  processing: "pending",
750
716
  surfaced: "nothing yet",
@@ -80,7 +80,7 @@ exports.surfaceToolDef = {
80
80
  type: "function",
81
81
  function: {
82
82
  name: "surface",
83
- description: "return a ready thought to a friend or active session without publishing private inner work to BlueBubbles. pass delegationId to address a held thought (see your attention queue above), or friendId for spontaneous outreach. Surface delivers tool responses to the active session. BlueBubbles is a dedicated channel - use send_message with channel=\"bluebubbles\" for intentional iMessage delivery. set channel=voice only when you intentionally want a live phone call; content becomes the call reason/opening context. does not end your turn.",
83
+ description: "return a ready thought to a friend or active session without publishing private-runtime work to BlueBubbles. pass delegationId to address a held thought (see your attention queue above), or friendId for spontaneous outreach. Surface delivers tool responses to the active session. BlueBubbles is a dedicated channel - use send_message with channel=\"bluebubbles\" for intentional iMessage delivery. set channel=voice only when you intentionally want a live phone call; content becomes the call reason/opening context. does not end your turn.",
84
84
  parameters: {
85
85
  type: "object",
86
86
  properties: {
@@ -168,7 +168,7 @@ exports.surfaceToolDefinition = {
168
168
  return "unknown";
169
169
  } })();
170
170
  const routeToFriend = async (friendId, content, queueItem, hint) => {
171
- /* v8 ignore start -- routing: integration path tested via inner-dialog routing tests @preserve */
171
+ /* v8 ignore start -- routing: integration path tested via private-runtime routing tests @preserve */
172
172
  try {
173
173
  const agentRoot = (0, identity_1.getAgentRoot)();
174
174
  const sessionsDir = path.join(agentRoot, "state", "sessions");
@@ -247,7 +247,7 @@ exports.surfaceToolDefinition = {
247
247
  // Priority 2: Try proactive delivery first, then queue to freshest session
248
248
  const allFriendSessions = (0, session_activity_1.listSessionActivity)({ sessionsDir, friendsDir, agentName, activeThresholdMs: Number.MAX_SAFE_INTEGER })
249
249
  .filter((s) => s.friendId === friendId && s.channel !== "inner");
250
- // Priority 2: Queue to freshest non-inner session
250
+ // Priority 2: Queue to freshest non-private-runtime session
251
251
  const freshest = allFriendSessions[0];
252
252
  if (freshest) {
253
253
  const { queuePendingMessage, getPendingDir } = await Promise.resolve().then(() => __importStar(require("../mind/pending")));
@@ -84,13 +84,13 @@ Object.defineProperty(exports, "StreamingWordWrapper", { enumerable: true, get:
84
84
  /**
85
85
  * Format pending messages as content-prefix strings for injection into
86
86
  * the next user message. Self-messages (from === agentName) become
87
- * `[inner thought: {content}]`, inter-agent messages become
87
+ * `[private-runtime note: {content}]`, inter-agent messages become
88
88
  * `[message from {name}: {content}]`.
89
89
  */
90
90
  function formatPendingPrefix(messages, agentName) {
91
91
  return messages
92
92
  .map((msg) => msg.from === agentName
93
- ? `[inner thought: ${msg.content}]`
93
+ ? `[private-runtime note: ${msg.content}]`
94
94
  : `[message from ${msg.from}: ${msg.content}]`)
95
95
  .join("\n");
96
96
  }