@paigy/mcp 0.40.39 → 0.40.41

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.
@@ -7,7 +7,7 @@ import { homedir } from "os";
7
7
  import { join } from "path";
8
8
  import { randomUUID as randomUUID2 } from "crypto";
9
9
  import { setTimeout as sleep2 } from "timers/promises";
10
- import { z as z11 } from "zod";
10
+ import { z as z12 } from "zod";
11
11
  import { z } from "zod";
12
12
  import { z as z3 } from "zod";
13
13
  import { z as z2 } from "zod";
@@ -21,6 +21,7 @@ import { z as z7 } from "zod";
21
21
  import { z as z8 } from "zod";
22
22
  import { z as z9 } from "zod";
23
23
  import { z as z10 } from "zod";
24
+ import { z as z11 } from "zod";
24
25
  import { closeSync, existsSync, mkdirSync, openSync, readFileSync as readFileSync2, rmSync, statSync, writeFileSync } from "fs";
25
26
  import { homedir as homedir2 } from "os";
26
27
  import { join as join2 } from "path";
@@ -1516,16 +1517,16 @@ function parseWhen(said2, tz, nowMs, read22 = "earliest") {
1516
1517
  let hour = null;
1517
1518
  let minute = 0;
1518
1519
  const spoken = new RegExp(`\\bat\\s+(${Object.keys(SPOKEN_HOUR).join("|")})\\b`, "i").exec(text);
1519
- const clock2 = CLOCK.exec(text);
1520
+ const clock22 = CLOCK.exec(text);
1520
1521
  if (spoken) {
1521
1522
  hour = SPOKEN_HOUR[spoken[1].toLowerCase()];
1522
- } else if (clock2 && (clock2[3] || /\bat\s/i.test(clock2[0]))) {
1523
- hour = Number(clock2[1]);
1524
- minute = clock2[2] ? Number(clock2[2]) : 0;
1523
+ } else if (clock22 && (clock22[3] || /\bat\s/i.test(clock22[0]))) {
1524
+ hour = Number(clock22[1]);
1525
+ minute = clock22[2] ? Number(clock22[2]) : 0;
1525
1526
  if (hour > 23 || minute > 59) return null;
1526
1527
  }
1527
1528
  if (hour !== null) {
1528
- const mer = clock2?.[3]?.toLowerCase().replace(/\./g, "") ?? "";
1529
+ const mer = clock22?.[3]?.toLowerCase().replace(/\./g, "") ?? "";
1529
1530
  const pmWord = /\b(p\.?m\.?|afternoon|evening|tonight|at night)\b/i.test(text);
1530
1531
  const amWord = /\b(a\.?m\.?|morning)\b/i.test(text);
1531
1532
  if (mer.startsWith("p") || pmWord && !amWord) {
@@ -1569,7 +1570,7 @@ function parseDelay(said2, tz, nowMs, read22 = "earliest") {
1569
1570
  return Math.max(0, Math.round((Date.parse(at2) - nowMs) / 1e3));
1570
1571
  }
1571
1572
  var NIGHT = { from: 23, to: 7 };
1572
- var ASK_MAX = 250;
1573
+ var ASK_MAX = 80;
1573
1574
  var UNITS_MAX = 12;
1574
1575
  var UNIT_TITLE_MAX = 50;
1575
1576
  var UNIT_BODY_MAX = 200;
@@ -1634,15 +1635,15 @@ var CompletionSchema = z3.object({
1634
1635
  }).strict();
1635
1636
  var CompleteChangeSchema = CompletionSchema.extend({ kind: z3.literal("complete") });
1636
1637
  var ASKING_RULES = `HOW TO ASK:
1637
- 1. Write one question per object. Five questions are five objects in \`questions\`, in one contact, so each can be answered on its own; one question with five parts settles nothing until all five are answered.
1638
- 2. Name the Goal you are working on as the question's \`goalId\`: the question goes onto that Goal and its answer comes back there. It must exist: create it with manage_goals first.
1639
- 3. \`workItBlocks\` only for work you are truly blocked on (it asks for a call); leave it out for a question you can keep working around.
1640
- 4. Never hold the process open with while-loops. A wait that comes back \`expired\` is not a finished conversation: wait again with contact({wait:true}) only while you have nothing else to do. While a Call you placed is open, keep receiving window after window until it ends, even when a window is empty: the person may give follow-ups or instructions. With no open Call, STOP WAITING when a window comes back with nothing new \u2014 the question stays open, and its answer reaches you on the Goal. Otherwise, yield only with a working listener or scheduled wakeup, and collect answers with \`contact({wait:false})\` or \`get_goals\` on that wake.
1641
- 5. One question, one row. Never restate a question that is still waiting inside a new contact: keep waiting on the original, or the answer lands on one copy and the other stays open. Take back one that no longer matters with \`withdrawQuestionIds\`.
1642
- 6. Read the Goal's conversation before asking. Never ask again what was answered or already shipped \u2014 and tell its states apart: \`answered\` carries the choice in \`answer\`, while \`replied\` means they said something and chose none of your options, so that question is still yours to settle and their words are the line beside it.
1643
- 7. A question carries its options when you have them; a free-text question may omit them. Each option\u2019s label must stand on its own and name its choice in full -- never \`All three\` or \`Option 2\`. \`pickMode: "many"\` makes the card a checklist (options they may want several of); \`"one"\`, the default, a pick (one rules out the others); \`"rank"\` an ordering. Each question is sent exactly as written, with no reading in between. They can always answer in their own words, so never add an 'Other' option.
1644
- 8. A diagnosis says when, why and how it happens, then proposes one fix. Never options first.
1645
- 9. GIVE A REPORT ITS REPLY: an update takes \`reply\` too, one line the person can tap instead of typing, written in THEIR voice for THAT report ("Sounds good, I'll test later") \u2014 the same care you give a question's options. What they tap is what you read back, which tells you whether they verified your work or only received it. One line, because a report has one way to close, and it may not change what happens next: a reply that would is a question. Requested delivery and completed-Goal reports require a reply (reply_required); ordinary progress may omit it.`;
1638
+ 1. One question per object in \`questions\`, so each is answered on its own.
1639
+ 2. \`goalId\` names the existing Goal it is about (create one with manage_goals first); the answer comes back there.
1640
+ 3. \`workItBlocks\` only when you are truly blocked: it asks for a call.
1641
+ 4. No while-loops. While any Call is open, even one your question joined from their items, keep receiving through empty windows; otherwise stop at one: the answer reaches you on the Goal. Yield only with a listener or wakeup.
1642
+ 5. One question, one row: never re-send one still waiting; take back one that no longer matters with \`withdrawQuestionIds\`.
1643
+ 6. Read the Goal before asking; never re-ask what was answered or shipped. \`replied\` means they chose no option: it is still yours to settle.
1644
+ 7. Give options when you have them. Each label names its choice in full (never "Option 2"); never add "Other". \`pickMode\`: one (default), many, rank.
1645
+ 8. A diagnosis says when, why and how it happens, then proposes one fix.
1646
+ 9. Give a report its \`reply\`: one line in THEIR voice for THAT report, so you learn whether they verified it or only received it. Required when it reaches them or completes a Goal.`;
1646
1647
  function draft2020(node) {
1647
1648
  if (Array.isArray(node)) return node.map(draft2020);
1648
1649
  if (node && typeof node === "object") {
@@ -1685,7 +1686,7 @@ var userExplicitlyRequested = z4.enum(["any", "call"]).optional().describe(
1685
1686
  `Only what the person said about THIS message, in so many words: "any" when they asked you to send it to them ("send it to my phone", "message me the result"), "call" when they asked to be called about it. It is then delivered (a call rings for the whole contact, and carries everything waiting on them); omitted, an update is only recorded as the Goal's progress unless the person needs it. Never set it to make a message louder.`
1686
1687
  );
1687
1688
  var units = z4.array(UnitInputSchema).optional().describe(
1688
- `The context this message needs, as up to ${UNITS_MAX} units in reading order, each {title, body}: a title of at most ${UNIT_TITLE_MAX} characters and a body of at most ${UNIT_BODY_MAX}. One idea per unit. Leave it out when the main text says it all.`
1689
+ `The context this message needs, as up to ${UNITS_MAX} units in reading order, each {title, body}: a title of at most ${UNIT_TITLE_MAX} characters and a body of at most ${UNIT_BODY_MAX}. One idea per unit. Leave it out when the main text says it all. Over a cap is refused by name (ask_too_long, too_many_units, unit_title_too_long, unit_body_too_long) and nothing is sent.`
1689
1690
  );
1690
1691
  var UpdateInputSchema = z4.object({
1691
1692
  message: z4.string().trim().min(1).describe(`The one point, at most ${ASK_MAX} characters; the context goes in units.`),
@@ -1740,7 +1741,7 @@ var questionFields = {
1740
1741
  ),
1741
1742
  goalId: z4.string().uuid().describe("The Goal the question is about, which must exist (create it with manage_goals first). Its answer comes back there."),
1742
1743
  units,
1743
- options: z4.array(OptionInputSchema).min(1).max(6).optional().describe("The choices, when you have them. Each label stands on its own, at most 50 characters; a hint, at most 200."),
1744
+ options: z4.array(OptionInputSchema).min(1).max(6).optional().describe("The choices, when you have them. Each label stands on its own, at most 50 characters; a hint, at most 200. They can always answer in their own words, so no 'Other' or 'None of these'."),
1744
1745
  // HOW THE OPTIONS ARE ANSWERED, SAID BY THE AGENT (owner, 2026-10-02: "one and many makes sense";
1745
1746
  // brain_prompts.md §1: structured agent questions need no model). The app draws all three.
1746
1747
  pickMode: z4.enum(["one", "many", "rank"]).optional().describe(
@@ -1782,9 +1783,11 @@ var QuestionDependencySchema = z4.object({
1782
1783
  reason: reason.optional()
1783
1784
  }).strict().refine(actionFits, ACTION_FITS);
1784
1785
  var sendFields = {
1785
- completions: z4.array(CompletionSchema).min(1).max(20).optional().describe("Close existing Goals and deliver their completion reports atomically. Ordinary updates never close work."),
1786
+ completions: z4.array(CompletionSchema).min(1).max(20).optional().describe(
1787
+ "COMPLETIONS close and report in one operation, the same contract as manage_goals kind:complete: closure and the report commit together or neither does. Required children and dependencies must already be finished. options suggest next steps: a tap acknowledges the report and requests that step, and never reopens the Goal (follow-up work needs a new one). No reviewer rejudges it: say only what your evidence supports. Ordinary updates never close a Goal."
1788
+ ),
1786
1789
  updates: z4.array(UpdateInputSchema).min(1).max(20).optional().describe(
1787
- "News: progress, findings, a result. An update asks nothing. It reaches the person only when they asked for it (userExplicitlyRequested), when it answers something they said, or once its Goal is done; otherwise it is recorded as the Goal's progress and nobody is notified."
1790
+ "News: progress, findings, a result. An update asks nothing. It reaches the person only when they asked for it (userExplicitlyRequested), when it answers something they said, or once its Goal is done; otherwise it is recorded as the Goal's progress, which the person is not told. Every update reaches the other agents that wrote on its Goal in the last hour: to tell another agent something, write it as an update on that agent's Goal."
1788
1791
  ),
1789
1792
  answers: z4.array(AnswerInputSchema).min(1).max(20).optional().describe("Answers to Questions addressed to you."),
1790
1793
  withdrawQuestionIds: z4.array(questionHandle).min(1).max(10).optional().describe(
@@ -1796,7 +1799,7 @@ var sendFields = {
1796
1799
  };
1797
1800
  var ContactSchema = z4.object({
1798
1801
  ...sendFields,
1799
- questions: z4.array(QuestionInputSchema).min(1).max(20).optional().describe("Questions for the person, one per object."),
1802
+ questions: z4.array(QuestionInputSchema).min(1).max(20).optional().describe("Questions for the person, one per object, each sent exactly as written, with no reading in between."),
1800
1803
  /** RECEIVING (2I, I2; brain_prompts.md §2.2): the events this agent handled. */
1801
1804
  ackEventIds: z4.array(z4.string().uuid()).min(1).max(100).optional().describe(
1802
1805
  "The exact eventIds of the events you have handled: an acknowledgment (ACK). Reading alone acknowledges nothing, so an event comes back until you acknowledge it; after that the next batch can come. Each recipient acknowledges separately, for itself only. A Question you owe is answered (answers), never acknowledged away."
@@ -1812,15 +1815,13 @@ var ContactWireSchema = z4.object({
1812
1815
  questions: z4.array(QuestionWireSchema).min(1).max(20).optional()
1813
1816
  }).strict().refine(sendsAnything, "a contact sends at least one update, question, answer, withdrawal or question dependency");
1814
1817
  var CONTACT_SCHEMA = { type: "object", ...mcpInputSchema(ContactSchema) };
1815
- var CONTACT_DESCRIPTION = "Send to and receive from the person: completions, updates, questions, answers to questions addressed to you, withdrawals of your own questions, and what a question holds up. Every Goal you name must already exist: create it with manage_goals first; an unknown Goal is refused and nothing is sent. Every item applies on its own: read `results`, where a failed item names why while the rest still apply.\n\n" + ASKING_RULES + `
1818
+ var CONTACT_DESCRIPTION = "Send to and receive from the person: completions, updates, questions, answers to questions addressed to you, withdrawals, and what a question holds up. Every Goal named must exist: an unknown one refuses the whole contact. Each item applies on its own: read `results`, where a failed one names why.\n\n" + ASKING_RULES + `
1816
1819
 
1817
- CUT A LONG MESSAGE BEFORE YOU SEND IT: a question, an update's message or an answer is the one point, in at most ${ASK_MAX} characters; everything else it needs goes in 'units', up to ${UNITS_MAX} {title, body} in reading order, one idea each, every title at most ${UNIT_TITLE_MAX} characters and every body at most ${UNIT_BODY_MAX}. The person sees the main text and the titles, and opens a unit to read its body. Over a cap is refused by name (ask_too_long, too_many_units, unit_title_too_long, unit_body_too_long) and nothing is sent.
1820
+ LENGTH: the question, message or answer is the one point, at most ${ASK_MAX} characters; the rest goes in \`units\`, one idea each. Over a cap is refused by name and nothing is sent. Several results are several updates.
1818
1821
 
1819
- UPDATES ask nothing, so no answer is owed and none should be awaited. An update reaches the person only when they asked you for it (userExplicitlyRequested), when it answers something they said, or once its Goal is done; any other is recorded as the Goal's progress and nobody is notified. Ordinary updates never close a Goal. On a Goal whose report card is still open, an update that reaches them is added to that card, with no new push. If the person is already on a call, anything that reaches them joins that call, with no ring.
1822
+ UPDATES ask nothing. One reaches the person only when they asked for it, it answers something they said, or its Goal is done; else it is kept as progress. One that reaches them joins an open report card or a live call.
1820
1823
 
1821
- COMPLETIONS close and report in one operation: completions:[{goalId,message,units?,reply,options?}]. The same contract works in manage_goals changes with kind:complete. message is at most 50 characters; use units when useful for initial state, changes, current state (verification and limits), and next steps / leftover work with its owner. reply is one acknowledgement in the person's voice. Optional options:[{label,hint}] suggest next steps: a tap acknowledges the report and requests that step from its author. It never reopens the completed Goal; follow-up work needs a new Goal. Closure and the report commit together or neither does. Required children and dependencies must already be finished. No Reviewer rejudges your completion; say only what your evidence supports.
1822
-
1823
- RECEIVING: a contact that sends nothing returns \`events\`, a limited batch of what is addressed to you (not a history page): \`question\`, a Question you owe (answer it in answers, with its questionId); \`update\`, something new on one of your Goals (a reply, an answer: read it with get_goals); \`instruction\`, a request or note sent to you. \`hasMore\` says more are waiting. Reading acknowledges nothing: once you have handled events, confirm their eventIds with contact({ackEventIds}), and the next batch can come. contact({}) waits up to about 45 seconds for something to arrive; contact({wait:false}) returns at once. It also lists work given to you that nobody has started (\`assigned\`; your first write to it starts it) and your work gone quiet (\`stalled\`).`;
1824
+ RECEIVING: contact({}) waits ~45 s; contact({wait:false}) returns \`events\` at once. Confirm the ones you handled with contact({ackEventIds}).`;
1824
1825
  var CreateGoalSchema = z5.object({
1825
1826
  outcome: z5.string().trim().min(1).max(1e4),
1826
1827
  /** The work's NAME (#2115) — one to five words, how a person refers to it out loud ("the night
@@ -1921,9 +1922,12 @@ var GetGoalsSchema = z5.object({
1921
1922
  history: z5.boolean().optional()
1922
1923
  }).strict();
1923
1924
  var GetDeliverySchema = z5.object({
1924
- deliveryId: z5.string().uuid().describe("The Delivery id returned by contact or receive.")
1925
+ deliveryId: z5.string().uuid().describe("The Delivery id returned by contact or receive."),
1926
+ // WHAT WAS SAID ON A CALL (owner, 2026-10-26, Goal c743f4a4: "A flag on get_delivery", "Any of my agents").
1927
+ transcript: z5.boolean().optional().describe("For a Call: also return what was said on it, one page of spoken lines."),
1928
+ after: z5.string().max(40).optional().describe("With transcript: the next value the previous page returned, to read the next page.")
1925
1929
  }).strict();
1926
- var GET_DELIVERY_DESCRIPTION = "Read a Delivery in full: its whole ask, units, options and answers, plus current callState and callOutcome for a Call. Any agent of the same account may read it; another account is not disclosed. Reading never acknowledges or resends anything. Use this after a call or when receive names a Call you are waiting on.";
1930
+ var GET_DELIVERY_DESCRIPTION = "Read a Delivery in full: its whole ask, units, options and answers, plus current callState and callOutcome for a Call. For a Call, transcript: true adds what was said: each spoken line in order, who said it, and when from pickup, a page at a time. A line from the room, not the person, is marked room. Any agent of the same account may read it; another account is not disclosed. Reading never acknowledges or resends anything. Use this after a call or when receive names a Call you are waiting on.";
1927
1931
  var GET_GOALS_DESCRIPTION = "Read one to ten Goals by goalIds, returned in the same order under goals (a read never puts you on them). history applies to every requested Goal. A refused read fails the call with its original refusal; no partial result is presented as complete. Each Goal includes its ten most recent other contributors (names, latest entry headlines and times), outcome, state, revision, progress, blockers, the conversation on it (each question with its options and what was decided), `next`, the one step to take, and `more`, where to read further. A question in that conversation reads `open` (nothing yet), `answered` (a choice was made, and `answer` carries it), `replied` (they said something and the read settled the question on their words \u2014 NO option of yours was chosen, and the words are the reply line beside it, so read that before you act), or `closed`. The conversation carries everything the person said, every open question and your newest entry; your older entries are left out and counted \u2014 history: true reads every entry in full. Every Goal of your person is readable, whichever of their agents owns it; another account's Goals are not disclosed.";
1928
1932
  var SearchToolSchema = z5.object({
1929
1933
  query: z5.string().trim().min(1).max(500),
@@ -2038,11 +2042,22 @@ var BrainMessageSchema = z6.union([
2038
2042
  // A MESSAGE TO THE PERSON KEEPS ITS SENTENCES (turns.md): the talker writes them one by one, and each is
2039
2043
  // its own unit of speech (`<cycle>:<key>:<n>`). `text` is the same words joined, for every reader of a
2040
2044
  // message's words. Absent on results written before sentences.
2041
- z6.object({ ...messageBase, to: z6.object({ kind: z6.literal("user") }).strict(), sentences: z6.array(z6.string().min(1)).min(1).optional() }).strict(),
2045
+ z6.object({
2046
+ ...messageBase,
2047
+ to: z6.object({ kind: z6.literal("user") }).strict(),
2048
+ sentences: z6.array(z6.string().min(1)).min(1).optional(),
2049
+ // THE REPORTS IT TELLS, BY THEIR OWN IDENTITY (call 9d1c096c, 2026-10-15): the talker's message names the report
2050
+ // Entries it speaks of, so the plan's line names that report rather than re-finding it by its Goal. Absent on
2051
+ // results written before it.
2052
+ tells: z6.array(z6.object({ id }).strict()).optional()
2053
+ }).strict(),
2042
2054
  z6.object({
2043
2055
  ...messageBase,
2044
2056
  to: z6.object({ kind: z6.literal("agent"), agentId: z6.string().regex(/^agent:(?!paigy$)\S+$/) }).strict(),
2045
2057
  call: z6.object({ callId: id, listen: z6.literal(true) }).strict().optional(),
2058
+ // WHAT IT ASKS THE AGENT, IN UNDER TEN WORDS (owner, 2026-10-15: "Yes, add the summary"): the talker's own, stored
2059
+ // as the sent Entry's summary, which the recap's "Sent to <agent>: …" row shows. Absent on results written before it.
2060
+ summary: z6.string().optional(),
2046
2061
  // THE PERSON ASKED TO BE CALLED BACK ONCE THIS AGENT'S WORK IS DONE (turns.md, step 0): the agent owes
2047
2062
  // the call, and its next contact about it rings them (`public.callbacks`).
2048
2063
  callback: z6.literal(true).optional()
@@ -2069,95 +2084,98 @@ var BrainResultSchema = z6.object({
2069
2084
  next: BrainNextSchema,
2070
2085
  search: BrainSearchSchema.optional()
2071
2086
  }).strict();
2072
- var str = z6.string();
2087
+ var str2 = z6.string();
2073
2088
  var strs = z6.array(z6.string());
2074
2089
  var CompactResultSchema = z6.object({
2075
- next: z6.object({ say: strs, then: z6.enum(["listen", "hold", "end", "none"]), waitFor: strs, reason: str, instructions: strs }).strict(),
2076
- messages: z6.array(z6.object({ key: str, to: str, text: str, about: strs, entries: strs, owed: strs, inviteToCall: z6.boolean() }).strict()),
2077
- entries: z6.array(z6.object({ key: str, from: str, on: strs }).strict()),
2078
- answers: z6.array(z6.object({ question: str, entries: strs, summary: str, picked: strs }).strict()),
2090
+ next: z6.object({ say: strs, then: z6.enum(["listen", "hold", "end", "none"]), waitFor: strs, reason: str2, instructions: strs }).strict(),
2091
+ messages: z6.array(z6.object({ key: str2, to: str2, text: str2, about: strs, entries: strs, owed: strs, inviteToCall: z6.boolean() }).strict()),
2092
+ entries: z6.array(z6.object({ key: str2, from: str2, on: strs }).strict()),
2093
+ answers: z6.array(z6.object({ question: str2, entries: strs, summary: str2, picked: strs }).strict()),
2079
2094
  changes: z6.array(z6.object({
2080
- key: str,
2095
+ key: str2,
2081
2096
  what: z6.enum(["goal", "question", "lesson"]),
2082
2097
  op: z6.enum(["create", "edit", "assign", "open", "complete", "cancel", "defer", "move", "block", "unblock", "withdraw", "remember", "revise"]),
2083
- id: str,
2084
- text: str,
2085
- title: str,
2086
- who: str,
2087
- under: str,
2098
+ id: str2,
2099
+ text: str2,
2100
+ title: str2,
2101
+ who: str2,
2102
+ under: str2,
2088
2103
  gate: z6.enum(["start", "complete", "answer", "none"]),
2089
- options: z6.array(z6.object({ id: str, label: str }).strict()),
2104
+ options: z6.array(z6.object({ id: str2, label: str2 }).strict()),
2090
2105
  pick: z6.enum(["one", "many", "rank", "words"]),
2091
2106
  entries: strs
2092
2107
  }).strict()),
2093
2108
  feedback: z6.array(strs),
2094
- search: z6.object({ query: str, within: strs, goal: str }).strict()
2109
+ search: z6.object({ query: str2, within: strs, goal: str2 }).strict()
2095
2110
  }).strict();
2096
2111
  var COMPACT_RESULT_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
2097
2112
  zodToJsonSchema(CompactResultSchema, { $refStrategy: "none" })
2098
2113
  );
2099
- var str2 = z7.string();
2114
+ var str3 = z7.string();
2100
2115
  var strs2 = z7.array(z7.string());
2101
2116
  var TalkerReplySchema = z7.object({
2102
2117
  /** What to say and send, messages to the person first: spoken in the order written. `to` is "user"
2103
2118
  * or an agent's handle; `sentences` is what a message to the person says, one short sentence each
2104
- * ([] to an agent); `text` is what a message to an agent says ("" to the person); `about` names
2119
+ * ([] to an agent); `text` is what a message to an agent says ("" to the person); `summary` is what it
2120
+ * asks the agent, in under ten words, as the person would put it ("" to the person; owner, 2026-10-15:
2121
+ * "Yes, add the summary"), which the recap's "Sent to <agent>: …" row shows; `about` names
2105
2122
  * handles; `blocks` is the item a question to an agent must be answered before ("" for none);
2106
2123
  * `callback` is true on a message to the agent doing work the person asked to be called back about
2107
2124
  * once it is done (false otherwise): that agent then owes the call (turns.md, step 0). */
2108
- messages: z7.array(z7.object({ key: str2, to: str2, sentences: strs2, text: str2, about: strs2, blocks: str2, callback: z7.boolean() }).strict()),
2125
+ messages: z7.array(z7.object({ key: str3, to: str3, sentences: strs2, text: str3, summary: str3, about: strs2, blocks: str3, callback: z7.boolean() }).strict()),
2109
2126
  /** What the call does next: listen, hold (the person asked for a moment) or end (they asked to). */
2110
2127
  then: z7.enum(["listen", "hold", "end"]),
2111
2128
  /** The person's replies to items (replies, owner 2026-10-07): the item's handle, the chosen option
2112
2129
  * IDs, the line handles, how they replied in under ten words (keeping any condition), and `defer`:
2113
2130
  * "" when their words settle the item, else what a reply that puts it off waits for -- "call" (the
2114
2131
  * end of this call), a question's handle (that question's answer) or an ISO time. */
2115
- replies: z7.array(z7.object({ item: str2, options: strs2, lines: strs2, summary: str2, defer: str2 }).strict()),
2132
+ replies: z7.array(z7.object({ item: str3, options: strs2, lines: strs2, summary: str3, defer: str3 }).strict()),
2116
2133
  /** The line handles that tell the talker how to run this call; they last until it ends and reach no agent. */
2117
2134
  instruction: strs2,
2118
2135
  /** The line handles the filer acts on, and the only ones it reads (3e): new work, a change to existing
2119
2136
  * work, feedback on Paigy, anything said to an agent, and any rule meant to outlast the call. */
2120
2137
  file: strs2,
2121
2138
  /** Evidence to fetch for a second round: a search, an item's full text, or an agent by name. */
2122
- need: z7.object({ kind: z7.enum(["search", "item", "agent", ""]), text: str2 }).strict(),
2139
+ need: z7.object({ kind: z7.enum(["search", "item", "agent", ""]), text: str3 }).strict(),
2123
2140
  /** The handle of the item to explain ("" for none). */
2124
- explain: str2
2141
+ explain: str3
2125
2142
  }).strict();
2126
2143
  var TALKER_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
2127
2144
  zodToJsonSchema(TalkerReplySchema, { $refStrategy: "none" })
2128
2145
  );
2129
- var str3 = z8.string();
2146
+ var str4 = z8.string();
2130
2147
  var strs3 = z8.array(z8.string());
2131
2148
  var FilerReplySchema = z8.object({
2132
- /** Which Goals each new line goes on: a line's handle, Goal handles (or keys of new Goals), and what
2133
- * the line says in at most ten words. */
2134
- filed: z8.array(z8.object({ line: str3, goals: strs3, summary: str3 }).strict()),
2149
+ /** Which Goals each new line goes on: a line's handle, Goal handles (or keys of new Goals: a line that asks
2150
+ * for new work goes on the Goal it creates, owner 2026-10-26), and what the line says in at most twenty
2151
+ * words (owner, 2026-10-26: "bump it from 10 to 20 words"). */
2152
+ filed: z8.array(z8.object({ line: str4, goals: strs3, summary: str4 }).strict()),
2135
2153
  goals: z8.array(z8.object({
2136
2154
  op: z8.enum(["create", "edit", "complete", "cancel", "reopen", "assign", "defer", "move", "block", "unblock"]),
2137
- key: str3,
2138
- goal: str3,
2139
- title: str3,
2140
- outcome: str3,
2141
- owner: str3,
2142
- under: str3,
2143
- until: str3,
2144
- on: str3,
2155
+ key: str4,
2156
+ goal: str4,
2157
+ title: str4,
2158
+ outcome: str4,
2159
+ owner: str4,
2160
+ under: str4,
2161
+ until: str4,
2162
+ on: str4,
2145
2163
  gate: z8.enum(["start", "complete", "answer", ""]),
2146
- why: str3
2164
+ why: str4
2147
2165
  }).strict()),
2148
2166
  questions: z8.array(z8.object({
2149
2167
  op: z8.enum(["create", "edit", "assign", "withdraw"]),
2150
- key: str3,
2151
- question: str3,
2152
- text: str3,
2153
- summary: str3,
2154
- to: str3,
2155
- goal: str3,
2156
- options: z8.array(z8.object({ id: str3, label: str3 }).strict()),
2168
+ key: str4,
2169
+ question: str4,
2170
+ text: str4,
2171
+ summary: str4,
2172
+ to: str4,
2173
+ goal: str4,
2174
+ options: z8.array(z8.object({ id: str4, label: str4 }).strict()),
2157
2175
  pick: z8.enum(["one", "many", "rank", "words", ""]),
2158
- blocks: str3
2176
+ blocks: str4
2159
2177
  }).strict()),
2160
- lessons: z8.array(z8.object({ op: z8.enum(["remember", "revise", "withdraw"]), lesson: str3, text: str3, scope: str3 }).strict()),
2178
+ lessons: z8.array(z8.object({ op: z8.enum(["remember", "revise", "withdraw"]), lesson: str4, text: str4, scope: str4 }).strict()),
2161
2179
  /** Line handles whose words comment on Paigy itself. */
2162
2180
  feedback: strs3
2163
2181
  }).strict();
@@ -2218,6 +2236,27 @@ var TidyReplySchema = z10.object({
2218
2236
  var TIDY_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
2219
2237
  zodToJsonSchema(TidyReplySchema, { $refStrategy: "none" })
2220
2238
  );
2239
+ var HandoutReplySchema = z11.object({
2240
+ assign: z11.array(z11.object({
2241
+ /** The Goal's handle (G). */
2242
+ goal: z11.string(),
2243
+ /** The agent's handle (A). */
2244
+ to: z11.string(),
2245
+ /** At most ten words, naming the Goal of theirs it is most like: the reason the hand-out records. */
2246
+ why: z11.string()
2247
+ }).strict()),
2248
+ /** The Goals no listed agent's work is even loosely like: Paigy starts a session for them (owner, 2026-10-24,
2249
+ * Goal 37603006, "One per family of related Goals"). */
2250
+ new: z11.array(z11.object({
2251
+ /** The Goal's handle (G). */
2252
+ goal: z11.string(),
2253
+ /** At most ten words: why nothing active fits it. */
2254
+ why: z11.string()
2255
+ }).strict())
2256
+ }).strict();
2257
+ var HANDOUT_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
2258
+ zodToJsonSchema(HandoutReplySchema, { $refStrategy: "none" })
2259
+ );
2221
2260
  function entryWords(entry) {
2222
2261
  const content = entry.content;
2223
2262
  if (content && "sealed" in content) return "";
@@ -2253,20 +2292,20 @@ var LIVE_MS = 3 * 6e4;
2253
2292
  var WORKING_MS = 60 * 6e4;
2254
2293
  var WORKING_TIER_MS = 2 * 60 * 6e4;
2255
2294
  var RECENT_TIER_MS = 24 * 60 * 6e4;
2256
- var ContextSchema = z11.object({
2257
- title: z11.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
2258
- description: z11.array(z11.string().min(1)).describe(
2295
+ var ContextSchema = z12.object({
2296
+ title: z12.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
2297
+ description: z12.array(z12.string().min(1)).describe(
2259
2298
  "Semantic chunks of detail (each a standalone, non-empty piece). The user can select chunks to ask you to expand. MAY BE EMPTY: a claim whose whole content is its heading \u2014 a single sentence \u2014 has no body, and saying so beats repeating the heading underneath itself. That repeat is what `min(1)` used to force, at 2x the storage, with every reader subtracting it back out at render time."
2260
2299
  ),
2261
2300
  /** THE ASK'S UNITS (3c): its context as titled units, in order. The app lists the titles and opens
2262
2301
  * a body on a tap. Absent on an ask sent without units, which renders as before. */
2263
- units: z11.array(z11.object({ title: z11.string(), body: z11.string() })).optional()
2302
+ units: z12.array(z12.object({ title: z12.string(), body: z12.string() })).optional()
2264
2303
  });
2265
- var ParticipantSchema = z11.object({
2266
- kind: z11.enum(["human", "agent"]),
2267
- id: z11.string()
2304
+ var ParticipantSchema = z12.object({
2305
+ kind: z12.enum(["human", "agent"]),
2306
+ id: z12.string()
2268
2307
  });
2269
- var TransformSchema = z11.enum([
2308
+ var TransformSchema = z12.enum([
2270
2309
  "structure",
2271
2310
  // shape intent into an answer contract; pick channel/urgency — broker `ask`, `select` shapes, `points`
2272
2311
  "request_more",
@@ -2289,13 +2328,13 @@ var PAIGY_SELF = { kind: "agent", id: "paigy" };
2289
2328
  function isPaigy(ref) {
2290
2329
  return ref === participantRef(PAIGY_SELF);
2291
2330
  }
2292
- var VisualSchema = z11.object({
2293
- url: z11.string().url(),
2294
- label: z11.string().optional()
2331
+ var VisualSchema = z12.object({
2332
+ url: z12.string().url(),
2333
+ label: z12.string().optional()
2295
2334
  });
2296
- var NotifyLevelSchema = z11.enum(["inbox", "push", "banner", "call"]);
2297
- var SelectShapeSchema = z11.enum(["one", "many", "rank", "confirm", "text"]);
2298
- var ReceiptEventSchema = z11.enum([
2335
+ var NotifyLevelSchema = z12.enum(["inbox", "push", "banner", "call"]);
2336
+ var SelectShapeSchema = z12.enum(["one", "many", "rank", "confirm", "text"]);
2337
+ var ReceiptEventSchema = z12.enum([
2299
2338
  "delivered",
2300
2339
  // the bundle reached the recipient at some level
2301
2340
  "seen",
@@ -2325,47 +2364,47 @@ var ReceiptEventSchema = z11.enum([
2325
2364
  // be rewound by a writer that forgot to advance it.
2326
2365
  "restarted"
2327
2366
  ]);
2328
- var AttentionSchema = z11.object({
2367
+ var AttentionSchema = z12.object({
2329
2368
  urgency: NotifyLevelSchema,
2330
2369
  /** The required answer shape, or null for a plain notify that asks nothing back. */
2331
2370
  select: SelectShapeSchema.nullable(),
2332
2371
  /** Coverage contract (#396) — points the answer must address; null = none declared. */
2333
- points: z11.array(z11.string()).nullable(),
2372
+ points: z12.array(z12.string()).nullable(),
2334
2373
  /** Whether the ask blocks the sender — what lets arbitration escalate it on silence. */
2335
- blocking: z11.boolean(),
2374
+ blocking: z12.boolean(),
2336
2375
  /** Reserved (docs/model/model.md lists it): a response deadline. No row column yet — a later Phase 2
2337
2376
  * slice wires it; optional so today's rows/callers project cleanly. */
2338
- deadline: z11.string().datetime().nullable().optional()
2377
+ deadline: z12.string().datetime().nullable().optional()
2339
2378
  });
2340
- var NotifyRequestFields = z11.object({
2379
+ var NotifyRequestFields = z12.object({
2341
2380
  /** Plaintext message content. Present on the plaintext path (today's shape);
2342
2381
  * ABSENT on the E2EE path, where the sealed `envelope` below carries it. The
2343
2382
  * superRefine at the bottom enforces exactly one of the two. */
2344
2383
  context: ContextSchema.optional(),
2345
- options: z11.array(OptionSchema.omit({ id: true }).extend({ label: z11.string().trim().min(1).max(1e3) }).strict()).min(OPTIONS_MIN).max(OPTIONS_MAX).optional().describe(
2384
+ options: z12.array(OptionSchema.omit({ id: true }).extend({ label: z12.string().trim().min(1).max(1e3) }).strict()).min(OPTIONS_MIN).max(OPTIONS_MAX).optional().describe(
2346
2385
  "The choices, in order \u2014 required when select is 'one'/'many'/'rank', omitted otherwise. Ids are assigned automatically by position ('1', '2', \u2026); the user's answer references them as optionId(s)."
2347
2386
  ),
2348
- points: z11.array(z11.string().min(1)).optional().describe(
2387
+ points: z12.array(z12.string().min(1)).optional().describe(
2349
2388
  "The distinct things you need answered, each a short phrase \u2014 on a call the broker keeps the conversation going until each is addressed, and the reply reports which were covered, so a half-answer is never silently returned as final. Omit for single-part asks."
2350
2389
  ),
2351
- visuals: z11.array(VisualSchema).optional().describe(
2390
+ visuals: z12.array(VisualSchema).optional().describe(
2352
2391
  "Images attached to the message itself \u2014 context for the whole question (a screenshot, a chart). For a preview on one selectable choice, use that option's `html`/`image` instead."
2353
2392
  ),
2354
2393
  /** Git repo the agent is working in ("owner/name"). Local MCP fills this from the checkout — omit unless overriding. */
2355
- repo: z11.string().optional(),
2394
+ repo: z12.string().optional(),
2356
2395
  /** Git branch the agent is on. Local MCP fills this from the checkout — omit unless overriding. */
2357
- branch: z11.string().optional(),
2396
+ branch: z12.string().optional(),
2358
2397
  /** Continue an existing conversation — the id of any notification in it (its root
2359
2398
  * is the conversation's identity). Omitted = start a new conversation. Renamed
2360
2399
  * from `parentId` (2026-08-03): one linkage system, the parent; the API edge
2361
2400
  * still accepts the old name from older clients. */
2362
- parentId: z11.string().uuid().optional(),
2401
+ parentId: z12.string().uuid().optional(),
2363
2402
  /** The durable outcome this contact advances. Optional during the notification-to-Work
2364
2403
  * migration; when present, a blocking ask creates a DecisionNeed for this Work. */
2365
- workId: z11.string().uuid().optional(),
2404
+ workId: z12.string().uuid().optional(),
2366
2405
  /** Target Goal scope. During staged migration this is accepted by the shared contract but
2367
2406
  * target delivery activation remains model-gated; workId and goalId are mutually exclusive. */
2368
- goalId: z11.string().uuid().optional(),
2407
+ goalId: z12.string().uuid().optional(),
2369
2408
  urgency: NotifyLevelSchema.default("inbox").describe(
2370
2409
  "The level you're requesting \u2014 the user's account permissions + session mode can lower it. 'inbox' (default) = sits silently in the inbox for the user to get to. 'push' = a quiet passive push (lands in Notification Center, no sound) \u2014 a gentle heads-up. 'banner' = a time-sensitive banner/lock-screen push with sound (a 'paige') they tap to open \u2014 use when you need them soon-ish but it's not worth ringing them. 'call' = rings the user's phone now (a CallKit voice call) \u2014 use only when you genuinely need them in the moment (blocked and waiting, time-sensitive). context.title is what they see on the banner/ring, so make it specific."
2371
2410
  ),
@@ -2373,7 +2412,7 @@ var NotifyRequestFields = z11.object({
2373
2412
  * visible and marks it needs_input. Renamed from the old `parentId` (2026-08-03)
2374
2413
  * when `parentId` became the conversation handle: `parentId` says WHERE, this
2375
2414
  * says HOW. */
2376
- clarifies: z11.string().optional(),
2415
+ clarifies: z12.string().optional(),
2377
2416
  select: SelectShapeSchema.optional().describe(
2378
2417
  "How the user answers \u2014 required on the fully-shaped form, pick the shape that fits the question: 'one' = pick one option, 'many' = pick several, 'rank' = pick & order (each needs `options`); 'confirm' = yes/no or approve/deny; 'text' = free-form reply only (status updates, open questions). 'confirm' and 'text' take no options. Omit only when sending the simplified `ask` form \u2014 the broker picks the shape."
2379
2418
  ),
@@ -2384,23 +2423,23 @@ var NotifyRequestFields = z11.object({
2384
2423
  * derive agent-side before sealing, so the server only ever shapes plaintext). */
2385
2424
  // 10k, not a sentence budget. What the human hears is bounded by the BROKER — it splits
2386
2425
  // the ask into topics and gives each one at most three sentences and one question
2387
- // (docs/brain/broker/agenda-design.md) — not by a wire cap the agent has to pre-summarize under.
2426
+ // (docs/history/agenda-design.md) — not by a wire cap the agent has to pre-summarize under.
2388
2427
  // Owner, 2026-07-28: "our actual limitation on how long something is to the user should
2389
2428
  // come from the broker splitting and summarizing." The cap that remains is a size guard.
2390
- ask: z11.string().min(1).max(1e4).optional().describe(
2429
+ ask: z12.string().min(1).max(1e4).optional().describe(
2391
2430
  'SIMPLIFIED FORM \u2014 state in plain prose what you need to learn from the user and why it matters now (e.g. "I need to know whether to deploy the auth fix \u2014 tests are green, staging verified"). Write as much as the situation needs (up to 10k characters) \u2014 Paigy breaks it into topics and reads it back a few sentences at a time; do NOT pre-summarize it into one line. Paigy derives the title, answer shape, options, and delivery channel for you. Mutually exclusive with context/select/options \u2014 send one form or the other.'
2392
2431
  ),
2393
- needs: z11.array(z11.string().min(1)).optional().describe(
2432
+ needs: z12.array(z12.string().min(1)).optional().describe(
2394
2433
  "With `ask` only: the distinct things you need answered when the ask is multi-part \u2014 becomes the coverage contract (`points`), so a half-answer is never silently final."
2395
2434
  ),
2396
- urgencyHint: z11.enum(["whenever", "soon", "now"]).optional().describe(
2435
+ urgencyHint: z12.enum(["whenever", "soon", "now"]).optional().describe(
2397
2436
  "With `ask` only: how urgently you need the answer \u2014 'whenever' (inbox), 'soon' (worth a heads-up), 'now' (you're blocked this minute). A hint, not a command: the user's settings still have the final word."
2398
2437
  ),
2399
2438
  /** #575: the ONE self-report that replaces urgencyHint + blocking — what happens
2400
2439
  * to the agent's work while it waits. Normalized server-side into those two
2401
2440
  * fields (normalizeWaiting) so everything downstream is untouched; explicit
2402
2441
  * urgencyHint/blocking win when both are sent. */
2403
- waiting: z11.enum(["none", "soft", "hard"]).optional().describe(
2442
+ waiting: z12.enum(["none", "soft", "hard"]).optional().describe(
2404
2443
  "With `ask`: what happens to your work while you wait. 'none' = you're just informing the user. 'soft' = you'd like an answer but can keep working. 'hard' = you are stopped until they answer (reaches them urgently and escalates to a real phone call if unanswered). Replaces urgencyHint + blocking \u2014 send this one field."
2405
2444
  ),
2406
2445
  /** Δ9b (#895): HOLD this claim so the sender can correct the plan before anyone is
@@ -2408,98 +2447,98 @@ var NotifyRequestFields = z11.object({
2408
2447
  * holding by default would charge every quiet claim that minute before any agent could
2409
2448
  * correct anything. Ignored for `waiting: 'hard'`: a blocking ask rings on what we have,
2410
2449
  * and the enrichment can still land mid-call (#781 re-plans the unspoken tail). */
2411
- confirm: z11.boolean().optional().describe(
2450
+ confirm: z12.boolean().optional().describe(
2412
2451
  "Hold this one so you can correct the plan before the user is interrupted. The response comes back with `held: true` and the plan; POST the confirm route to release it (with options/visuals/urgency corrections, or nothing at all). If you never do, it is announced anyway a couple of minutes later. Ignored when waiting is 'hard'."
2413
2452
  ),
2414
2453
  /** #575: a RELAY of the user's explicitly stated preference, never the agent's
2415
2454
  * choice. Outranks waiting in both directions: 'call' rings even for a
2416
2455
  * waiting:'none' "call me when it's done"; 'message' never rings even for
2417
2456
  * waiting:'hard'. */
2418
- channel: z11.enum(["call", "message"]).optional().describe(
2457
+ channel: z12.enum(["call", "message"]).optional().describe(
2419
2458
  "Only if the user explicitly said how to reach them \u2014 'call me' \u2192 'call', 'just message/text me' \u2192 'message'. Omit otherwise; Paigy picks."
2420
2459
  ),
2421
- confirmStyle: z11.enum(["yesno", "approve"]).default("yesno").describe(
2460
+ confirmStyle: z12.enum(["yesno", "approve"]).default("yesno").describe(
2422
2461
  "Labels for a select:'confirm' paige \u2014 'yesno' (Yes/No) or 'approve' (Approve/Deny). Ignored unless select is 'confirm'."
2423
2462
  ),
2424
- blocking: z11.boolean().default(false).describe(
2463
+ blocking: z12.boolean().default(false).describe(
2425
2464
  "Set true when real downstream work is stuck behind this specific decision \u2014 you can't make meaningful progress until it's answered. This is the real signal for how urgently the user should be reached; it's what the premier use case (an agent that stays unblocked instead of going idle) depends on. Independent of `urgency`: a `banner`-level question can still be `blocking` (something IS stuck, just not time-critical enough to ring for immediately) \u2014 if it goes unanswered a while, Paigy escalates it to a real call using this flag rather than guessing from how many other things happen to be pending. Leave false for anything you could work around, defer, or where other useful work exists meanwhile."
2426
2465
  )
2427
2466
  });
2428
2467
  var NotifyRequestSchema = NotifyRequestFields.superRefine((r, ctx) => {
2429
- if (r.workId && r.goalId) ctx.addIssue({ code: z11.ZodIssueCode.custom, path: ["goalId"], message: "pass goalId or workId, not both" });
2468
+ if (r.workId && r.goalId) ctx.addIssue({ code: z12.ZodIssueCode.custom, path: ["goalId"], message: "pass goalId or workId, not both" });
2430
2469
  if (r.ask !== void 0) {
2431
2470
  for (const f of ["context", "select", "points"]) {
2432
2471
  if (r[f] !== void 0)
2433
- ctx.addIssue({ code: z11.ZodIssueCode.custom, path: [f], message: `the simplified \`ask\` form takes no ${f} \u2014 the broker derives the answer shape from your prose. Drop ${f} and say it in \`ask\` instead ("should I\u2026" for approve/deny, "which of these\u2026" for a pick), passing \`options\` when you're offering concrete alternatives.` });
2472
+ ctx.addIssue({ code: z12.ZodIssueCode.custom, path: [f], message: `the simplified \`ask\` form takes no ${f} \u2014 the broker derives the answer shape from your prose. Drop ${f} and say it in \`ask\` instead ("should I\u2026" for approve/deny, "which of these\u2026" for a pick), passing \`options\` when you're offering concrete alternatives.` });
2434
2473
  }
2435
2474
  return;
2436
2475
  }
2437
2476
  if (r.needs !== void 0 || r.urgencyHint !== void 0)
2438
- ctx.addIssue({ code: z11.ZodIssueCode.custom, path: ["needs"], message: "needs/urgencyHint belong to the simplified `ask` form \u2014 with a shaped request use points/urgency" });
2477
+ ctx.addIssue({ code: z12.ZodIssueCode.custom, path: ["needs"], message: "needs/urgencyHint belong to the simplified `ask` form \u2014 with a shaped request use points/urgency" });
2439
2478
  if (!r.context)
2440
- ctx.addIssue({ code: z11.ZodIssueCode.custom, path: ["context"], message: "context is required (plaintext path)" });
2479
+ ctx.addIssue({ code: z12.ZodIssueCode.custom, path: ["context"], message: "context is required (plaintext path)" });
2441
2480
  if (!r.select)
2442
- ctx.addIssue({ code: z11.ZodIssueCode.custom, path: ["select"], message: "select is required on the shaped form" });
2481
+ ctx.addIssue({ code: z12.ZodIssueCode.custom, path: ["select"], message: "select is required on the shaped form" });
2443
2482
  const needsOptions = r.select === "one" || r.select === "many" || r.select === "rank";
2444
2483
  if (needsOptions && !r.options?.length)
2445
- ctx.addIssue({ code: z11.ZodIssueCode.custom, path: ["options"], message: `select:'${r.select}' requires options` });
2484
+ ctx.addIssue({ code: z12.ZodIssueCode.custom, path: ["options"], message: `select:'${r.select}' requires options` });
2446
2485
  if (!needsOptions && r.options?.length)
2447
- ctx.addIssue({ code: z11.ZodIssueCode.custom, path: ["options"], message: `select:'${r.select}' takes no options` });
2486
+ ctx.addIssue({ code: z12.ZodIssueCode.custom, path: ["options"], message: `select:'${r.select}' takes no options` });
2448
2487
  });
2449
- var NotifyStatusSchema = z11.enum(["pending", "answered", "ignored"]);
2450
- var AgentStateSchema = z11.enum(["idle", "in_progress", "completed", "needs_input"]);
2451
- var TurnSchema = z11.object({
2452
- prompt: z11.string(),
2453
- reply: z11.string()
2488
+ var NotifyStatusSchema = z12.enum(["pending", "answered", "ignored"]);
2489
+ var AgentStateSchema = z12.enum(["idle", "in_progress", "completed", "needs_input"]);
2490
+ var TurnSchema = z12.object({
2491
+ prompt: z12.string(),
2492
+ reply: z12.string()
2454
2493
  });
2455
- var UserAnswerSchema = z11.discriminatedUnion("kind", [
2456
- z11.object({ kind: z11.literal("option"), optionId: z11.string(), label: z11.string().optional() }),
2457
- z11.object({ kind: z11.literal("text"), text: z11.string() }),
2458
- z11.object({ kind: z11.literal("ignored") }),
2459
- z11.object({ kind: z11.literal("multi"), optionIds: z11.array(z11.string()), labels: z11.array(z11.string()).optional() }),
2460
- z11.object({ kind: z11.literal("ranked"), optionIds: z11.array(z11.string()), labels: z11.array(z11.string()).optional() }),
2461
- z11.object({ kind: z11.literal("clarify"), chunks: z11.array(z11.string()).min(1) }),
2462
- z11.object({ kind: z11.literal("confirm"), approved: z11.boolean() }),
2463
- z11.object({ kind: z11.literal("turns"), turns: z11.array(TurnSchema).min(1) }),
2464
- /** An auto-answer derived from the user's PAST decisions (docs/brain/broker/precedent-design.md §2):
2494
+ var UserAnswerSchema = z12.discriminatedUnion("kind", [
2495
+ z12.object({ kind: z12.literal("option"), optionId: z12.string(), label: z12.string().optional() }),
2496
+ z12.object({ kind: z12.literal("text"), text: z12.string() }),
2497
+ z12.object({ kind: z12.literal("ignored") }),
2498
+ z12.object({ kind: z12.literal("multi"), optionIds: z12.array(z12.string()), labels: z12.array(z12.string()).optional() }),
2499
+ z12.object({ kind: z12.literal("ranked"), optionIds: z12.array(z12.string()), labels: z12.array(z12.string()).optional() }),
2500
+ z12.object({ kind: z12.literal("clarify"), chunks: z12.array(z12.string()).min(1) }),
2501
+ z12.object({ kind: z12.literal("confirm"), approved: z12.boolean() }),
2502
+ z12.object({ kind: z12.literal("turns"), turns: z12.array(TurnSchema).min(1) }),
2503
+ /** An auto-answer derived from the user's PAST decisions (docs/history/precedent-design.md §2):
2465
2504
  * delivered through the same settle/await path as a human answer, carrying the judge's
2466
2505
  * derivation and the precedent ids it grew from. Always paired with a visible trail
2467
2506
  * card the user can reply to — the broker never overrides the user. */
2468
- z11.object({ kind: z11.literal("precedent"), answer: z11.string(), derivation: z11.string(), sources: z11.array(z11.string()).min(1) })
2507
+ z12.object({ kind: z12.literal("precedent"), answer: z12.string(), derivation: z12.string(), sources: z12.array(z12.string()).min(1) })
2469
2508
  ]);
2470
- var IntentSchema = z11.object({
2509
+ var IntentSchema = z12.object({
2471
2510
  // The full vocabulary the bot's mapper emits (mapper.INTENT_KINDS) — the schema lagged
2472
2511
  // it by two ("detail", "feedback"), and because the settle handler parsed the array
2473
2512
  // all-or-nothing, ONE feedback act silently dropped EVERY intent on the call,
2474
2513
  // questions included. Found auditing five calls' stored feedback, 2026-08-01.
2475
- kind: z11.enum(["defer", "delegate", "channel", "question", "detail", "feedback", "command", "control"]),
2476
- detail: z11.string(),
2514
+ kind: z12.enum(["defer", "delegate", "channel", "question", "detail", "feedback", "command", "control"]),
2515
+ detail: z12.string(),
2477
2516
  /** Defer only: seconds until the callback the caller asked for, when something upstream
2478
2517
  * already read the time. Nothing sets it today (#397 documented an MCP parser that was
2479
2518
  * never written) — the API reads the defer's `detail` itself with `notes/when.ts`
2480
2519
  * (`parseDelay`, #1292), and a value here simply wins over that reading. */
2481
- dueInSeconds: z11.number().int().positive().optional(),
2520
+ dueInSeconds: z12.number().int().positive().optional(),
2482
2521
  /** Feedback only (#812): WHICH failure the complaint names — typed by the mapper that
2483
2522
  * already read the utterance, so `signals.kind` stops defaulting to
2484
2523
  * 'other' on every row. A table that records that something was wrong and nothing
2485
2524
  * about what cannot answer "is the bot looping less this week?". */
2486
- fault: z11.enum(["loop", "unanswered", "overridden", "misheard", "slow", "other"]).optional()
2525
+ fault: z12.enum(["loop", "unanswered", "overridden", "misheard", "slow", "other"]).optional()
2487
2526
  });
2488
- var RideAlongSchema = z11.object({
2527
+ var RideAlongSchema = z12.object({
2489
2528
  /** The note this came from — assign/clarify/close it through /api/notes/:id. */
2490
- noteId: z11.string(),
2529
+ noteId: z12.string(),
2491
2530
  /** What to do, in the owner's own words (the note's headline). Never model-rewritten. */
2492
- text: z11.string(),
2531
+ text: z12.string(),
2493
2532
  /** The thread to report back on, when the note was dispatched over the request rail. */
2494
- parentId: z11.string().nullable()
2533
+ parentId: z12.string().nullable()
2495
2534
  });
2496
- var AwaitItemSchema = z11.discriminatedUnion("type", [
2497
- z11.object({
2498
- type: z11.literal("reply"),
2499
- parentId: z11.string(),
2500
- notificationId: z11.string(),
2501
- workId: z11.string().uuid().optional(),
2502
- decisionId: z11.string().uuid().optional(),
2535
+ var AwaitItemSchema = z12.discriminatedUnion("type", [
2536
+ z12.object({
2537
+ type: z12.literal("reply"),
2538
+ parentId: z12.string(),
2539
+ notificationId: z12.string(),
2540
+ workId: z12.string().uuid().optional(),
2541
+ decisionId: z12.string().uuid().optional(),
2503
2542
  answer: UserAnswerSchema,
2504
2543
  /** WHAT THE AGENT CANNOT KNOW FROM THE FIELDS BESIDE IT (owner, 2026-09-04, issue
2505
2544
  * #1537). One line, built from the record: the ask and the caller's reply VERBATIM,
@@ -2509,111 +2548,126 @@ var AwaitItemSchema = z11.discriminatedUnion("type", [
2509
2548
  * "call me back after you merge" in their own words decides for itself what to do,
2510
2549
  * and now knows exactly which call to make. Absent when either half is missing —
2511
2550
  * a sentence with a hole in it is worse than no sentence. */
2512
- note: z11.string().optional(),
2551
+ note: z12.string().optional(),
2513
2552
  /** The call record rendered for THIS agent (`docs/brain/voice/record-design.md`): the words the
2514
2553
  * shaped answer was mapped from, filtered to its own claims. There is no second list
2515
2554
  * of labels beside it — the acts went 2026-09-04 and `intents` went with them (owner,
2516
2555
  * 2026-09-04): the agent reads the sentence and decides. */
2517
- transcript: z11.string().optional(),
2556
+ transcript: z12.string().optional(),
2518
2557
  /** Coverage report (#396), when the ask declared `points`: which of them this
2519
2558
  * answer addressed. Missing points = re-ask or proceed knowingly partial. */
2520
- covered: z11.array(z11.string()).optional(),
2559
+ covered: z12.array(z12.string()).optional(),
2521
2560
  /** Ride-alongs (RideAlongSchema) — pending work for you, attached to the moment you
2522
2561
  * became free. Only `reply` and `idle` carry it: those are the two outcomes that
2523
2562
  * END a wait. `remind`, `superseded` and `turn` are mid-flight, and handing an
2524
2563
  * agent a side-quest while it is still holding the line is how the main thing gets
2525
2564
  * dropped. Absent/empty = nothing owed. */
2526
- also: z11.array(RideAlongSchema).optional()
2565
+ also: z12.array(RideAlongSchema).optional()
2527
2566
  }),
2528
- z11.object({
2529
- type: z11.literal("remind"),
2530
- parentId: z11.string(),
2531
- notificationId: z11.string(),
2532
- remindAt: z11.string().datetime({ offset: true }),
2567
+ z12.object({
2568
+ type: z12.literal("remind"),
2569
+ parentId: z12.string(),
2570
+ notificationId: z12.string(),
2571
+ remindAt: z12.string().datetime({ offset: true }),
2533
2572
  /** Seconds until remindAt, server-computed — pass straight to ScheduleWakeup. */
2534
- remindInSeconds: z11.number()
2573
+ remindInSeconds: z12.number()
2535
2574
  }),
2536
2575
  /** The awaited ask was REPLACED by a newer notification on its thread (e.g. a
2537
2576
  * post-feedback revision, #633) — the user will never answer this id. Stop
2538
2577
  * awaiting it; the live ask is the thread's newest turn (await that one, or
2539
2578
  * re-orient via contact({})). */
2540
- z11.object({
2541
- type: z11.literal("superseded"),
2542
- parentId: z11.string(),
2543
- notificationId: z11.string()
2579
+ z12.object({
2580
+ type: z12.literal("superseded"),
2581
+ parentId: z12.string(),
2582
+ notificationId: z12.string()
2544
2583
  }),
2545
2584
  /** A LIVE call's turn, streamed as it lands (#783). PROVISIONAL: the user can still
2546
2585
  * revise any of these until the final reply arrives — partial = intelligence,
2547
2586
  * settled = authorization. Use it to PREPARE (fetch, draft, warm), never to act
2548
2587
  * irreversibly. If `acts` carries a question aimed at you and you know the answer,
2549
2588
  * contact on the same thread right away — the caller hears it on the same call. */
2550
- z11.object({
2551
- type: z11.literal("partial"),
2552
- notificationId: z11.string(),
2553
- inFlight: z11.literal(true),
2554
- turn: z11.object({
2555
- idx: z11.number(),
2556
- prompt: z11.string(),
2557
- reply: z11.string(),
2558
- acts: z11.array(IntentSchema).nullable().optional()
2589
+ z12.object({
2590
+ type: z12.literal("partial"),
2591
+ notificationId: z12.string(),
2592
+ inFlight: z12.literal(true),
2593
+ turn: z12.object({
2594
+ idx: z12.number(),
2595
+ prompt: z12.string(),
2596
+ reply: z12.string(),
2597
+ acts: z12.array(IntentSchema).nullable().optional()
2559
2598
  })
2560
2599
  }),
2561
- z11.object({
2562
- type: z11.literal("idle"),
2563
- also: z11.array(RideAlongSchema).optional(),
2600
+ z12.object({
2601
+ type: z12.literal("idle"),
2602
+ also: z12.array(RideAlongSchema).optional(),
2564
2603
  /** Is a call live for this agent's user right now? The SDK polls the partial stream
2565
2604
  * (#783) between idle ticks ONLY while this is not `false` — a partial can only exist
2566
2605
  * during a live call, and polling for one on a banner/message was a wasted HTTP call +
2567
2606
  * 3 queries on every idle tick of every waiting agent (~80% of all traffic at scale).
2568
2607
  * Absent = an older API → the SDK keeps polling, exactly as before. */
2569
- inFlight: z11.boolean().optional()
2608
+ inFlight: z12.boolean().optional()
2570
2609
  })
2571
2610
  ]);
2572
- var VoiceKeySchema = z11.enum(["rachel", "george", "jessica", "brian", "lily"]);
2573
- var AgendaTurnSchema = z11.object({
2611
+ var VoiceKeySchema = z12.enum(["rachel", "george", "jessica", "brian", "lily"]);
2612
+ var AgendaTurnSchema = z12.object({
2574
2613
  /** THE TURN'S IDENTITY (the first-sentence stream, 2026-09-09): the brain call that wrote
2575
2614
  * it and its place in that reply — `<brainCallId>:<index>`, with `:p` on the first
2576
2615
  * sentence a re-plan publishes ahead of the rest. A turn is spoken once, by this id: the
2577
2616
  * completion of a streamed re-plan carries the published sentence again, and the walk
2578
2617
  * drops what it already said by identity, never by the API's guess of what was polled.
2579
2618
  * Absent on plans nothing streams (a ring plan, a floor). */
2580
- id: z11.string().optional(),
2619
+ id: z12.string().optional(),
2581
2620
  /** Twin coverage (#1089): sibling claim ids this asking turn's answer ALSO settles —
2582
2621
  * the planner declares duplicates instead of asking them twice. */
2583
- coveredIds: z11.array(z11.string()).optional(),
2622
+ coveredIds: z12.array(z12.string()).optional(),
2584
2623
  /** The spoken sentences of the turn, in order. No count: how long a turn is is the brain's call
2585
2624
  * (owner, 2026-09-25), and a count here refused whole plans. */
2586
- info: z11.array(z11.string().min(1)).default([]),
2625
+ info: z12.array(z12.string().min(1)).default([]),
2587
2626
  /** THE ID OF EACH SENTENCE, when the plan names them (turns.md): a talker message's sentences are its
2588
2627
  * `info`, one piece each, and `units[i]` is the id the bot's line receipt carries for `info[i]`
2589
2628
  * (`<cycle>:<key>:<n>`), so what was heard is known per sentence. Absent on every other turn. */
2590
- units: z11.array(z11.string().min(1)).optional(),
2591
- question: z11.string().min(1).nullable(),
2629
+ units: z12.array(z12.string().min(1)).optional(),
2630
+ question: z12.string().min(1).nullable(),
2592
2631
  /** True on the one turn carrying the agent's own declared question. */
2593
- asks: z11.boolean().optional(),
2632
+ asks: z12.boolean().optional(),
2594
2633
  /** The claim this turn belongs to (#781) — the RETURN identity: answers route by it.
2595
2634
  * Absent on a single-claim plan (the session's own claim) and on shared context turns,
2596
2635
  * which route nothing. */
2597
- claimId: z11.string().optional(),
2636
+ claimId: z12.string().optional(),
2598
2637
  /** The claim's voice key (#462) — the OUTBOUND identity, audible who-is-asking. */
2599
- voice: z11.string().optional(),
2638
+ voice: z12.string().optional(),
2600
2639
  /** The claim's AGENT NAME (#838) — the spoken identity. A voice alone doesn't say
2601
2640
  * whose request this is: an item that folded in from another agent arrived as a bare
2602
2641
  * non-sequitur ("First real production sign-in is yours to make whenever you want.")
2603
2642
  * and the owner answered "What?". The bot names the agent before its first turn. */
2604
- agent: z11.string().optional(),
2643
+ agent: z12.string().optional(),
2605
2644
  /** The claim's agent by ID — the pairing's connection id (`notifications.token_id`), the
2606
2645
  * same id a face is minted from. A name is not an identity: two pairings may be called
2607
2646
  * "Claude", and a name cannot be joined on. The record's entries carry it (`agent_id`)
2608
2647
  * so "who said that" survives the call, and it rides PER TURN because a coalesced call
2609
2648
  * speaks for several agents — the turn is the only place that knows which. */
2610
- agentId: z11.string().optional(),
2649
+ agentId: z12.string().optional(),
2611
2650
  /** ITS QUESTION IS ON THE TABLE (#3292): a talker line about a question the person owes. The walk tells
2612
2651
  * the phone (`asking`, so the agenda goes gold and its options show) without treating the line as a
2613
2652
  * question turn — the talker owns re-asking and the waits, so `question` stays null. */
2614
- onTable: z11.boolean().optional(),
2653
+ onTable: z12.boolean().optional(),
2654
+ /** THE CARRIED ITEM THIS LINE TELLS (Goal 2a1e50eb, owner 2026-10-14: "Build the whole design") — a
2655
+ * request the Call carries that asks NOTHING: a report, a progress note, another agent's waiting news.
2656
+ * Its request Entry id, so the phone can make that agenda row the current one while it is read
2657
+ * (`telling` on the `turn` topic, `docs/clients/app/walk/design.md` §11).
2658
+ *
2659
+ * A FIELD OF ITS OWN, NEVER `claimId`: the claim is the RETURN identity — answers route by it and the
2660
+ * record tags the line with it (`workId`) — and an answer must never route to an Entry that asks
2661
+ * nothing. Absent on a turn speaking for a question (`claimId` says that) and on one speaking for no
2662
+ * carried item at all (an opener, a sign-off, Paigy's own line). */
2663
+ telling: z12.string().optional(),
2664
+ /** PAIGY'S OWN LINE (owner, 2026-10-15; calls ed2cbdce, ad50ad25): a turn that speaks for no item -- an
2665
+ * opener, a sign-off, a reply about nothing an agent asked or told -- is recorded as Paigy's, not as the
2666
+ * agent that rang. Absent on every turn that speaks for an item (`agentId` names whose), and on plans
2667
+ * from before it: a bot that does not know it records the ringing agent, as before. */
2668
+ speaksFor: z12.literal("paigy").optional(),
2615
2669
  select: SelectShapeSchema.optional(),
2616
- options: z11.array(OptionSchema.omit({ id: true })).optional(),
2670
+ options: z12.array(OptionSchema.omit({ id: true })).optional(),
2617
2671
  /* `pace` STOOD HERE (#826). A turn could carry seconds and the model chose them. The walk
2618
2672
  paces itself now — a short beat between the sentences of a turn, the longer one at its end
2619
2673
  (owner, 2026-09-30: "remove the bot deciding pace") — and it does that where the words are
@@ -2622,58 +2676,58 @@ var AgendaTurnSchema = z11.object({
2622
2676
  /** Whether the walk WAITS for an answer before moving on. Absent = derived as today
2623
2677
  * (a question blocks, context flows). blocking:false on a question = ask and move
2624
2678
  * on, the claim stays pending; blocking:true on context = hold for a reply. */
2625
- blocking: z11.boolean().optional(),
2679
+ blocking: z12.boolean().optional(),
2626
2680
  /** SPOKEN ONLY IF THEY SAY NOTHING (owner, 2026-10-01, call 812de935: "you're gonna re-ask, but it
2627
2681
  * shouldn't be the same words … more like, hey, are you still there, or are you able to answer, or
2628
2682
  * would you need more information"). The walk holds this turn out of its queue; at the queue's end it
2629
2683
  * listens for the last word, and only if that listen is silent is this turn said and asked. If they
2630
2684
  * speak, it is dropped and their words are taken like any reply. */
2631
- ifSilent: z11.boolean().optional()
2685
+ ifSilent: z12.boolean().optional()
2632
2686
  });
2633
2687
  var CLAIM_STALE_MS = 30 * 6e4;
2634
- var CallQuestionSchema = z11.object({
2635
- id: z11.string(),
2636
- entryId: z11.string(),
2637
- title: z11.string(),
2638
- state: z11.enum(["open", "answered"]),
2639
- answer: z11.string().nullable(),
2688
+ var CallQuestionSchema = z12.object({
2689
+ id: z12.string(),
2690
+ entryId: z12.string(),
2691
+ title: z12.string(),
2692
+ state: z12.enum(["open", "answered"]),
2693
+ answer: z12.string().nullable(),
2640
2694
  /** WHO ASKED IT (owner, 2026-09-23, Goal a345e906: each agenda row wears its agent's face) — the
2641
2695
  * request Entry's author, as the same three facts the item's own `tokenId`/`name`/`voice`
2642
2696
  * carry for the call's one agent, so the phone draws it with the same seed. Absent when the
2643
2697
  * author is not an agent this account holds (unpaired since, or a person). */
2644
- agent: z11.object({ tokenId: z11.string(), name: z11.string(), voice: VoiceKeySchema.optional() }).optional(),
2698
+ agent: z12.object({ tokenId: z12.string(), name: z12.string(), voice: VoiceKeySchema.optional() }).optional(),
2645
2699
  /** ITS OPTIONS, WHEN THERE IS SOMETHING TO SEE (owner, 2026-09-25: "Yes, add it"): the options
2646
2700
  * its need offers, exactly as its own card carries them, present only when one of them has a
2647
2701
  * preview (`html` or `image`). The call screen opens them from the agenda row, so a preview is
2648
2702
  * never re-sent as a second card to be seen mid-call. Words-only options are `choices`. */
2649
- options: z11.array(OptionSchema).optional(),
2703
+ options: z12.array(OptionSchema).optional(),
2650
2704
  /** ITS OPTIONS WHEN THEY ARE WORDS (owner, 2026-10-02, on a call: "whenever there are pre-made
2651
2705
  * options … now for a checklist, we should also show them on the screen"; design C, 2026-10-08):
2652
2706
  * numbered chips above the call's controls, so a checklist is never only something read aloud. A
2653
2707
  * field of its own so `options` keeps meaning "previews": a phone on an older bundle opens the
2654
2708
  * preview layout for any `options`, and must see exactly what it did. */
2655
- choices: z11.array(OptionSchema).optional(),
2709
+ choices: z12.array(OptionSchema).optional(),
2656
2710
  /** HOW MANY MAY BE PICKED, beside its `choices`: one, any (`many`) or an order (`rank`). */
2657
- select: z11.enum(["one", "many", "rank"]).optional()
2711
+ select: z12.enum(["one", "many", "rank"]).optional()
2658
2712
  });
2659
- var InboxItemSchema = z11.object({
2660
- id: z11.string(),
2661
- tokenId: z11.string().optional(),
2713
+ var InboxItemSchema = z12.object({
2714
+ id: z12.string(),
2715
+ tokenId: z12.string().optional(),
2662
2716
  status: NotifyStatusSchema,
2663
2717
  context: ContextSchema,
2664
- options: z11.array(OptionSchema).optional(),
2718
+ options: z12.array(OptionSchema).optional(),
2665
2719
  /** The ask's declared coverage points (#396), when the agent sent them. */
2666
- points: z11.array(z11.string()).optional(),
2720
+ points: z12.array(z12.string()).optional(),
2667
2721
  /** Does this claim want an ANSWER, or is it telling you something? Written per row from
2668
2722
  * `requestAsks` — the agent's own declaration, not a guess. `false` is what earns a card
2669
2723
  * its acknowledge affordance: without it a status update offers a text box and a dismiss,
2670
2724
  * and neither of those is "got it" (owner, 2026-08-10). */
2671
- asks: z11.boolean().optional(),
2725
+ asks: z12.boolean().optional(),
2672
2726
  /** When a live process last pulsed for this row's agent — the liveness input for
2673
2727
  * "working requires a pulse" (#928): the list said "Working…" from agent_state alone
2674
2728
  * while the party called the same dead claim stalled. Absent = no token/no data,
2675
2729
  * which must never CLAIM stalled. */
2676
- lastSeenAt: z11.string().optional(),
2730
+ lastSeenAt: z12.string().optional(),
2677
2731
  /** WHEN THE AGENT LAST SAID ANYTHING ABOUT THIS CLAIM — the newest `agent_state` row in
2678
2732
  * the `notification_events` ledger (trigger-written since 20260621010000, so every row a
2679
2733
  * user can see has one). The age input for `CLAIM_STALE_MS`, and it has to be this rather
@@ -2683,7 +2737,7 @@ var InboxItemSchema = z11.object({
2683
2737
  * work. Reading the row's birth as the claim's age brands that "No update in 8h" the
2684
2738
  * instant the agent picks it up (#997). Absent = pre-trigger row; fall back to
2685
2739
  * `createdAt`. */
2686
- agentStateAt: z11.string().datetime().optional(),
2740
+ agentStateAt: z12.string().datetime().optional(),
2687
2741
  /** THE QUESTIONS A CALL CARRIES — the call screen's agenda spine (docs/clients/app/walk/design.md §11, owner
2688
2742
  * 2026-09-22). One per DecisionNeed on the Call, in the Call's order, answered or open (a
2689
2743
  * superseded or cancelled need is no longer a question anyone is asked). Present only on a
@@ -2697,40 +2751,40 @@ var InboxItemSchema = z11.object({
2697
2751
  * `turn` topic (`asking`, `settled`), because the bot never sees a DecisionNeed id. `title` is
2698
2752
  * the card's own concise heading; `answer` the accepted answer in words, null while open. It
2699
2753
  * REPLACED `agenda` (turns), which nothing ever filled. */
2700
- questions: z11.array(CallQuestionSchema).optional(),
2754
+ questions: z12.array(CallQuestionSchema).optional(),
2701
2755
  /** The same call carrying order, including request Entries with no DecisionNeed as reports.
2702
2756
  * Additive: questions stays decision-only for every other surface and older bundles. */
2703
- callItems: z11.array(CallQuestionSchema.extend({ state: z11.enum(["open", "answered", "report"]) })).optional(),
2704
- visuals: z11.array(VisualSchema).optional(),
2757
+ callItems: z12.array(CallQuestionSchema.extend({ state: z12.enum(["open", "answered", "report"]), acknowledged: z12.boolean().optional() })).optional(),
2758
+ visuals: z12.array(VisualSchema).optional(),
2705
2759
  /** The connected agent's name (the single pairing name — user-typed, or the
2706
2760
  * agent's suggestion, or a default silly name). */
2707
- name: z11.string(),
2761
+ name: z12.string(),
2708
2762
  /** The pairing's assigned voice (#462); absent = the default voice. */
2709
2763
  voice: VoiceKeySchema.optional(),
2710
- repo: z11.string().optional(),
2711
- branch: z11.string().optional(),
2712
- createdAt: z11.string().datetime(),
2713
- snoozedUntil: z11.string().datetime().optional(),
2764
+ repo: z12.string().optional(),
2765
+ branch: z12.string().optional(),
2766
+ createdAt: z12.string().datetime(),
2767
+ snoozedUntil: z12.string().datetime().optional(),
2714
2768
  agentState: AgentStateSchema.default("idle"),
2715
2769
  /** Whose action the item is waiting on: "you" = an agent asked you (the default,
2716
2770
  * every agent→user notification); "agent" = you sent a request and it's awaiting the
2717
2771
  * agent (held in the inbox until the agent replies on the thread). */
2718
- turn: z11.enum(["you", "agent"]).default("you"),
2772
+ turn: z12.enum(["you", "agent"]).default("you"),
2719
2773
  /** Hard error reason on an awaiting request (turn="agent") — the wake failed to reach
2720
2774
  * the agent (provider-agnostic; set server-side). Absent = no hard error. Drives the inbox
2721
2775
  * error badge + Retry. */
2722
- error: z11.string().optional(),
2776
+ error: z12.string().optional(),
2723
2777
  /** WHEN THIS AGENT WORK WENT QUIET (turn="agent"), by the one rule (`coldSince`: three days
2724
2778
  * with nothing said), or absent while it is not stalled. The inbox's stalled badge reads
2725
2779
  * this and nothing else (2026-09-23: a 3-minute age rule badged every live Goal stalled,
2726
2780
  * and "dismiss the stalled ones" cancelled 37 pieces of live work). */
2727
- cold: z11.string().datetime().optional(),
2728
- clarifies: z11.string().optional(),
2781
+ cold: z12.string().datetime().optional(),
2782
+ clarifies: z12.string().optional(),
2729
2783
  /** THIS CARD'S QUESTION IS ON A LIVE CALL (owner, 2026-09-24: "Mark it while the call is
2730
2784
  * live"). Present only while an open Call Delivery carries the card's request Entry — read
2731
2785
  * off the same open list the card came from, so it clears when the Call does. A card is the
2732
2786
  * backup for a call not taken; while the call has it, the call is where it is answered. */
2733
- onCall: z11.literal(true).optional(),
2787
+ onCall: z12.literal(true).optional(),
2734
2788
  /** THE RING, ON THE ITEM (docs/clients/app/walk/design.md §12 §17, #2251): the last ring on this card was
2735
2789
  * declined, and what the ladder will do next — read off the cron's own row, never computed
2736
2790
  * on the phone. Present only while a `declined` receipt stands on the card's last Call.
@@ -2740,31 +2794,52 @@ var InboxItemSchema = z11.object({
2740
2794
  * It replaced `gaveUp` (deleted 2026-09-22): "the ladder spent" was a boolean the projection
2741
2795
  * never set, and it is `nextRingAt === null` here — the party's *Missed you* (`party/dress.ts`)
2742
2796
  * and the roster's `unreached` read `declinedAt`, and stand while it does. */
2743
- ring: z11.object({
2744
- declinedAt: z11.string().datetime(),
2745
- anchorAt: z11.string().datetime(),
2746
- nextRingAt: z11.string().datetime().nullable(),
2747
- step: z11.number().int()
2797
+ ring: z12.object({
2798
+ declinedAt: z12.string().datetime(),
2799
+ anchorAt: z12.string().datetime(),
2800
+ nextRingAt: z12.string().datetime().nullable(),
2801
+ step: z12.number().int()
2748
2802
  }).optional(),
2749
2803
  /** Why this arrived the way it did, read back off the delivery receipt (`notify/why.ts`).
2750
2804
  * Absent for anything never delivered through a push, and for older rows written before
2751
2805
  * the reason was recorded. Deliberately a debug affordance, shown small (owner,
2752
2806
  * 2026-08-07) — its real job is to give "this didn't need a call" something to be
2753
2807
  * feedback ABOUT. */
2754
- why: z11.object({
2808
+ why: z12.object({
2755
2809
  asked: NotifyLevelSchema,
2756
2810
  got: NotifyLevelSchema,
2757
- because: z11.enum(["unresponsive", "dismissed", "not_permitted", "silent", "coalesced", "agent_capped", "unplanned", "learned_raise"]).optional(),
2758
- line: z11.string()
2811
+ because: z12.enum(["unresponsive", "dismissed", "not_permitted", "silent", "coalesced", "agent_capped", "unplanned", "learned_raise"]).optional(),
2812
+ line: z12.string()
2759
2813
  }).optional(),
2760
- select: z11.enum(["one", "many", "rank", "confirm", "text"]).default("one"),
2761
- confirmStyle: z11.enum(["yesno", "approve"]).default("yesno").describe(
2814
+ select: z12.enum(["one", "many", "rank", "confirm", "text"]).default("one"),
2815
+ confirmStyle: z12.enum(["yesno", "approve"]).default("yesno").describe(
2762
2816
  "Labels for a select:'confirm' paige \u2014 'yesno' (Yes/No) or 'approve' (Approve/Deny). Ignored unless select is 'confirm'."
2763
2817
  ),
2764
2818
  /** Real downstream work is stuck behind this one — set by the agent, independent of
2765
- * urgency (see the main README's "premier use case" + docs/delivery/notify/states.md). Drives the
2819
+ * urgency (see the main README's "premier use case" + docs/history/notify-states.md). Drives the
2766
2820
  * inbox's blocking badge and the extra confirm step before dismissing it. */
2767
- blocking: z11.boolean().default(false),
2821
+ blocking: z12.boolean().default(false),
2822
+ /** WHAT FREED THIS QUESTION (owner, 2026-10-16, Goal 2383ef14: "we don't really show the question
2823
+ * at the top until the question it could reply to with is resolved. And then we show it again
2824
+ * with the context of the other thing that was resolved"; asked how it should carry that, "The
2825
+ * answer above it"). A question they answered with a question of their own waits for theirs
2826
+ * (`private.ask_back`) and drops out of the front while it waits; when it comes back, the card
2827
+ * draws their question and the answer it got ABOVE the ask, as one card. Absent on a question
2828
+ * nothing ever held back. */
2829
+ freedBy: z12.object({
2830
+ questionId: z12.string(),
2831
+ asked: z12.string(),
2832
+ answer: z12.string(),
2833
+ answeredAt: z12.string(),
2834
+ /** The answer in ten words, when the talker wrote one beside it. */
2835
+ summary: z12.string().optional()
2836
+ }).optional(),
2837
+ /** WHAT THIS CARD ANSWERS (owner, 2026-10-27, Goal 81b6a9d6: "this reads very clearly as an answer to
2838
+ * something I asked, but I don't see the question… To show the question near the top of the card").
2839
+ * An agent's card that is its answer to one of the person's own questions carries that question's
2840
+ * words, drawn above it as "You asked" (`public.questions_answered_by`, read beside the card read).
2841
+ * Absent on every card that answers nothing of theirs, and on a held question, which has `freedBy`. */
2842
+ answering: z12.object({ asked: z12.string() }).optional(),
2768
2843
  /** The user's locked-in answer; present only for replied items (GET /api/replied/:id). */
2769
2844
  answer: UserAnswerSchema.optional(),
2770
2845
  /** THE TARGET FACTS A CARD RENDERS (#1796 point 5, 2026-09-11): the Delivery it is a view of,
@@ -2772,17 +2847,17 @@ var InboxItemSchema = z11.object({
2772
2847
  * for a request that asks nothing), whether its content is sealed, and that Goal's state. The
2773
2848
  * answer writer (`POST /api/entries`) and the disposition (`close_delivery`) take their ids from
2774
2849
  * here. The server projects it (`apps/api/src/inbox/project.ts`); a client never builds it. */
2775
- communication: z11.object({
2776
- deliveryId: z11.string(),
2777
- kind: z11.enum(["notification", "call"]),
2778
- entryId: z11.string(),
2779
- goalIds: z11.array(z11.string()),
2780
- decisionNeedId: z11.string().optional(),
2781
- sealed: z11.boolean(),
2782
- goalState: z11.string().optional(),
2850
+ communication: z12.object({
2851
+ deliveryId: z12.string(),
2852
+ kind: z12.enum(["notification", "call"]),
2853
+ entryId: z12.string(),
2854
+ goalIds: z12.array(z12.string()),
2855
+ decisionNeedId: z12.string().optional(),
2856
+ sealed: z12.boolean(),
2857
+ goalState: z12.string().optional(),
2783
2858
  /** THAT GOAL'S NAME (#2416) — what Activity's row is headed by, since a row there is one Goal
2784
2859
  * and the cards it holds sit behind it. Stamped by the same read as `goalState`. */
2785
- goalTitle: z11.string().optional()
2860
+ goalTitle: z12.string().optional()
2786
2861
  }).optional(),
2787
2862
  /** WHAT THIS CARD IS, IN TWELVE CHARACTERS (#3019) — the hash of every other field on it, stamped
2788
2863
  * by the one read that serves the open list (`apps/api/src/inbox/project.ts` `inboxFor`). It is
@@ -2794,27 +2869,27 @@ var InboxItemSchema = z11.object({
2794
2869
  * own moves (its Goal's state and name, how cold the work behind it has gone, whether a ring is
2795
2870
  * live). Optional, so a fixture, the demo and the archive lens need not spell one, and a card
2796
2871
  * with no rev is simply always re-sent. */
2797
- rev: z11.string().optional()
2872
+ rev: z12.string().optional()
2798
2873
  });
2799
2874
  var APNS_TOKEN_RE = /^[0-9a-fA-F]{64}$/;
2800
- var PushTokenSchema = z11.object({
2801
- voipToken: z11.string().min(1).optional(),
2802
- alertToken: z11.string().min(1).optional(),
2803
- fcmToken: z11.string().min(1).optional(),
2804
- platform: z11.enum(["ios", "android"])
2875
+ var PushTokenSchema = z12.object({
2876
+ voipToken: z12.string().min(1).optional(),
2877
+ alertToken: z12.string().min(1).optional(),
2878
+ fcmToken: z12.string().min(1).optional(),
2879
+ platform: z12.enum(["ios", "android"])
2805
2880
  }).superRefine((v, ctx) => {
2806
2881
  if (v.platform !== "ios") return;
2807
2882
  for (const field of ["voipToken", "alertToken"]) {
2808
2883
  const token = v[field];
2809
2884
  if (token === void 0 || APNS_TOKEN_RE.test(token)) continue;
2810
2885
  ctx.addIssue({
2811
- code: z11.ZodIssueCode.custom,
2886
+ code: z12.ZodIssueCode.custom,
2812
2887
  path: [field],
2813
2888
  message: `not an APNs device token (want 64 hex chars, got ${token.length})`
2814
2889
  });
2815
2890
  }
2816
2891
  });
2817
- var MissedCallSchema = z11.enum([
2892
+ var MissedCallSchema = z12.enum([
2818
2893
  "retry_10m",
2819
2894
  "retry_30m",
2820
2895
  "retry_60m",
@@ -2826,31 +2901,32 @@ var MissedCallSchema = z11.enum([
2826
2901
  ]);
2827
2902
  var clock = (h) => h === 0 ? "midnight" : h === 12 ? "noon" : h < 12 ? `${h} am` : `${h - 12} pm`;
2828
2903
  var QUIET = ` Nothing rings from ${clock(NIGHT.from)} to ${clock(NIGHT.to)} your time; the count waits for morning.`;
2829
- var BrokerTuningSchema = z11.object({
2904
+ var THEIR_QUIET = ` Nothing rings from ${clock(NIGHT.from)} to ${clock(NIGHT.to)} their time; the count waits for morning.`;
2905
+ var BrokerTuningSchema = z12.object({
2830
2906
  /** 'none' = skip the spoken ack after a mapped answer (power users find it slow). */
2831
- ackVerbosity: z11.enum(["normal", "none"]).optional(),
2907
+ ackVerbosity: z12.enum(["normal", "none"]).optional(),
2832
2908
  /** How readily the mapper asks its one clarification: 'low' = only when truly
2833
2909
  * uninterpretable, 'high' = whenever not fully certain. */
2834
- clarifyEagerness: z11.enum(["low", "normal", "high"]).optional(),
2910
+ clarifyEagerness: z12.enum(["low", "normal", "high"]).optional(),
2835
2911
  /** The user's own shorthand: when they say `say`, they mean `mean`. */
2836
- phrasebook: z11.array(z11.object({ say: z11.string().min(1).max(60), mean: z11.string().min(1).max(120) })).max(24).optional(),
2912
+ phrasebook: z12.array(z12.object({ say: z12.string().min(1).max(60), mean: z12.string().min(1).max(120) })).max(24).optional(),
2837
2913
  /** The language calls are PLANNED in, when the account has chosen one (#1272). Absent —
2838
2914
  * which is every account today — means the agent's own words decide, per ask: a call
2839
2915
  * about an English ask opens in English. This is the only thing that overrides that,
2840
2916
  * and a live caller who switches language mid-call still outranks it (broker/lang.ts).
2841
2917
  * Set per user (no UI yet), like `voiceTuning`. */
2842
- language: z11.enum(["en", "es"]).optional()
2918
+ language: z12.enum(["en", "es"]).optional()
2843
2919
  });
2844
- var UserSettingsSchema = z11.object({
2845
- permissions: z11.object({
2846
- call: z11.boolean(),
2847
- banner: z11.boolean(),
2848
- push: z11.boolean()
2920
+ var UserSettingsSchema = z12.object({
2921
+ permissions: z12.object({
2922
+ call: z12.boolean(),
2923
+ banner: z12.boolean(),
2924
+ push: z12.boolean()
2849
2925
  }),
2850
2926
  /** LockedIn / Default / DateNight on screen; the stored words are unchanged on purpose —
2851
2927
  * they are an enum on a live column across every account, and the rename is a rename of
2852
2928
  * what people read (owner, 2026-09-30). */
2853
- sessionMode: z11.enum(["default", "all_calls", "silent"]),
2929
+ sessionMode: z12.enum(["default", "all_calls", "silent"]),
2854
2930
  /** `silentPush` lived here until #2813 and is now GONE, field and column both. It was kept as an
2855
2931
  * optional long after DateNight stopped reading it, on the theory that a phone on an older
2856
2932
  * bundle PATCHing the whole settings object would be REFUSED for sending a key we had stopped
@@ -2859,7 +2935,7 @@ var UserSettingsSchema = z11.object({
2859
2935
  * an old bundle's `silentPush` is accepted and ignored. Worth remembering before keeping the
2860
2936
  * next dead field for the same reason. */
2861
2937
  /** Opt-in (default false) to using your content to improve Paigy and train models. */
2862
- improveConsent: z11.boolean(),
2938
+ improveConsent: z12.boolean(),
2863
2939
  missedCall: MissedCallSchema.default("backoff_standard"),
2864
2940
  /** Where voice audio is processed. 'hosted' (default) = Paigy's voice services
2865
2941
  * (ElevenLabs TTS, faster-whisper STT, the call bot); 'on_device' = the phone
@@ -2867,17 +2943,17 @@ var UserSettingsSchema = z11.object({
2867
2943
  * Optional, NOT defaulted: a stale client PATCHing the full settings object
2868
2944
  * must not silently reset this privacy choice. Absent = leave unchanged on
2869
2945
  * write, 'hosted' on read (see store.ts). */
2870
- voiceMode: z11.enum(["hosted", "on_device"]).optional(),
2946
+ voiceMode: z12.enum(["hosted", "on_device"]).optional(),
2871
2947
  /** Talk — after you answer, the next step is read aloud (docs/clients/app/walk/design.md §6). ALWAYS ON until
2872
2948
  * turned off (owner, 2026-09-18, #2249): a setting, not a per-walk toggle. Optional, NOT
2873
2949
  * defaulted, for the same reason `voiceMode` is: a stale client PATCHing the full settings
2874
2950
  * object must not silently turn it back on. Absent = leave unchanged on write, true on
2875
2951
  * read (see store.ts). */
2876
- talk: z11.boolean().optional(),
2952
+ talk: z12.boolean().optional(),
2877
2953
  /** CALL DIAGNOSTICS (owner, 2026-10-01): the call report carries each listen and the bot's own
2878
2954
  * load timings. SERVER-SET, no UI — on for every account that existed on 2026-10-01, off for
2879
2955
  * newer ones (migration 20261001132859). Read-only here: the settings PATCH never writes it. */
2880
- callDiagnostics: z11.boolean().optional(),
2956
+ callDiagnostics: z12.boolean().optional(),
2881
2957
  /** Per-user ring budget (#603): calls per rolling day before further calls
2882
2958
  * degrade to banner. Absent = the global default (25). A number, never a
2883
2959
  * bypass — every account keeps a ceiling. No UI; set per user for testing. */
@@ -2885,7 +2961,7 @@ var UserSettingsSchema = z11.object({
2885
2961
  * payload['tuning'] (e.g. { silence_s: 3.5 } — a longer pause window for a
2886
2962
  * slower speaker). No API-side semantics; the bot resolves each key with its
2887
2963
  * own defaults. Set per user (no UI yet); absent = bot defaults. */
2888
- voiceTuning: z11.record(z11.string(), z11.union([z11.number(), z11.string()])).optional(),
2964
+ voiceTuning: z12.record(z12.string(), z12.union([z12.number(), z12.string()])).optional(),
2889
2965
  /** The user's IANA timezone (e.g. "America/Bogota"), recorded by the app — it is the
2890
2966
  * only party that knows it. REMINDERS are why it exists: "remind me at ten" becomes
2891
2967
  * an absolute `due_at` only if we know whose ten. Optional and never defaulted, for
@@ -2894,108 +2970,109 @@ var UserSettingsSchema = z11.object({
2894
2970
  * that failure reads as the reminder rail being unreliable rather than as a missing
2895
2971
  * setting. Absent = a spoken time can't be landed, so the reminder rides the next
2896
2972
  * call — honest about what we know. */
2897
- timezone: z11.string().min(1).max(64).optional(),
2973
+ timezone: z12.string().min(1).max(64).optional(),
2898
2974
  /** Rung-2 broker tuning (#381). Optional and NOT defaulted, same stale-client
2899
2975
  * clobber guard as voiceMode: absent = leave unchanged on write. */
2900
2976
  broker: BrokerTuningSchema.optional()
2901
2977
  });
2902
- var GoalLatestSchema = z11.object({
2903
- from: z11.enum(["person", "agent"]),
2904
- said: z11.string(),
2905
- at: z11.string(),
2906
- entryId: z11.string(),
2978
+ var GoalLatestSchema = z12.object({
2979
+ from: z12.enum(["person", "agent"]),
2980
+ said: z12.string(),
2981
+ at: z12.string(),
2982
+ entryId: z12.string(),
2907
2983
  /** ITS SUMMARY IN AT MOST TEN WORDS (owner, 2026-10-08: "the same switch to the more summarized sources
2908
2984
  * at the work tab top level screen too"): what the talker or filer wrote on the Entry; absent when
2909
2985
  * none was. The Work row reads it before `said`. */
2910
- summary: z11.string().optional(),
2986
+ summary: z12.string().optional(),
2911
2987
  /** AN AGENT'S UPDATE OR QUESTION AS ITS UNITS' TITLES (owner, 2026-10-08: "send the 50 chars from the title
2912
2988
  * of each unit"): each at most 50 characters, in order; absent when it has none. */
2913
- titles: z11.array(z11.string()).optional(),
2989
+ titles: z12.array(z12.string()).optional(),
2914
2990
  /** A PROGRESS NOTE'S ONE POINT ("An agent's progress note -> maybe let's cap it at 200 chars"): the
2915
2991
  * update's own line, before its units; the row caps it at 200. Absent on anything else. */
2916
- line: z11.string().optional()
2992
+ line: z12.string().optional()
2917
2993
  });
2918
- var HistoryWorkSchema = z11.object({
2919
- id: z11.string(),
2920
- title: z11.string(),
2921
- state: z11.enum(["done", "cancelled"]),
2994
+ var HistoryWorkSchema = z12.object({
2995
+ id: z12.string(),
2996
+ title: z12.string(),
2997
+ state: z12.enum(["done", "cancelled"]),
2922
2998
  /** Who held it (`agent:<tokenId>` or `human:<userId>`). */
2923
- assignee: z11.string(),
2999
+ assignee: z12.string(),
2924
3000
  latest: GoalLatestSchema.nullable().optional()
2925
3001
  });
2926
- var HistoryEntrySchema = z11.union([
2927
- z11.object({ at: z11.string(), card: InboxItemSchema }),
2928
- z11.object({ at: z11.string(), work: HistoryWorkSchema })
3002
+ var HistoryEntrySchema = z12.union([
3003
+ z12.object({ at: z12.string(), card: InboxItemSchema }),
3004
+ z12.object({ at: z12.string(), work: HistoryWorkSchema })
2929
3005
  ]);
2930
- var HistoryPageSchema = z11.object({
2931
- entries: z11.array(HistoryEntrySchema),
2932
- next: z11.string().nullable()
3006
+ var HistoryPageSchema = z12.object({
3007
+ entries: z12.array(HistoryEntrySchema),
3008
+ next: z12.string().nullable()
2933
3009
  });
2934
3010
  var ACTIVITY_LINES = 2;
2935
3011
  var ACTIVITY_LINE_MAX = 80;
2936
- var AgentActivitySchema = z11.object({
3012
+ var AgentActivitySchema = z12.object({
2937
3013
  /** Oldest first, so the newest line is last — the one that replaces in place. */
2938
- lines: z11.array(z11.string().max(ACTIVITY_LINE_MAX)).max(ACTIVITY_LINES),
3014
+ lines: z12.array(z12.string().max(ACTIVITY_LINE_MAX)).max(ACTIVITY_LINES),
2939
3015
  /** When the harness observed this tail. Its own timestamp, not the heartbeat's: a beat
2940
3016
  * that carries an UNCHANGED tail must not make a stalled agent look like it just moved. */
2941
- at: z11.string().datetime()
3017
+ at: z12.string().datetime()
2942
3018
  });
2943
- var ConnectionSummarySchema = z11.object({
3019
+ var ConnectionSummarySchema = z12.object({
2944
3020
  /** The connection = the agent's token id (used to address a request). */
2945
- id: z11.string(),
3021
+ id: z12.string(),
2946
3022
  /** The credential kind: "device" = a paired machine (mint-only — it hosts and mints, it
2947
3023
  * never talks); "agent" = an identity that sends. The roster and devices surfaces split
2948
3024
  * on this. Optional/absent reads as "agent" (a row predating the kind column). See
2949
3025
  * docs/server/tokens/devices-vs-agents-design.md. */
2950
- kind: z11.enum(["device", "agent"]).optional(),
3026
+ kind: z12.enum(["device", "agent"]).optional(),
2951
3027
  /** For an agent, the token id of the DEVICE that minted it — so agents group under their
2952
3028
  * machine, and revoking a device cascades to them. Null on devices, and on unlinked
2953
- * agents (phone-launched, provider-managed, or minted before the link existed). */
2954
- mintedByDevice: z11.string().nullable().optional(),
2955
- device: z11.string().nullable(),
3029
+ * agents (provider-managed, hatched by another agent, or minted before the link existed);
3030
+ * a phone-launched agent is linked to the computer it runs on since #1602. */
3031
+ mintedByDevice: z12.string().nullable().optional(),
3032
+ device: z12.string().nullable(),
2956
3033
  /** The agent's display name (the single pairing name). */
2957
- name: z11.string(),
3034
+ name: z12.string(),
2958
3035
  /** For a managed connection, the provider key (e.g. "cma") that agentOrigin maps to a
2959
3036
  * label; null for a local connection. Sourced from the token's provider, not the name. */
2960
- provider: z11.string().nullable(),
3037
+ provider: z12.string().nullable(),
2961
3038
  /** The pairing's assigned voice (#462); null = the default voice. */
2962
3039
  voice: VoiceKeySchema.nullable(),
2963
3040
  /** The LOUDEST this agent may ever reach you — a ceiling on `NOTIFY_LADDER`, set by the
2964
3041
  * user on the agent's own page. null = no ceiling (today's behaviour for every
2965
3042
  * connection). Android binds importance to a relationship rather than to each message,
2966
3043
  * and that is the thing our roster could not say: "Marlow may always call me; Otto
2967
- * never may" (docs/clients/app/party/navigation-design.md, gap 2). Clamped in `arbitrateLevel`, so it binds
3044
+ * never may" (docs/history/party-navigation-design.md, gap 2). Clamped in `arbitrateLevel`, so it binds
2968
3045
  * every surface at once and outranks even `sessionMode: all_calls` — a mode the user
2969
3046
  * set once must not overrule a rule they set about one agent. */
2970
3047
  reach: NotifyLevelSchema.nullable().optional(),
2971
- createdAt: z11.string().datetime(),
3048
+ createdAt: z12.string().datetime(),
2972
3049
  /** Most recent notification on this connection, either direction. Null = no contact yet.
2973
3050
  * Drives the agents-page recency grouping (Today / This week / …). */
2974
- lastContactAt: z11.string().datetime().nullable(),
3051
+ lastContactAt: z12.string().datetime().nullable(),
2975
3052
  /** Last presence heartbeat from a running agent process (POST /api/presence) — the
2976
3053
  * desktop app while open. Null = never seen; stale = offline. */
2977
- lastSeenAt: z11.string().datetime().nullable().optional(),
3054
+ lastSeenAt: z12.string().datetime().nullable().optional(),
2978
3055
  /** WORKING, NOT JUST CONNECTED (owner, 2026-09-30): the last time the agent itself acted on one of
2979
3056
  * its Goals — wrote on one or recorded an operation (`tokens.last_worked_at`). Within
2980
3057
  * `WORKING_MS` it is working; otherwise it is connected but idle. Null = not seen working yet. */
2981
- lastWorkedAt: z11.string().datetime().nullable().optional(),
3058
+ lastWorkedAt: z12.string().datetime().nullable().optional(),
2982
3059
  /** The oldest of its Goals that is `ready` for it — work handed to it that nobody has started.
2983
3060
  * With no work of its own for `WORKING_MS`, an agent sitting on this is not taking its work. */
2984
- oldestReadyAt: z11.string().datetime().nullable().optional(),
3061
+ oldestReadyAt: z12.string().datetime().nullable().optional(),
2985
3062
  /** What a live desktop can run (docs/clients/desktop/companion.md §2.2), advertised on its heartbeat:
2986
3063
  * harness availabilities + granted workspaces — the option set the phone's
2987
3064
  * "new session" sheet offers. Absent for ordinary MCP agents. */
2988
- runtime: z11.object({
3065
+ runtime: z12.object({
2989
3066
  /** The @paigy/harness this host is running — a machine the self-update has not reached
2990
3067
  * shows its age here (`apps/desktop/src/update.ts`). */
2991
- version: z11.string().optional(),
2992
- harnesses: z11.array(z11.object({ name: z11.string(), label: z11.string(), status: z11.string(), models: z11.array(z11.string()).optional() })).optional(),
2993
- workspaces: z11.array(z11.string()).optional(),
3068
+ version: z12.string().optional(),
3069
+ harnesses: z12.array(z12.object({ name: z12.string(), label: z12.string(), status: z12.string(), models: z12.array(z12.string()).optional() })).optional(),
3070
+ workspaces: z12.array(z12.string()).optional(),
2994
3071
  /** THE GIT REPOS IN THOSE FOLDERS (2026-10-01, Goal 26982211): each granted folder that is a
2995
3072
  * repo, and each repo directly inside one, with its `origin` remote. A session started for
2996
3073
  * work on `mauurda/paigy` opens in that repo rather than the folder above it, where the repo's
2997
3074
  * own AGENTS.md is never read (`workspaceForRepo`). Absent on hosts that predate it. */
2998
- repos: z11.array(z11.object({ path: z11.string(), remote: z11.string() })).optional()
3075
+ repos: z12.array(z12.object({ path: z12.string(), remote: z12.string() })).optional()
2999
3076
  }).optional(),
3000
3077
  /** The tail of this agent's working log, when a harness is driving it — the agent page's
3001
3078
  * live strip. Absent for anything the desktop harness isn't running (a hatched identity
@@ -3004,145 +3081,151 @@ var ConnectionSummarySchema = z11.object({
3004
3081
  activity: AgentActivitySchema.optional(),
3005
3082
  /** True = a provider-managed agent running in the provider's cloud (e.g. Anthropic CMA);
3006
3083
  * false = a local MCP connection running on the user's computer (Claude Code/Codex/…). */
3007
- managed: z11.boolean()
3084
+ managed: z12.boolean()
3008
3085
  });
3009
- var LedgerItemSchema = z11.object({ id: z11.string(), parentId: z11.string(), title: z11.string(), createdAt: z11.string() });
3010
- var AgentLedgerSchema = z11.object({
3086
+ var LedgerItemSchema = z12.object({ id: z12.string(), parentId: z12.string(), title: z12.string(), createdAt: z12.string() });
3087
+ var AgentLedgerSchema = z12.object({
3011
3088
  /** Null when the agent has not named itself yet — never a placeholder (owner, 2026-10-01). */
3012
- agent: z11.object({ id: z11.string(), name: z11.string().nullable(), revokedAt: z11.string().nullable() }),
3089
+ agent: z12.object({ id: z12.string(), name: z12.string().nullable(), revokedAt: z12.string().nullable() }),
3013
3090
  /** Its own questions you have not answered. */
3014
- asks: z11.array(LedgerItemSchema),
3091
+ asks: z12.array(LedgerItemSchema),
3015
3092
  /** Its questions you answered that nobody acted on — still owed to somebody. */
3016
- answered: z11.array(LedgerItemSchema),
3093
+ answered: z12.array(LedgerItemSchema),
3017
3094
  /** Requests you sent it that it never took. */
3018
- requests: z11.array(LedgerItemSchema),
3019
- goals: z11.array(z11.object({ id: z11.string(), outcome: z11.string(), state: z11.string() })),
3020
- callbacks: z11.array(z11.object({ id: z11.string(), parentId: z11.string(), trigger: z11.string(), note: z11.string(), dueAt: z11.string().nullable() }))
3095
+ requests: z12.array(LedgerItemSchema),
3096
+ goals: z12.array(z12.object({ id: z12.string(), outcome: z12.string(), state: z12.string() })),
3097
+ callbacks: z12.array(z12.object({ id: z12.string(), parentId: z12.string(), trigger: z12.string(), note: z12.string(), dueAt: z12.string().nullable() }))
3021
3098
  });
3022
- var ReassignResultSchema = z11.object({
3023
- moved: z11.object({ asks: z11.number(), answered: z11.number(), requests: z11.number(), goals: z11.number(), callbacks: z11.number() }),
3024
- parentId: z11.string().nullable()
3099
+ var ReassignResultSchema = z12.object({
3100
+ moved: z12.object({ asks: z12.number(), answered: z12.number(), requests: z12.number(), goals: z12.number(), callbacks: z12.number() }),
3101
+ parentId: z12.string().nullable()
3025
3102
  });
3026
- var LessonStateSchema = z11.enum(["active", "proposed", "retired"]);
3027
- var LessonViewSchema = z11.object({
3028
- id: z11.string(),
3029
- text: z11.string(),
3103
+ var LessonStateSchema = z12.enum(["active", "proposed", "retired"]);
3104
+ var LessonViewSchema = z12.object({
3105
+ id: z12.string(),
3106
+ text: z12.string(),
3030
3107
  state: LessonStateSchema,
3031
3108
  /** The Goal it is scoped to; null = the whole account. */
3032
- scopeGoalId: z11.string().nullable(),
3033
- goalTitle: z11.string().nullable(),
3034
- version: z11.number(),
3035
- pinned: z11.boolean(),
3109
+ scopeGoalId: z12.string().nullable(),
3110
+ goalTitle: z12.string().nullable(),
3111
+ version: z12.number(),
3112
+ pinned: z12.boolean(),
3036
3113
  /** When the person last wrote its text themselves. */
3037
- editedAt: z11.string().nullable(),
3038
- createdAt: z11.string(),
3039
- updatedAt: z11.string(),
3114
+ editedAt: z12.string().nullable(),
3115
+ createdAt: z12.string(),
3116
+ updatedAt: z12.string(),
3040
3117
  /** The Entries it came from, oldest first; `words` is null when an Entry has none to show (sealed). */
3041
- sources: z11.array(z11.object({ entryId: z11.string(), words: z11.string().nullable(), at: z11.string() }))
3118
+ sources: z12.array(z12.object({ entryId: z12.string(), words: z12.string().nullable(), at: z12.string() }))
3042
3119
  });
3043
- var QueueQuestionSchema = z11.object({
3120
+ var QueueQuestionSchema = z12.object({
3044
3121
  /** The decision need's id — what an answer is accepted against. */
3045
- id: z11.string(),
3122
+ id: z12.string(),
3046
3123
  /** The words that were asked, from the request Entry that asked them. */
3047
- question: z11.string(),
3124
+ question: z12.string(),
3048
3125
  /** Where it was asked — which is where the ruling goes (`POST /api/entries`). Null only
3049
3126
  * for a need whose request Entry is carried by no interactive Delivery, which nothing
3050
3127
  * can answer. */
3051
- deliveryId: z11.string().nullable().default(null),
3128
+ deliveryId: z12.string().nullable().default(null),
3052
3129
  /** The Entry the ruling is about. */
3053
- aboutId: z11.string().nullable().default(null),
3130
+ aboutId: z12.string().nullable().default(null),
3054
3131
  /** Empty for a free-text question. */
3055
- options: z11.array(OptionSchema).default([]),
3056
- select: z11.enum(["one", "many", "rank", "confirm", "text"]).default("text"),
3057
- askedAt: z11.string(),
3132
+ options: z12.array(OptionSchema).default([]),
3133
+ select: z12.enum(["one", "many", "rank", "confirm", "text"]).default("text"),
3134
+ askedAt: z12.string(),
3058
3135
  /** Null while the question is open — which is how the page tells the two apart. */
3059
- answeredAt: z11.string().nullable().default(null),
3136
+ answeredAt: z12.string().nullable().default(null),
3060
3137
  /** The ruling in the person's own words, from the contribution that replied — not the
3061
3138
  * option id, which is not something anyone reads back. Null while it is open, and null
3062
3139
  * for a settled question whose reply carried nothing readable. */
3063
- answer: z11.string().nullable().default(null),
3140
+ answer: z12.string().nullable().default(null),
3064
3141
  /** The Goal this question belongs to — a step knows its Goal on its own, not only through
3065
3142
  * an `InboxItem`'s `communication.goalIds[0]` (docs/clients/app/walk/design.md §12 item 3).
3066
3143
  * READ BY `apps/client/src/walk/order.ts`, which stamps it onto every `WalkStep`: the walk's
3067
3144
  * order, its route, home's trees and the list of steps all take a step's Goal from here, so
3068
3145
  * this is the field they agree through rather than each re-deriving it from the row it
3069
3146
  * arrived under. Required because the API projects it on every need it sends. */
3070
- goalId: z11.string(),
3147
+ goalId: z12.string(),
3071
3148
  /** True only while an unmet START gate holds the Goal — a Goal that merely waits to
3072
3149
  * *finish* does not stop a person from answering (owner, 2026-09-16: "per need gate from
3073
3150
  * the API"; §4's dashed node). Not the same fact as `QueueItem.blocked`, which counts any
3074
3151
  * gate at all. */
3075
- blocked: z11.boolean().default(false)
3152
+ blocked: z12.boolean().default(false)
3076
3153
  });
3077
- var QueueReplySchema = z11.object({
3154
+ var QueueReplySchema = z12.object({
3078
3155
  /** The card this note was (`deliveryId:requestEntryId`, minted by the server like every card
3079
3156
  * id) — so the phone can tell a reply it just sent from one the queue already carries, and the
3080
3157
  * walk can name it in its zoom. */
3081
- id: z11.string(),
3158
+ id: z12.string(),
3082
3159
  /** The Goal the note is on. */
3083
- goalId: z11.string(),
3160
+ goalId: z12.string(),
3084
3161
  /** What the note said. */
3085
- note: z11.string(),
3162
+ note: z12.string(),
3086
3163
  /** Where it was carried — where a second reply goes (`POST /api/entries`, #2252). */
3087
- deliveryId: z11.string(),
3088
- requestEntryId: z11.string(),
3089
- askedAt: z11.string(),
3164
+ deliveryId: z12.string(),
3165
+ requestEntryId: z12.string(),
3166
+ askedAt: z12.string(),
3090
3167
  /** When the person last replied — the window's start. */
3091
- repliedAt: z11.string(),
3168
+ repliedAt: z12.string(),
3092
3169
  /** The person's latest words about it; null when there is nothing readable in them. */
3093
- reply: z11.string().nullable()
3170
+ reply: z12.string().nullable()
3094
3171
  });
3095
- var QueueItemSchema = z11.object({
3096
- id: z11.string(),
3172
+ var QueueItemSchema = z12.object({
3173
+ id: z12.string(),
3097
3174
  /** One-line headline — the first sentence of the outcome. */
3098
- title: z11.string(),
3175
+ title: z12.string(),
3099
3176
  /** The outcome in full, verbatim: the person's own words are what an assignee sees. */
3100
- intent: z11.string(),
3177
+ intent: z12.string(),
3101
3178
  /** `ready` | `active` | `waiting` | `done` | `cancelled`, straight off the Goal. */
3102
- state: z11.string(),
3179
+ state: z12.string(),
3103
3180
  /** Who holds it (a participant ref); null when nobody does yet. */
3104
- assignee: z11.string().nullable().default(null),
3181
+ assignee: z12.string().nullable().default(null),
3105
3182
  /** What the agent last said it was doing; null if it has said nothing. */
3106
- progress: z11.string().nullable().default(null),
3183
+ progress: z12.string().nullable().default(null),
3107
3184
  /** HOME'S LINE FOR THAT NOTE (owner, 2026-09-23): a few plain words one read wrote from `progress`,
3108
3185
  * served only while it was written for the current note. Null means show the Goal's name. */
3109
- progressLine: z11.string().nullable().optional(),
3110
- reviewPending: z11.boolean().default(false),
3111
- dueAt: z11.string().nullable().default(null),
3186
+ progressLine: z12.string().nullable().optional(),
3187
+ reviewPending: z12.boolean().default(false),
3188
+ dueAt: z12.string().nullable().default(null),
3112
3189
  /** WHEN ITS OWNER SAID DONE WHILE CHILDREN WERE OPEN (#2704): its own work is finished and it closes
3113
3190
  * with its last open child. Null otherwise; optional, so hand-built queues need not spell it. */
3114
- finishedAt: z11.string().nullable().optional(),
3191
+ finishedAt: z12.string().nullable().optional(),
3115
3192
  /** The Goal this one was opened under; null at the root. */
3116
- parentGoalId: z11.string().nullable().default(null),
3193
+ parentGoalId: z12.string().nullable().default(null),
3117
3194
  /** Goals opened under this one — only those the same list holds. */
3118
- childGoalIds: z11.array(z11.string()).default([]),
3195
+ childGoalIds: z12.array(z12.string()).default([]),
3119
3196
  /** Goals this one waits on (start or finish gates). */
3120
- dependencyGoalIds: z11.array(z11.string()).default([]),
3197
+ dependencyGoalIds: z12.array(z12.string()).default([]),
3121
3198
  /** True while any gate is on a Goal that is not done — the walk draws it dashed. */
3122
- blocked: z11.boolean().default(false),
3199
+ blocked: z12.boolean().default(false),
3123
3200
  /** Its questions: every OPEN one, and at most ten settled, newest settled first
3124
3201
  * (20260929133308) — the page decides which of them to show. NOT the whole set: `asked` and
3125
3202
  * `answered` are, and a settled one's words are a line (280 characters), its body read when the
3126
- * question is opened. */
3127
- questions: z11.array(QueueQuestionSchema).default([]),
3203
+ * question is opened. Never a CANCELLED one (withdrawn, dismissed, or its Goal or call ended): it
3204
+ * asks nothing of anyone (#3723). */
3205
+ questions: z12.array(QueueQuestionSchema).default([]),
3128
3206
  /** HOW MANY QUESTIONS THIS WORK HAS ASKED, and how many are answered — the Goal's own totals,
3129
3207
  * bounded at 100 server-side. A tally counted off `questions` is a wrong number that looks
3130
3208
  * right once the cap bites (`walk/trees.ts` `tallyOf`). Optional, and defaulted from the array
3131
- * by the projection, so hand-built queues (fixtures, the demo) need not spell them. */
3132
- asked: z11.number().optional(),
3133
- answered: z11.number().optional(),
3209
+ * by the projection, so hand-built queues (fixtures, the demo) need not spell them. A cancelled
3210
+ * question is not asked (#3725). */
3211
+ asked: z12.number().optional(),
3212
+ answered: z12.number().optional(),
3134
3213
  /** Every note on it the person replied to (`QueueReplySchema`) — the page decides which to show.
3135
3214
  * Optional, not defaulted: absent is none, and every hand-built queue (fixtures, the demo) need
3136
3215
  * not spell an empty list. */
3137
- replies: z11.array(QueueReplySchema).optional(),
3216
+ replies: z12.array(QueueReplySchema).optional(),
3138
3217
  /** The repository or project identifier this Goal belongs to (#2280), null if untracked. */
3139
- repo: z11.string().nullable().optional(),
3140
- createdAt: z11.string(),
3141
- updatedAt: z11.string().nullable().default(null),
3218
+ repo: z12.string().nullable().optional(),
3219
+ createdAt: z12.string(),
3220
+ updatedAt: z12.string().nullable().default(null),
3142
3221
  /** When its owner last SAID something about it (the newest `progress` Entry: a contact update kept
3143
3222
  * as progress). `updatedAt` moves for reasons nobody chose — a
3144
3223
  * state recomputed, a review flag — so it cannot tell work in hand from work gone quiet. */
3145
- lastProgressAt: z11.string().nullable().optional(),
3224
+ lastProgressAt: z12.string().nullable().optional(),
3225
+ /** WHEN AN AGENT LAST ACTED ON IT (owner, 2026-10-27: "Move it now", Goal 567258dc): its newest agent write, an
3226
+ * Entry or a Goal change, Paigy's excluded (`goals.worked_at`). What keeps work an agent is writing on from
3227
+ * reading as gone quiet (`coldSince`); absent on a door that does not carry it. */
3228
+ workedAt: z12.string().nullable().optional(),
3146
3229
  /** THE GOAL'S NEWEST WORD, FROM EITHER SIDE (owner, 2026-09-27): the newest Entry on it, of any
3147
3230
  * kind — what the person added ("Add to this"), their reply, the agent's ask or its progress
3148
3231
  * note. A progress note is an Entry, so this is already the newer of the two: the person's note
@@ -3161,7 +3244,7 @@ var QueueItemSchema = z11.object({
3161
3244
  * minute after the person speaks erases their instant from it, and the durable traces the client
3162
3245
  * can see (`replies`, `questions[].answeredAt`) miss a spontaneous note entirely — a `request`
3163
3246
  * Entry with no `about_id` is in neither. */
3164
- lastPersonAt: z11.string().nullable().optional(),
3247
+ lastPersonAt: z12.string().nullable().optional(),
3165
3248
  /** EACH SIDE'S NEWEST WORD IN THE LAST DAY (owner, 2026-10-13, the Work tab's order): the person's
3166
3249
  * (`yours`) and the agents' (`theirs`), each null when that side wrote nothing on it in 24 hours.
3167
3250
  * `latest` holds one Entry, so whichever side wrote first is hidden there; Work orders a Goal by
@@ -3179,40 +3262,40 @@ var QueueItemSchema = z11.object({
3179
3262
  * the row shows that no `updated_at` moves for (`active` lapsing, a dependency's state, a
3180
3263
  * sibling appearing in `childGoalIds`) cannot go unnoticed. Optional because a hand-built
3181
3264
  * queue (a fixture, the demo) spells none, and a row with no rev is simply always re-sent. */
3182
- rev: z11.string().optional()
3265
+ rev: z12.string().optional()
3183
3266
  });
3184
- var QueueDeltaSchema = z11.object({
3185
- ids: z11.array(z11.string()),
3186
- items: z11.array(QueueItemSchema)
3267
+ var QueueDeltaSchema = z12.object({
3268
+ ids: z12.array(z12.string()),
3269
+ items: z12.array(QueueItemSchema)
3187
3270
  });
3188
3271
  var COLD_AFTER_MS = 3 * 24 * 60 * 60 * 1e3;
3189
- var NoteSourceSchema = z11.enum(["app", "call"]);
3190
- var NoteStatusSchema = z11.enum(["open", "assigned", "in_progress", "done"]);
3191
- var NoteRepeatSchema = z11.enum(["once", "until_done"]);
3192
- var DecisionSchema = z11.object({
3193
- id: z11.string(),
3272
+ var NoteSourceSchema = z12.enum(["app", "call"]);
3273
+ var NoteStatusSchema = z12.enum(["open", "assigned", "in_progress", "done"]);
3274
+ var NoteRepeatSchema = z12.enum(["once", "until_done"]);
3275
+ var DecisionSchema = z12.object({
3276
+ id: z12.string(),
3194
3277
  /** The note this decision refines; null = recorded on a bare thread (the
3195
3278
  * extensibility seam — any conversation can accrue decisions). */
3196
- noteId: z11.string().nullable(),
3279
+ noteId: z12.string().nullable(),
3197
3280
  /** What was ambiguous — the broker's (or the user's own) question. */
3198
- question: z11.string(),
3281
+ question: z12.string(),
3199
3282
  /** The user's ruling; null while the question is open. */
3200
- answer: z11.string().nullable(),
3201
- decidedAt: z11.string().nullable(),
3202
- createdAt: z11.string()
3283
+ answer: z12.string().nullable(),
3284
+ decidedAt: z12.string().nullable(),
3285
+ createdAt: z12.string()
3203
3286
  });
3204
- var NoteSchema = z11.object({
3205
- id: z11.string(),
3287
+ var NoteSchema = z12.object({
3288
+ id: z12.string(),
3206
3289
  /** One-line headline (broker-titled; deterministic floor). */
3207
- title: z11.string(),
3290
+ title: z12.string(),
3208
3291
  /** The original intent, verbatim — assignees always see the user's own words. */
3209
- intent: z11.string(),
3292
+ intent: z12.string(),
3210
3293
  source: NoteSourceSchema,
3211
3294
  status: NoteStatusSchema,
3212
3295
  /** Who it was assigned to (a participant ref, 'agent:<tokenId>'); null = unassigned. */
3213
- assignee: z11.string().nullable(),
3296
+ assignee: z12.string().nullable(),
3214
3297
  /** The request thread minted at assignment; null until assigned. */
3215
- parentId: z11.string().nullable(),
3298
+ parentId: z12.string().nullable(),
3216
3299
  /** REMINDERS (docs/model/notes/reminders-design.md): the NOT-BEFORE this becomes eligible to ride a
3217
3300
  * call — never a deadline. It only ever comes from the user's own words, so when it
3218
3301
  * passes Paigy rings ONCE (#1293, owner 2026-08-26: a time said out loud is consent to
@@ -3221,102 +3304,102 @@ var NoteSchema = z11.object({
3221
3304
  // Defaulted, not required: a Note from an API deploy older than the reminders
3222
3305
  // migration has none of these, and the defaults ARE what it means — no not-before,
3223
3306
  // one ride, never ridden. Parsing must not fail across a rolling deploy.
3224
- dueAt: z11.string().nullable().default(null),
3307
+ dueAt: z12.string().nullable().default(null),
3225
3308
  repeat: NoteRepeatSchema.default("once"),
3226
3309
  /** How many calls have already carried it — the fatigue cap counts rides, not days. */
3227
- rides: z11.number().int().default(0),
3228
- lastRideAt: z11.string().nullable().default(null),
3229
- createdAt: z11.string()
3310
+ rides: z12.number().int().default(0),
3311
+ lastRideAt: z12.string().nullable().default(null),
3312
+ createdAt: z12.string()
3230
3313
  });
3231
- var DeliveryModeSchema = z11.enum(["poll", "self_hosted"]);
3314
+ var DeliveryModeSchema = z12.enum(["poll", "self_hosted"]);
3232
3315
  var WAKE_EVENT = "wake";
3233
3316
  var wakeChannel = (tokenId) => `wake:${tokenId}`;
3234
- var RegisterDeliverySchema = z11.object({ mode: DeliveryModeSchema });
3235
- var OAuthStartSchema = z11.object({
3236
- provider: z11.enum(["cma"]),
3237
- returnTo: z11.string().min(1)
3317
+ var RegisterDeliverySchema = z12.object({ mode: DeliveryModeSchema });
3318
+ var OAuthStartSchema = z12.object({
3319
+ provider: z12.enum(["cma"]),
3320
+ returnTo: z12.string().min(1)
3238
3321
  });
3239
- var DeliveryConfigSchema = z11.object({
3240
- tokenId: z11.string(),
3322
+ var DeliveryConfigSchema = z12.object({
3323
+ tokenId: z12.string(),
3241
3324
  mode: DeliveryModeSchema,
3242
3325
  /** null when the deployment has no anon key configured. `self_hosted` is then REFUSED
3243
3326
  * (503 `self_hosted_unavailable`) rather than registered, so a self_hosted config always
3244
3327
  * carries credentials; only a `poll` registration can come back with null here. */
3245
- realtime: z11.object({ url: z11.string(), anonKey: z11.string() }).nullable()
3328
+ realtime: z12.object({ url: z12.string(), anonKey: z12.string() }).nullable()
3246
3329
  });
3247
- var HostDecisionSchema = z11.object({
3330
+ var HostDecisionSchema = z12.object({
3248
3331
  /** The agent's token id: the row's `recipient`. */
3249
- agent: z11.string().uuid(),
3250
- decision: z11.enum(["stood_back", "took_over"]),
3332
+ agent: z12.string().uuid(),
3333
+ decision: z12.enum(["stood_back", "took_over"]),
3251
3334
  /** The work it was about: the Goal waiting on that agent next (`claimable` on its `contact({})` read). */
3252
- goalId: z11.string().uuid().nullable().optional(),
3335
+ goalId: z12.string().uuid().nullable().optional(),
3253
3336
  /** When the server last heard from the agent, as the host read it: the presence it stood back for. */
3254
- seenAt: z11.string().datetime().nullable().optional(),
3337
+ seenAt: z12.string().datetime().nullable().optional(),
3255
3338
  /** When that work last moved (`claimable.since` on an agent's `contact({})` read), the fact the bound is judged on. */
3256
- since: z11.string().datetime().nullable().optional(),
3339
+ since: z12.string().datetime().nullable().optional(),
3257
3340
  /** What the host said, in its log's own words: why it stood back, or what the take-over did. */
3258
- said: z11.string().max(300).optional()
3341
+ said: z12.string().max(300).optional()
3259
3342
  });
3260
- var WakeNudgeSchema = z11.object({
3261
- kind: z11.enum(["reply", "request", "callback"]),
3262
- notificationId: z11.string().optional(),
3263
- parentId: z11.string()
3343
+ var WakeNudgeSchema = z12.object({
3344
+ kind: z12.enum(["reply", "request", "callback"]),
3345
+ notificationId: z12.string().optional(),
3346
+ parentId: z12.string()
3264
3347
  });
3265
- var PairingStatusSchema = z11.enum(["pending", "approved", "denied", "expired"]);
3266
- var DeviceCodeSchema = z11.object({
3267
- device_code: z11.string(),
3268
- user_code: z11.string(),
3269
- verification_uri: z11.string().url(),
3270
- verification_uri_complete: z11.string().url(),
3271
- interval: z11.number(),
3272
- expires_in: z11.number()
3348
+ var PairingStatusSchema = z12.enum(["pending", "approved", "denied", "expired"]);
3349
+ var DeviceCodeSchema = z12.object({
3350
+ device_code: z12.string(),
3351
+ user_code: z12.string(),
3352
+ verification_uri: z12.string().url(),
3353
+ verification_uri_complete: z12.string().url(),
3354
+ interval: z12.number(),
3355
+ expires_in: z12.number()
3273
3356
  });
3274
- var DeviceInfoSchema = z11.object({
3275
- code: z11.string(),
3357
+ var DeviceInfoSchema = z12.object({
3358
+ code: z12.string(),
3276
3359
  /** The agent's suggested name (from /device/code) — shown on the approval screen,
3277
3360
  * pre-filling the name field the human can edit. */
3278
- name: z11.string(),
3361
+ name: z12.string(),
3279
3362
  /** @deprecated Legacy alias of `name` for the pre-#531 embedded bundle in App Store
3280
3363
  * build 35, whose DeviceFlow renders `info.agent.slice(0, 2)` — without this a FRESH
3281
3364
  * install crashes on the pairing screen on first launch, before the OTA lands
3282
3365
  * (seen live: PAIGY-5T, 2026-07-21). Remove once a newer binary is the floor. */
3283
- agent: z11.string().optional(),
3284
- device: z11.string().nullable(),
3366
+ agent: z12.string().optional(),
3367
+ device: z12.string().nullable(),
3285
3368
  status: PairingStatusSchema
3286
3369
  });
3287
- var DeviceTokenSchema = z11.object({
3288
- access_token: z11.string(),
3370
+ var DeviceTokenSchema = z12.object({
3371
+ access_token: z12.string(),
3289
3372
  /** The pairing's single name (user-typed at approval, the agent's suggestion, or
3290
3373
  * a default silly name). */
3291
- name: z11.string(),
3292
- device: z11.string().nullable(),
3374
+ name: z12.string(),
3375
+ device: z12.string().nullable(),
3293
3376
  /** The pairing's assigned voice, cached so the desktop can seed the SAME face the phone
3294
3377
  * draws — voice is the third ingredient of a hatchling's build (party/traits.ts). */
3295
- voice: z11.string().nullable().optional(),
3378
+ voice: z12.string().nullable().optional(),
3296
3379
  /** The token's server-side id — the face's COLOUR anchor, and the only seed ingredient
3297
3380
  * that survives a rename. Cached by the host's identity beat. */
3298
- token_id: z11.string().nullable().optional(),
3381
+ token_id: z12.string().nullable().optional(),
3299
3382
  /** WHERE this identity works — the folder a wake should land it in. Written by the host
3300
3383
  * at spawn and by `paigy-harness handoff` from a live terminal. Without it every wake
3301
3384
  * landed in the FIRST granted workspace and the agent rediscovered its own repo from
3302
3385
  * the thread each time (host.ts, live catch 2026-08-06 — prompt-papered until now). */
3303
- workspace: z11.string().nullable().optional(),
3386
+ workspace: z12.string().nullable().optional(),
3304
3387
  /** Local host recovery must preserve the launch's runtime and Paigy identity. */
3305
- harness: z11.enum(["claude", "codex", "agy"]).optional(),
3306
- session_id: z11.string().uuid().optional(),
3388
+ harness: z12.enum(["claude", "codex", "agy"]).optional(),
3389
+ session_id: z12.string().uuid().optional(),
3307
3390
  /** A conversation the host must not resume: its context is full, so every turn fails
3308
3391
  * ("Prompt is too long"). Written when a run hits it (`run.ts` `onFull`); the host skips a slot
3309
3392
  * whose resumable session is this one, so its Goals reach the dead-agent handoff instead of a
3310
3393
  * copy that types the person's words into a turn that cannot run (Calls, 2026-10-06). */
3311
- full_session: z11.string().optional(),
3312
- uik_pub: z11.string().nullable().optional()
3394
+ full_session: z12.string().optional(),
3395
+ uik_pub: z12.string().nullable().optional()
3313
3396
  });
3314
- var SupportRequestSchema = z11.object({
3315
- email: z11.string().email().max(320),
3316
- message: z11.string().trim().min(1).max(5e3),
3317
- name: z11.string().trim().max(120).optional()
3397
+ var SupportRequestSchema = z12.object({
3398
+ email: z12.string().email().max(320),
3399
+ message: z12.string().trim().min(1).max(5e3),
3400
+ name: z12.string().trim().max(120).optional()
3318
3401
  });
3319
- var NotificationFeedbackKindSchema = z11.enum([
3402
+ var NotificationFeedbackKindSchema = z12.enum([
3320
3403
  "break_down",
3321
3404
  // "This should be more than one ask — break it down."
3322
3405
  "regenerate_options",
@@ -3331,131 +3414,136 @@ var NotificationFeedbackKindSchema = z11.enum([
3331
3414
  // anything else — the note carries it.
3332
3415
  ]);
3333
3416
  var SlimOptionSchema = OptionSchema.omit({ html: true });
3334
- var QuestionRowSchema = z11.object({
3417
+ var QuestionRowSchema = z12.object({
3335
3418
  /** The card's id (`deliveryId:needId`, or `deliveryId:entryId` for an update), as the inbox mints it. */
3336
- id: z11.string(),
3337
- deliveryId: z11.string(),
3338
- entryId: z11.string(),
3419
+ id: z12.string(),
3420
+ deliveryId: z12.string(),
3421
+ entryId: z12.string(),
3339
3422
  /** The decision it waits on; null for an update, which asks nothing. */
3340
- needId: z11.string().nullable(),
3341
- goalIds: z11.array(z11.string()),
3423
+ needId: z12.string().nullable(),
3424
+ goalIds: z12.array(z12.string()),
3342
3425
  /** The name of the work it is about, when the read could word it. */
3343
- goalTitle: z11.string().optional(),
3344
- tokenId: z11.string().optional(),
3345
- name: z11.string(),
3346
- title: z11.string(),
3347
- body: z11.string(),
3348
- select: z11.enum(["one", "many", "rank", "confirm", "text"]),
3349
- options: z11.array(SlimOptionSchema),
3350
- hasPreview: z11.boolean(),
3351
- blocking: z11.boolean(),
3352
- askedAt: z11.string().datetime(),
3426
+ goalTitle: z12.string().optional(),
3427
+ tokenId: z12.string().optional(),
3428
+ name: z12.string(),
3429
+ title: z12.string(),
3430
+ body: z12.string(),
3431
+ select: z12.enum(["one", "many", "rank", "confirm", "text"]),
3432
+ options: z12.array(SlimOptionSchema),
3433
+ hasPreview: z12.boolean(),
3434
+ blocking: z12.boolean(),
3435
+ askedAt: z12.string().datetime(),
3353
3436
  ring: InboxItemSchema.shape.ring,
3354
- onCall: z11.literal(true).optional(),
3355
- sealed: z11.boolean()
3437
+ onCall: z12.literal(true).optional(),
3438
+ sealed: z12.boolean()
3356
3439
  });
3357
- var WorkStateSchema = z11.enum(["ready", "active", "waiting", "done", "cancelled"]);
3358
- var WorkRowSchema = z11.object({
3359
- id: z11.string(),
3360
- parentId: z11.string().nullable(),
3361
- title: z11.string(),
3440
+ var WorkStateSchema = z12.enum(["ready", "active", "waiting", "done", "cancelled"]);
3441
+ var WorkRowSchema = z12.object({
3442
+ id: z12.string(),
3443
+ parentId: z12.string().nullable(),
3444
+ title: z12.string(),
3362
3445
  /** Straight off the Goal. */
3363
3446
  state: WorkStateSchema,
3364
- owner: z11.string().nullable(),
3365
- revision: z11.number().int(),
3447
+ owner: z12.string().nullable(),
3448
+ revision: z12.number().int(),
3366
3449
  /** Open questions on it, counted to 100. */
3367
- waiting: z11.number().int(),
3450
+ waiting: z12.number().int(),
3368
3451
  /** Held by a gate on work that is not done. */
3369
- blocked: z11.boolean(),
3370
- lastProgressAt: z11.string().datetime().nullable(),
3452
+ blocked: z12.boolean(),
3453
+ lastProgressAt: z12.string().datetime().nullable(),
3371
3454
  /** The line written for its newest progress note, else that note's first words. */
3372
- line: z11.string().nullable(),
3455
+ line: z12.string().nullable(),
3373
3456
  /** Work directly under it, counted to 100; the list carries up to 12 of them. */
3374
- children: z11.number().int(),
3375
- createdAt: z11.string().datetime(),
3376
- updatedAt: z11.string().datetime(),
3457
+ children: z12.number().int(),
3458
+ createdAt: z12.string().datetime(),
3459
+ updatedAt: z12.string().datetime(),
3377
3460
  /** When anything at or under it last moved — the order the list is in. */
3378
- activeAt: z11.string().datetime(),
3461
+ activeAt: z12.string().datetime(),
3379
3462
  /** A sealed outcome has no title here; the work's page opens it. */
3380
- sealed: z11.boolean()
3463
+ sealed: z12.boolean()
3381
3464
  });
3382
3465
  var ComputerRowSchema = ConnectionSummarySchema.omit({ activity: true });
3383
3466
  var AgentRowSchema = ComputerRowSchema.extend({
3384
3467
  /** Open questions it is asking the person, over every open card; null when that read failed. */
3385
- asking: z11.number().int().nullable(),
3386
- oldestAskAt: z11.string().datetime().nullable(),
3468
+ asking: z12.number().int().nullable(),
3469
+ oldestAskAt: z12.string().datetime().nullable(),
3387
3470
  /** Up to three of the live Goals it holds, oldest first (the order it picks them up), and how
3388
3471
  * many in all among the account's 200 most recently active agent-held live Goals
3389
3472
  * (`agent_holds`); null when that read failed. */
3390
- holds: z11.array(z11.object({ id: z11.string(), title: z11.string() })).nullable(),
3391
- held: z11.number().int().nullable(),
3473
+ holds: z12.array(z12.object({ id: z12.string(), title: z12.string() })).nullable(),
3474
+ held: z12.number().int().nullable(),
3392
3475
  /** The earliest instant any Goal it holds went quiet, by the one rule (`coldSince`); null
3393
3476
  * while none has, or when that read failed. */
3394
- cold: z11.string().datetime().nullable(),
3477
+ cold: z12.string().datetime().nullable(),
3395
3478
  /** The newest line of its working log, and when the harness saw it. */
3396
- line: z11.string().nullable(),
3397
- lineAt: z11.string().datetime().nullable()
3479
+ line: z12.string().nullable(),
3480
+ lineAt: z12.string().datetime().nullable()
3398
3481
  });
3399
- var SnapshotSchema = z11.object({
3482
+ var SnapshotSchema = z12.object({
3400
3483
  /** The API's clock, taken before the first read: what a later delta will start from. */
3401
- at: z11.string().datetime(),
3402
- questions: z11.object({
3484
+ at: z12.string().datetime(),
3485
+ questions: z12.object({
3403
3486
  /** The newest 30 open cards, questions before updates. */
3404
- items: z11.array(QuestionRowSchema),
3487
+ items: z12.array(QuestionRowSchema),
3405
3488
  /** Every open question, and apart from them every update, and what was put off. */
3406
- total: z11.number().int(),
3407
- updates: z11.number().int(),
3408
- putOff: z11.number().int()
3489
+ total: z12.number().int(),
3490
+ updates: z12.number().int(),
3491
+ putOff: z12.number().int()
3409
3492
  }).nullable(),
3410
- agents: z11.object({
3493
+ agents: z12.object({
3411
3494
  /** Up to 60, most recently seen first. */
3412
- items: z11.array(AgentRowSchema),
3413
- more: z11.boolean()
3495
+ items: z12.array(AgentRowSchema),
3496
+ more: z12.boolean()
3414
3497
  }).nullable(),
3415
- work: z11.object({
3498
+ work: z12.object({
3416
3499
  /** The 60 most recently active roots, each followed by up to 12 children; 240 rows at most. */
3417
- items: z11.array(WorkRowSchema),
3500
+ items: z12.array(WorkRowSchema),
3418
3501
  /** How much work is behind each of the Work tab's four filters, each counted to 100, read with
3419
3502
  * the rows. `work_list` (20260928023533) owns the predicates: Live is `ready`, `active` or
3420
3503
  * `waiting`; Waiting on you is live work with an open question or an unmet gate; Not started
3421
3504
  * is `ready`; Done is `done` or `cancelled`. */
3422
- counts: z11.object({ live: z11.number().int(), waiting: z11.number().int(), notStarted: z11.number().int(), done: z11.number().int() })
3505
+ counts: z12.object({ live: z12.number().int(), waiting: z12.number().int(), notStarted: z12.number().int(), done: z12.number().int() })
3423
3506
  }).nullable(),
3424
- you: z11.object({
3507
+ you: z12.object({
3425
3508
  settings: UserSettingsSchema,
3426
- callable: z11.boolean(),
3509
+ callable: z12.boolean(),
3427
3510
  /** Up to 20 paired computers; null when the roster read failed. */
3428
- computers: z11.array(ComputerRowSchema).nullable()
3511
+ computers: z12.array(ComputerRowSchema).nullable()
3429
3512
  }).nullable()
3430
3513
  });
3431
- var CallRecapSchema = z11.object({
3432
- call: z11.object({
3433
- status: z11.string(),
3434
- startedAt: z11.string(),
3435
- durationMs: z11.number().nullable(),
3514
+ var CallRecapSchema = z12.object({
3515
+ call: z12.object({
3516
+ status: z12.string(),
3517
+ startedAt: z12.string(),
3518
+ durationMs: z12.number().nullable(),
3436
3519
  /** Bot-clock pickup offset; absent before the timestamp release, null before its report lands. */
3437
- pickupMs: z11.number().nullable().optional(),
3438
- agents: z11.array(z11.object({ id: z11.string(), name: z11.string().nullable() }))
3520
+ pickupMs: z12.number().nullable().optional(),
3521
+ /** STILL FILING (20261026182117): the call has not ended on the server, or it has and a brain cycle on it is
3522
+ * still pending, the next writer, which may still settle, file or start something. What the close itself
3523
+ * waits for (`private.close_call`). `status` cannot say it: nothing writes "finalizing", and a call reads
3524
+ * "open" until the sweep closes it, after nothing is pending. Absent from an API before it. */
3525
+ filing: z12.boolean().optional(),
3526
+ agents: z12.array(z12.object({ id: z12.string(), name: z12.string().nullable() }))
3439
3527
  }),
3440
- topics: z11.array(z11.object({
3441
- goalId: z11.string().uuid(),
3442
- title: z11.string(),
3443
- owner: z11.string(),
3444
- state: z11.string(),
3528
+ topics: z12.array(z12.object({
3529
+ goalId: z12.string().uuid(),
3530
+ title: z12.string(),
3531
+ owner: z12.string(),
3532
+ state: z12.string(),
3445
3533
  /** Presented Entry content and its author, separately from the current Goal owner. */
3446
- items: z11.array(z11.object({ entryId: z11.string(), author: z11.string(), text: z11.string(), summary: z11.string().nullable() })).optional(),
3534
+ items: z12.array(z12.object({ entryId: z12.string(), author: z12.string(), text: z12.string(), summary: z12.string().nullable(), acknowledged: z12.boolean().optional() })).optional(),
3447
3535
  /** Whether the call put it to the person. An item it carried and never said has no row on the
3448
3536
  * review (owner, 2026-10-08: "why do we get the third one when it didn't happen in the call?"). */
3449
- presented: z11.boolean(),
3537
+ presented: z12.boolean(),
3450
3538
  /** Whether THIS call created it — the third way a call touches work, beside carrying a request
3451
3539
  * there and filing words there (owner, 2026-10-08, Goal `5b4b1a0a`: "Show the new work, keep my
3452
3540
  * words under it"). Created work is never carried, so it is never `presented`; without this the
3453
3541
  * row is dropped by the "only what happened on the call" filter. False on a database before
3454
3542
  * 20261013080133. */
3455
- created: z11.boolean(),
3543
+ created: z12.boolean(),
3456
3544
  /** `request` is the Entry that asked it — what a line's `about` names when the line answered or put
3457
3545
  * it off. Optional: an older API sent none. */
3458
- questions: z11.array(z11.object({ id: z11.string().uuid(), state: z11.string(), title: z11.string(), request: z11.string().optional() })),
3546
+ questions: z12.array(z12.object({ id: z12.string().uuid(), state: z12.string(), title: z12.string(), request: z12.string().optional() })),
3459
3547
  /** `words` is always what they SAID, verbatim — the record, never replaced. `summary` is what
3460
3548
  * the line says in ten words (owner, 2026-10-07): the filer's, or the talker's for the answer it
3461
3549
  * gave, so the row scans like a chosen option and their own words stay under it. Absent when
@@ -3465,33 +3553,89 @@ var CallRecapSchema = z11.object({
3465
3553
  /** `reply` is the reply the line makes up (an answer, an ok, a deferral), so one reply is one row
3466
3554
  * however many lines it cites; `at` is the call lines it came from, so a filed line an answer already
3467
3555
  * said is not drawn again (owner, 2026-10-07: "fix them all"); `replyKind` says which replies are answers. */
3468
- lines: z11.array(z11.object({
3469
- entryId: z11.string().uuid(),
3470
- words: z11.string(),
3471
- summary: z11.string().optional(),
3472
- about: z11.string().nullable().optional(),
3473
- reply: z11.string().nullable().optional(),
3474
- replyKind: z11.string().nullable().optional(),
3475
- at: z11.array(z11.number()).optional()
3556
+ lines: z12.array(z12.object({
3557
+ entryId: z12.string().uuid(),
3558
+ words: z12.string(),
3559
+ summary: z12.string().optional(),
3560
+ about: z12.string().nullable().optional(),
3561
+ reply: z12.string().nullable().optional(),
3562
+ replyKind: z12.string().nullable().optional(),
3563
+ at: z12.array(z12.number()).optional()
3476
3564
  }))
3477
3565
  })),
3478
- unfiled: z11.array(z11.object({ lineId: z11.string().uuid(), words: z11.string(), atMs: z11.number() })),
3566
+ unfiled: z12.array(z12.object({ lineId: z12.string().uuid(), words: z12.string(), atMs: z12.number() })),
3479
3567
  /** THE PUBLIC TRANSCRIPT — every line said on the call, in the order it was said, and WHO SAID IT
3480
3568
  * (owner, 2026-10-08: "the public view should only have the lines and who said them, and that's
3481
3569
  * it"; `docs/brain/phase-three/modular.md` build step 3). `speaker` is the role: "user" is the
3482
3570
  * person, "agent" an agent speaking, named in `agent`. The timeline's action lines are ours, not
3483
3571
  * theirs, and are not here; nor is a sealed line, which the server has no words for. It stands
3484
3572
  * BESIDE `topics` and `unfiled` — what the call did with the words — never instead of them. */
3485
- said: z11.array(z11.object({
3486
- lineId: z11.string().uuid(),
3487
- speaker: z11.enum(["user", "agent"]),
3488
- agent: z11.object({ id: z11.string().nullable(), name: z11.string().nullable() }).nullable(),
3489
- words: z11.string(),
3490
- atMs: z11.number()
3573
+ said: z12.array(z12.object({
3574
+ lineId: z12.string().uuid(),
3575
+ speaker: z12.enum(["user", "agent"]),
3576
+ agent: z12.object({ id: z12.string().nullable(), name: z12.string().nullable() }).nullable(),
3577
+ words: z12.string(),
3578
+ atMs: z12.number()
3491
3579
  })),
3492
- more: z11.object({ lines: z11.number(), entries: z11.number(), topics: z11.number() }),
3580
+ /** What did not fit, counted. `settles` counts items past the recap's 100; absent before 20261026165518. */
3581
+ more: z12.object({ lines: z12.number(), entries: z12.number(), topics: z12.number(), settles: z12.number().optional() }),
3493
3582
  /** Last stored position on this page when another exists; absent before paging shipped. */
3494
- next: z11.number().int().nonnegative().nullable().optional()
3583
+ next: z12.number().int().nonnegative().nullable().optional(),
3584
+ /** THE CALL AS ONE LIST OF ROWS (owner, 2026-10-14: "we only really want a thing like transcript but
3585
+ * built from the summaries", then "the transcript tabs should show the same but with full words").
3586
+ * Both tabs draw these rows, in this order: Summary from `summary`, Transcript from `words`.
3587
+ * - `put`: an item put to the person, at the first agent line that voiced it. Paigy's sentences
3588
+ * that voiced it are folded into `spoken`, never rows of their own.
3589
+ * - `said`: the person's words, one row per reply or per filed line no reply covers.
3590
+ * - `did`: what Paigy did ("Sent to Mouth: …", "Recorded: …", "Filed on …").
3591
+ * `by` is the row's real author, never inferred from `kind`: a relay Paigy sent to an agent is
3592
+ * Paigy's, not the person's. Optional and additive (owner: "make sure whatever you do is backward
3593
+ * compatible"): an API before it sends none, and the screen falls back to `topics` and `said`. */
3594
+ timeline: z12.array(z12.object({
3595
+ id: z12.string(),
3596
+ position: z12.number(),
3597
+ atMs: z12.number(),
3598
+ kind: z12.enum(["put", "said", "did"]),
3599
+ by: z12.object({ participant: z12.string().nullable(), agentId: z12.string().nullable(), name: z12.string().nullable() }),
3600
+ goalId: z12.string().uuid().nullable(),
3601
+ requestId: z12.string().nullable(),
3602
+ summary: z12.string().nullable(),
3603
+ words: z12.string(),
3604
+ /** Paigy's sentences folded into this row: on a `put` row, what it said putting the item to the
3605
+ * person (before their next row); on a `said` row, what it said in reply (until their next row).
3606
+ * `atMs` is when each was said; optional, absent before 2026-10-14's fix. */
3607
+ spoken: z12.array(z12.object({ lineId: z12.string(), words: z12.string(), atMs: z12.number().optional() })),
3608
+ /** On a `said` row: the work these words were filed on, and whether they answered (recorded) a
3609
+ * question. They replace the "Filed on ..." and "Recorded: ..." rows that repeated the person's own
3610
+ * summary (Brain, 2026-10-14). Optional: absent from an API before it. */
3611
+ filedOn: z12.array(z12.object({ goalId: z12.string().uuid(), title: z12.string() })).optional(),
3612
+ recorded: z12.boolean().optional(),
3613
+ settled: z12.object({ requestId: z12.string(), answer: z12.string() }).nullable().optional(),
3614
+ acknowledged: z12.boolean().optional(),
3615
+ /** On a `put` row: still waiting for the person's answer (not settled, not answered, not put off).
3616
+ * The server's judgement; the screen draws "Still waiting for your answer" from it. Optional: absent
3617
+ * from an API before it, where the screen falls back to its own reading. */
3618
+ waiting: z12.boolean().optional(),
3619
+ lineIds: z12.array(z12.string())
3620
+ })).optional(),
3621
+ /** THE RECAP (owner, 2026-10-26: "the transcript should just be the entries that settled or
3622
+ * acknowledged the items; that's it"). Each item the person's words settled on this call, in the
3623
+ * order they said them: who asked it (`by`), the item in its agent's words (`title`), and only the
3624
+ * words of theirs that settled it (`lines`: each line once, verbatim, with when it was said on the
3625
+ * bot clock like `said[].atMs`). Built from their replies, not from what the call put, so an item
3626
+ * settled without being put is still here. Beside them (owner: "List them too, with the words that
3627
+ * said them"), each Goal his words told something (`kind` "told") or the call started ("started"),
3628
+ * with `requestId` null and the Goal's name as `title`; a started Goal may have no `lines` yet. `kind`
3629
+ * is a string, not an enum, so a later kind never fails an older build's parse; `requestId` is the
3630
+ * request the words settled. On the first page only; absent from an API before it. */
3631
+ settles: z12.array(z12.object({
3632
+ requestId: z12.string().nullable(),
3633
+ kind: z12.string(),
3634
+ by: z12.object({ participant: z12.string(), agentId: z12.string().nullable(), name: z12.string() }),
3635
+ goalId: z12.string().uuid().nullable(),
3636
+ title: z12.string(),
3637
+ lines: z12.array(z12.object({ lineId: z12.string(), words: z12.string(), atMs: z12.number() }))
3638
+ })).optional()
3495
3639
  });
3496
3640
  function sessionSlot(sessionId2) {
3497
3641
  const id2 = sessionId2 ?? sessionId();
@@ -3598,6 +3742,14 @@ async function requestCode(suggestedName = agentName(), device) {
3598
3742
  if (!res.ok) throw new Error(`/api/device/code failed: ${res.status} ${await res.text()}`);
3599
3743
  return await res.json();
3600
3744
  }
3745
+ var ServerFault = class extends Error {
3746
+ constructor(status) {
3747
+ super(`Paigy's server failed (HTTP ${status}) while checking the code.`);
3748
+ this.status = status;
3749
+ this.name = "ServerFault";
3750
+ }
3751
+ status;
3752
+ };
3601
3753
  async function pollToken(deviceCode) {
3602
3754
  const res = await reach(`${BACKEND_URL}/api/device/token`, {
3603
3755
  method: "POST",
@@ -3605,6 +3757,7 @@ async function pollToken(deviceCode) {
3605
3757
  body: JSON.stringify({ device_code: deviceCode })
3606
3758
  });
3607
3759
  if (res.ok) return await res.json();
3760
+ if (res.status >= 500) throw new ServerFault(res.status);
3608
3761
  const body = await res.json().catch(() => ({ error: "unknown" }));
3609
3762
  const err = body.error ?? "unknown";
3610
3763
  if (err === "authorization_pending") return null;
@@ -3825,11 +3978,12 @@ async function checkActivity(opts = {}) {
3825
3978
  if (!res.ok) await fail("check_activity", res);
3826
3979
  return await res.json();
3827
3980
  }
3828
- var NOT_SENT = `Recorded as the Goal's progress, not sent: nobody was notified. The person is told only a question, an answer to one they asked you, and what you say once the Goal is done. To close the work, send contact.completions or manage_goals kind:complete with the shared completion report, closing and reporting together. If the person asked you, in so many words, to send them this, send it again with userExplicitlyRequested: "any" on that update.`;
3981
+ var NOT_SENT = `Recorded as the Goal's progress, not sent to the person; the other agents that wrote on the Goal in the last hour are told. The person is told only a question, an answer to one they asked you, and what you say once the Goal is done. To close the work, send contact.completions or manage_goals kind:complete with the shared completion report, closing and reporting together. If the person asked you, in so many words, to send them this, send it again with userExplicitlyRequested: "any" on that update.`;
3829
3982
  var APPLIED = "Applied; nothing was sent to the person.";
3830
3983
  var DEMOTED = "Delivered as a card, not a call: the person's settings do not allow a call right now (silent, quiet hours, or a mode). It has reached them; do not send it again.";
3831
3984
  async function readDelivery(deliveryId, opts = {}) {
3832
- const res = await ensureAuthed(await (opts.reach ?? reach)(`${BACKEND_URL}/api/deliveries/${encodeURIComponent(deliveryId)}`, {
3985
+ const query = opts.transcript ? `?transcript=1${opts.after ? `&after=${encodeURIComponent(opts.after)}` : ""}` : "";
3986
+ const res = await ensureAuthed(await (opts.reach ?? reach)(`${BACKEND_URL}/api/deliveries/${encodeURIComponent(deliveryId)}${query}`, {
3833
3987
  headers: { authorization: `Bearer ${authToken(opts.token) ?? ""}` },
3834
3988
  signal: opts.signal
3835
3989
  }));
@@ -3966,6 +4120,9 @@ async function receiveContact(input, opts = {}) {
3966
4120
  throw error;
3967
4121
  }
3968
4122
  }
4123
+ function viaLine(via) {
4124
+ return via ? `a card they shared by link${via.decidedBy ? `, decided by ${via.decidedBy}` : ""}` : void 0;
4125
+ }
3969
4126
  function compact(o) {
3970
4127
  return Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0 && v !== null && v !== "" && !(Array.isArray(v) && v.length === 0)));
3971
4128
  }
@@ -3989,7 +4146,8 @@ function decided(result) {
3989
4146
  return void 0;
3990
4147
  }
3991
4148
  }
3992
- function stateOf(state, answer, decided2) {
4149
+ function stateOf(state, answer, decided2, withdrawn) {
4150
+ if (withdrawn && state === "answered") return "closed";
3993
4151
  return state === "answered" && answer && decided2 === void 0 ? "replied" : state;
3994
4152
  }
3995
4153
  var handle = (entryId) => entryId.slice(0, 8);
@@ -4018,10 +4176,11 @@ function conversation(e) {
4018
4176
  at: at(entry.createdAt),
4019
4177
  said: sealed ? "[encrypted]" : entryWords(entry).trim(),
4020
4178
  caveat: entry.callOngoing ? "Call ongoing; what the person decides may change." : void 0,
4179
+ via: viaLine(entry.via),
4021
4180
  units: askUnits(entry, e.entries ?? []).map((u) => `${u.title}: ${u.body}`),
4022
4181
  re: re ? handle(re) : void 0,
4023
4182
  options,
4024
- decision: need ? compact({ state: stateOf(need.state, answer, decision), answer: decision }) : void 0
4183
+ decision: need ? compact({ state: stateOf(need.state, answer, decision, need.withdrawn), answer: decision, via: viaLine(answer?.via) }) : void 0
4025
4184
  });
4026
4185
  });
4027
4186
  }
@@ -4061,7 +4220,11 @@ function goalView(g) {
4061
4220
  subtree: g.subtree?.length ? g.subtree.map((c) => compact({
4062
4221
  goal: `${" ".repeat(c.depth - 1)}${c.title} (${c.state})`,
4063
4222
  goalId: c.goalId,
4064
- questions: c.questions.length ? c.questions.map((q) => q.answer ? `${q.question} \u2192 ${q.answer}` : `${q.question} \u2192 (open)`) : void 0
4223
+ // AN ANSWERED QUESTION NEVER READS OPEN (2026-10-27, Goal b5f1fc27): an answer given on a call,
4224
+ // an option pick or a spoken reply, has an instant on the list's row and no words there, and
4225
+ // it read "(open)". Seven answered questions read that way, and an agent reading them would
4226
+ // ask the owner again. The words are on the Goal's own read.
4227
+ questions: c.questions.length ? c.questions.map((q) => `${q.question} \u2192 ${q.answer || (q.answeredAt ? "(answered: read this Goal for the answer)" : "(open)")}`) : void 0
4065
4228
  })) : void 0,
4066
4229
  blockedBy: g.blockedDependencyGoalIds,
4067
4230
  dueAt: g.dueAt,
@@ -4089,7 +4252,8 @@ var itemsView = (results) => (results ?? []).map((r) => compact({
4089
4252
  error: r.error,
4090
4253
  detail: r.detail
4091
4254
  }));
4092
- function deliveryReadView(d) {
4255
+ function deliveryReadView(d, asked2 = {}) {
4256
+ const t = d.transcript;
4093
4257
  return compact({
4094
4258
  deliveryId: d.deliveryId,
4095
4259
  kind: d.kind,
@@ -4098,9 +4262,20 @@ function deliveryReadView(d) {
4098
4262
  conversation: conversation(d),
4099
4263
  callState: d.callState,
4100
4264
  callOutcome: d.callOutcome ?? (d.kind === "call" ? d.message : void 0),
4101
- next: d.callState && d.callState !== "ended" ? "Keep receiving with contact({wait:true}) while this Call is open, even after an empty window. Do not resend the ask." : "Answers and follow-ups are on their Goals; receive on your next wake. This read acknowledges nothing."
4265
+ // WHAT WAS SAID (owner, 2026-10-26): each line as "m:ss", who said it, and the words; `for` and `room` only
4266
+ // when they are true of the line, so a short call reads as the call did.
4267
+ transcript: t ? compact({
4268
+ timedFrom: t.pickupKnown ? "pickup" : "the call's start",
4269
+ lines: t.lines.map((l) => compact({ at: clock2(l.atMs), by: l.by, for: l.for ?? void 0, room: l.room || void 0, words: l.words })),
4270
+ next: t.next ?? void 0
4271
+ }) : void 0,
4272
+ next: t?.next ? `Read the next page of the transcript with get_delivery({deliveryId: "${d.deliveryId}", transcript: true, after: "${t.next}"}).` : asked2.transcript && !t ? d.kind === "call" ? "This API sent no transcript: it is older than the transcript, or the call has none it can show." : "Only a Call has a transcript." : d.callState && d.callState !== "ended" ? "Keep receiving with contact({wait:true}) while this Call is open, even after an empty window. Do not resend the ask." : "Answers and follow-ups are on their Goals; receive on your next wake. This read acknowledges nothing."
4102
4273
  });
4103
4274
  }
4275
+ function clock2(ms) {
4276
+ const s = Math.max(0, Math.floor(ms / 1e3));
4277
+ return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, "0")}`;
4278
+ }
4104
4279
  function deliveryView(d) {
4105
4280
  const answers = "Answers land on the Goal: collect them with contact({wait:true}) or get_goals. Do not resend it.";
4106
4281
  const pending = d.state === "open" && d.decisionNeeds.some((n) => n.state === "open");
@@ -4180,6 +4355,8 @@ function receivedView(r, now = Date.now()) {
4180
4355
  // on startup and after a wake (contact({wait:false}), and every hosted receive), never on a window of a
4181
4356
  // held wait, which would repeat them window after window.
4182
4357
  houseRules: r.waitOutcome === "not_waited" ? w.houseRules : void 0,
4358
+ // THEIR RING POLICY, ONE FOR EVERY AGENT (owner, 2026-10-27, Goal 6faa6a51), on the same reads as the house rules.
4359
+ ringPolicy: r.waitOutcome === "not_waited" ? w.ringPolicy : void 0,
4183
4360
  next: [
4184
4361
  r.events.length ? `Handle each event, then acknowledge the ones you handled: contact({ ackEventIds: [${r.events.filter((e) => e.kind !== "question").map((e) => `"${e.eventId}"`).join(", ")}] }).` : w.claimable || assigned.length || rings.length || w.calls?.some((c) => c.callState !== "ended") ? "No messages." : "Nothing is waiting.",
4185
4362
  ...owed.length ? [`You owe ${owed.length === 1 ? "an answer" : `${owed.length} answers`}: contact({ answers: [{ questionId: "<questionId>", answer: { text: <your answer> } }] }) for each question; a question is answered, never acknowledged.`] : [],
@@ -4189,7 +4366,7 @@ function receivedView(r, now = Date.now()) {
4189
4366
  ...rings.map((r2) => rerings(r2, now)),
4190
4367
  ...assigned.length ? [`${assigned.length} of your Goals are assigned to you and not started (assigned): read one with get_goals({goalIds:[goalId]}); your first write to it starts it.`] : [],
4191
4368
  ...w.claimable && !assigned.length ? [`Next waiting on you: ${w.claimable.title ?? w.claimable.goalId} (get_goals({ goalIds: ["${w.claimable.goalId}"] })).`] : [],
4192
- ...stalled.length ? [`${stalled.length} of your Goals have had no progress${stalled.length === 1 ? " " : ""}${quietFor(stalled, now)}: report on each with a contact update, or finish or cancel it with manage_goals.`] : [],
4369
+ ...stalled.length ? [`${stalled.length} of your Goals have had no progress${stalled.length === 1 ? " " : ""}${quietFor(stalled, now)}: report on each with a contact update, or finish, cancel or defer it with manage_goals.`] : [],
4193
4370
  // The COUNT, oldest three, and where to read them (owner, 2026-10-08): it was 34 rows of
4194
4371
  // other agents' work on every window, ahead of this agent's own next step.
4195
4372
  ...others ? [`${others.count} of other agents' Goals have gone quiet${others.count === 1 ? " " : ""}${quietFor([{ since: others.oldestSince }], now, others.count)}: The oldest three are in others.goals: get_goals({goalIds:[goalId]}) reads one in full. A write to it puts you on it without changing its owner.`] : [],
@@ -4264,8 +4441,16 @@ async function runTool(name, args, opts) {
4264
4441
  for (const g of managed.goals ?? []) remember(client.token, g.goalId, g.revision);
4265
4442
  return managedView(managed, changes);
4266
4443
  }
4267
- case "get_delivery":
4268
- return deliveryReadView(await readDelivery(GetDeliverySchema.parse(input).deliveryId, { ...client, signal }));
4444
+ case "get_delivery": {
4445
+ const asked2 = GetDeliverySchema.parse(input);
4446
+ return deliveryReadView(
4447
+ await readDelivery(
4448
+ asked2.deliveryId,
4449
+ { ...client, signal, ...asked2.transcript ? { transcript: true, ...asked2.after ? { after: asked2.after } : {} } : {} }
4450
+ ),
4451
+ { transcript: asked2.transcript === true }
4452
+ );
4453
+ }
4269
4454
  case "get_goals": {
4270
4455
  const { goalIds, history } = GetGoalsSchema.parse(input);
4271
4456
  const rows = await getGoals(goalIds, client, { history });
@@ -4534,6 +4719,7 @@ export {
4534
4719
  deleteToken,
4535
4720
  revokeToken,
4536
4721
  requestCode,
4722
+ ServerFault,
4537
4723
  pollToken,
4538
4724
  UnpairedError,
4539
4725
  RevokedError,