@kingcrab/pi-imessage 0.0.43 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/README.md +93 -127
  2. package/dist/agent/behavior.js +79 -0
  3. package/dist/agent/chats.js +88 -0
  4. package/dist/agent/commands.js +191 -0
  5. package/dist/agent/compaction.js +51 -0
  6. package/dist/agent/deliver.js +139 -0
  7. package/dist/agent/direct-send.js +69 -0
  8. package/dist/agent/harness.js +79 -0
  9. package/dist/agent/health.js +33 -0
  10. package/dist/agent/models.js +69 -0
  11. package/dist/agent/progress-format.js +87 -0
  12. package/dist/agent/progress.js +173 -0
  13. package/dist/agent/prompt.js +79 -0
  14. package/dist/agent/replies.js +10 -0
  15. package/dist/agent/run.js +160 -0
  16. package/dist/agent/scheduling.js +291 -0
  17. package/dist/agent/time.js +18 -0
  18. package/dist/cli.js +88 -191
  19. package/dist/config/settings.js +60 -0
  20. package/dist/extensions/browser.js +326 -0
  21. package/dist/extensions/final-text.js +23 -0
  22. package/dist/extensions/memory.js +109 -0
  23. package/dist/extensions/message.js +33 -0
  24. package/dist/extensions/read-image.js +72 -0
  25. package/dist/extensions/restart.js +100 -0
  26. package/dist/extensions/schedules.js +42 -0
  27. package/dist/extensions/subagent.js +54 -0
  28. package/dist/extensions/web.js +100 -0
  29. package/dist/extensions/workspace.js +98 -0
  30. package/dist/main.js +578 -88
  31. package/dist/transport/attachments.js +37 -0
  32. package/dist/transport/http.js +110 -0
  33. package/dist/{rich-text.js → transport/rich-text.js} +25 -13
  34. package/dist/{send.js → transport/send.js} +13 -13
  35. package/dist/transport/watch.js +124 -0
  36. package/dist/web/app.js +826 -0
  37. package/dist/web/history.js +87 -0
  38. package/dist/web/memory.js +81 -0
  39. package/dist/web/page.js +29 -0
  40. package/dist/web/schedules.js +63 -0
  41. package/dist/web/server.js +382 -0
  42. package/dist/web/style.css +577 -0
  43. package/dist/web/tasks.js +97 -0
  44. package/docs/adr/0001-durable-owns-state.md +11 -0
  45. package/docs/adr/0002-module-layering.md +11 -0
  46. package/docs/adr/0003-replies-at-most-once.md +11 -0
  47. package/docs/adr/0004-native-extensions.md +11 -0
  48. package/docs/adr/0005-history-migration.md +11 -0
  49. package/docs/adr/0006-jsonl-storage.md +11 -0
  50. package/docs/adr/0007-images-by-path.md +11 -0
  51. package/docs/adr/0008-compaction-and-run.md +11 -0
  52. package/docs/adr/0009-one-shot-cutover.md +11 -0
  53. package/docs/adr/0010-test-budget.md +11 -0
  54. package/docs/adr/0011-reconcile-unsent-answers.md +24 -0
  55. package/docs/adr/0012-run-in-owned-conversation.md +22 -0
  56. package/docs/adr/0013-thin-adapters-around-durable.md +18 -0
  57. package/docs/adr/0014-ephemeral-private-storage.md +13 -0
  58. package/docs/adr/0015-ordinary-stop-keeps-native-inbox.md +21 -0
  59. package/docs/adr/0016-process-http-transport.md +21 -0
  60. package/docs/adr/0017-browser-cli-owned-scope.md +22 -0
  61. package/docs/adr/0018-tasks-without-prompt-api.md +19 -0
  62. package/docs/adr/0019-remove-scheduled-services.md +41 -0
  63. package/docs/adr/0020-chat-task-progress.md +41 -0
  64. package/docs/adr/0021-readable-progress-without-link-previews.md +33 -0
  65. package/docs/adr/0022-progress-admission-and-settlement.md +35 -0
  66. package/docs/adr/0023-retain-progress-type-prefixes.md +18 -0
  67. package/docs/adr/0024-status-marker-before-type-prefix.md +13 -0
  68. package/docs/adr/0025-reusable-progress-and-command-preview.md +49 -0
  69. package/docs/adr/0026-inline-command-only-requests.md +16 -0
  70. package/docs/adr/0027-command-preview-width.md +10 -0
  71. package/docs/adr/0028-command-preview-120.md +8 -0
  72. package/docs/adr/0030-shared-web-read-cache.md +33 -0
  73. package/docs/adr/0031-quiet-compaction-progress.md +32 -0
  74. package/docs/adr/0032-native-background-schedules.md +58 -0
  75. package/docs/adr/0033-operator-scheduled-run.md +23 -0
  76. package/docs/adr/0034-machine-local-schedule-time.md +36 -0
  77. package/docs/adr/0035-external-business-task-extensions.md +56 -0
  78. package/docs/adr/0036-workspace-policy-and-neutral-service-id.md +37 -0
  79. package/docs/adr/0037-restart-during-in-flight-work.md +30 -0
  80. package/docs/adr/0038-restart-any-time.md +25 -0
  81. package/docs/adr/0039-rerun-interrupted-tools.md +24 -0
  82. package/docs/adr/0040-chat-progress-notices.md +44 -0
  83. package/docs/adr/0041-restart-and-recovery.md +28 -0
  84. package/docs/adr/0042-background-schedules-and-workspace-extensions.md +44 -0
  85. package/docs/adr/0043-remove-legacy-migration.md +23 -0
  86. package/docs/adr/0044-message-channels.md +32 -0
  87. package/docs/adr/0045-chat-scheduling-tools.md +51 -0
  88. package/docs/adr/0046-selective-command-redaction.md +31 -0
  89. package/docs/adr/0047-one-scheduling-path.md +158 -0
  90. package/docs/adr/0048-quiet-attachment-reads.md +11 -0
  91. package/docs/adr/0049-per-chat-progress-notices.md +21 -0
  92. package/docs/adr/0052-host-owned-self-restart.md +53 -0
  93. package/docs/adr/README.md +54 -0
  94. package/docs/api.md +104 -0
  95. package/docs/architecture.md +164 -0
  96. package/docs/browser.md +93 -0
  97. package/docs/memory.md +27 -0
  98. package/docs/screenshot.png +0 -0
  99. package/docs/workspace-extensions.md +133 -0
  100. package/examples/workspace-extensions/system-context/index.ts +69 -0
  101. package/examples/workspace-extensions/system-context/package.json +3 -0
  102. package/ops/README.md +250 -0
  103. package/ops/preflight.mjs +28 -0
  104. package/package.json +36 -37
  105. package/dist/agent.d.ts +0 -84
  106. package/dist/agent.d.ts.map +0 -1
  107. package/dist/agent.js +0 -780
  108. package/dist/agent.js.map +0 -1
  109. package/dist/cli.d.ts +0 -15
  110. package/dist/cli.d.ts.map +0 -1
  111. package/dist/cli.js.map +0 -1
  112. package/dist/imessage.d.ts +0 -33
  113. package/dist/imessage.d.ts.map +0 -1
  114. package/dist/imessage.js +0 -76
  115. package/dist/imessage.js.map +0 -1
  116. package/dist/logger.d.ts +0 -33
  117. package/dist/logger.d.ts.map +0 -1
  118. package/dist/logger.js +0 -104
  119. package/dist/logger.js.map +0 -1
  120. package/dist/main.d.ts +0 -5
  121. package/dist/main.d.ts.map +0 -1
  122. package/dist/main.js.map +0 -1
  123. package/dist/memory.d.ts +0 -53
  124. package/dist/memory.d.ts.map +0 -1
  125. package/dist/memory.js +0 -196
  126. package/dist/memory.js.map +0 -1
  127. package/dist/model-health.d.ts +0 -11
  128. package/dist/model-health.d.ts.map +0 -1
  129. package/dist/model-health.js +0 -69
  130. package/dist/model-health.js.map +0 -1
  131. package/dist/pipeline.d.ts +0 -27
  132. package/dist/pipeline.d.ts.map +0 -1
  133. package/dist/pipeline.js +0 -59
  134. package/dist/pipeline.js.map +0 -1
  135. package/dist/queue.d.ts +0 -23
  136. package/dist/queue.d.ts.map +0 -1
  137. package/dist/queue.js +0 -89
  138. package/dist/queue.js.map +0 -1
  139. package/dist/reminders.d.ts +0 -42
  140. package/dist/reminders.d.ts.map +0 -1
  141. package/dist/reminders.js +0 -207
  142. package/dist/reminders.js.map +0 -1
  143. package/dist/rich-text.d.ts +0 -26
  144. package/dist/rich-text.d.ts.map +0 -1
  145. package/dist/rich-text.js.map +0 -1
  146. package/dist/self-echo.d.ts +0 -19
  147. package/dist/self-echo.d.ts.map +0 -1
  148. package/dist/self-echo.js +0 -54
  149. package/dist/self-echo.js.map +0 -1
  150. package/dist/send.d.ts +0 -24
  151. package/dist/send.d.ts.map +0 -1
  152. package/dist/send.js.map +0 -1
  153. package/dist/settings.d.ts +0 -44
  154. package/dist/settings.d.ts.map +0 -1
  155. package/dist/settings.js +0 -80
  156. package/dist/settings.js.map +0 -1
  157. package/dist/store.d.ts +0 -57
  158. package/dist/store.d.ts.map +0 -1
  159. package/dist/store.js +0 -124
  160. package/dist/store.js.map +0 -1
  161. package/dist/tasks.d.ts +0 -95
  162. package/dist/tasks.d.ts.map +0 -1
  163. package/dist/tasks.js +0 -384
  164. package/dist/tasks.js.map +0 -1
  165. package/dist/types.d.ts +0 -93
  166. package/dist/types.d.ts.map +0 -1
  167. package/dist/types.js +0 -38
  168. package/dist/types.js.map +0 -1
  169. package/dist/watch.d.ts +0 -21
  170. package/dist/watch.d.ts.map +0 -1
  171. package/dist/watch.js +0 -219
  172. package/dist/watch.js.map +0 -1
  173. package/dist/web/data.d.ts +0 -11
  174. package/dist/web/data.d.ts.map +0 -1
  175. package/dist/web/data.js +0 -56
  176. package/dist/web/data.js.map +0 -1
  177. package/dist/web/html.d.ts +0 -5
  178. package/dist/web/html.d.ts.map +0 -1
  179. package/dist/web/html.js +0 -16
  180. package/dist/web/html.js.map +0 -1
  181. package/dist/web/index.d.ts +0 -25
  182. package/dist/web/index.d.ts.map +0 -1
  183. package/dist/web/index.js +0 -335
  184. package/dist/web/index.js.map +0 -1
  185. package/dist/web/render.d.ts +0 -11
  186. package/dist/web/render.d.ts.map +0 -1
  187. package/dist/web/render.js +0 -56
  188. package/dist/web/render.js.map +0 -1
  189. package/dist/web/templates/logs.eta +0 -75
  190. package/dist/web/templates/memory.eta +0 -91
  191. package/dist/web/templates/page.eta +0 -98
@@ -0,0 +1,32 @@
1
+ # 0031. Hide only six-hour compaction progress
2
+
3
+ Status: proposed (owner clarified trigger-specific visibility on 2026-10-06)
4
+
5
+ Narrows ADR 0020's compaction notices only for six-hour maintenance ticks.
6
+
7
+ **Problem.** The six-hour timer emits `pi.compaction` progress into chat. The
8
+ owner wants that timer quiet, but wants progress for manual `/compact` and
9
+ automatic context-threshold/overflow compaction.
10
+
11
+ **Example.** A timer tick sends neither a start nor completion notice. Manual
12
+ `/compact` shows both notices and its command result. A native context-triggered
13
+ compaction shows both notices.
14
+
15
+ **Decision.** Track exact task IDs admitted by `compactChats` using process-local
16
+ Harness-scoped state. Before a compaction admission notice, wait for in-flight
17
+ timer admissions to resolve so the observer can classify the committed task
18
+ before `compact()` has returned its ID. Suppress only a matching timer task's
19
+ notice; without an admission notice its settlement also remains quiet. Consume
20
+ the classification after observation. Do not mute an entire conversation or
21
+ filter by native reason: both the timer and `/compact` use reason `manual`.
22
+
23
+ Native manual, threshold and overflow task progress keeps its existing routing,
24
+ receipts and settlement formatting. Timer execution, logs, six-hour cadence,
25
+ manual command results and other progress are unchanged. Classification is not
26
+ persisted because pre-start task progress is never replayed.
27
+
28
+ **Verification.** An existing isolated faux-provider messaging regression with
29
+ progress enabled checks timer admission/settlement create no notices or progress
30
+ receipts, manual `/compact` shows progress and its result, and native tasks with
31
+ threshold/overflow reasons retain both progress receipts. Existing tool and
32
+ child-task progress regressions remain enabled.
@@ -0,0 +1,58 @@
1
+ # 0032. Native background schedules and read-only execution history
2
+
3
+ Status: proposed (owner requested native scheduling, compact migration and Web history)
4
+
5
+ **Problem.** The retired scheduler called HTTP `/prompt`, which no longer exists.
6
+ The six-hour maintenance `setInterval` also loses its next deadline on restart.
7
+
8
+ **Example.** Restart at 07:40 must retain tomorrow's English deadline and the
9
+ maintenance deadline, without starting another message pipeline or recreating
10
+ uncertain sends. A Web refresh must show both jobs without invoking a model.
11
+
12
+ **Decision.**
13
+
14
+ - Register one Durable scheduling extension in the agent layer. Each configured
15
+ job has a dedicated ownerless conversation and a conversation-owned task with
16
+ `background: true`. Its saved `sleep` checkpoint contains the absolute next
17
+ deadline. `runtime.sleep()` is an invocation-local wait, not a persisted timer.
18
+ - An occurrence is a child task admitted atomically with the scheduler's waiting
19
+ checkpoint. Join with `allSettled`, then compute the next deadline, including
20
+ after generation failure. Native task records are the execution history; there
21
+ is no separate host worker database or UI execution log.
22
+ - Support exactly six-hour chat compaction and the explicitly configured daily
23
+ English card. Keep native compaction, its quiet maintenance progress routing,
24
+ and automatic/manual compaction behavior. No arbitrary cron parser or LLM
25
+ scheduling tools. Do not revive legacy job files, HTTP prompt/send, reminders,
26
+ background completion watchers or PT Automation.
27
+ - Daily English uses Asia/Shanghai calendar deadlines. A late start processes
28
+ only the current day after its scheduled time; missed days are not backfilled.
29
+ Compaction processes one overdue tick and skips missed interval slots. Long
30
+ executions never overlap themselves. Configuration is read at startup; existing
31
+ saved deadlines remain, with changed cadence applied to the following slot.
32
+ - Import the configured English `used.json` once, read-only, preserving unknown
33
+ fields. Durable owns subsequent learning progress. Code selects due reviews
34
+ and enforces the existing three-expression daily limit and new-learning quota;
35
+ a tool-less, isolated model conversation provides wording, never updates files
36
+ or sends. Commit learning changes, the actual card and its outbox together.
37
+ Per-date card records and stable submission/request IDs prevent regeneration.
38
+ - Deliver the outbox using existing direct-send receipts and passive chat records.
39
+ Sending is not transactional with Messages.app. `sending` becomes `unknown` on
40
+ restart; uncertain or previously accepted sends are not automatically replayed.
41
+ Stored learning progress means generated/displayed content, not proof of delivery.
42
+ - `/scheduled` and `/scheduled/data` show all native configured schedules, their
43
+ task state/deadline, per-job latest ten occurrence tasks, and the latest ten
44
+ across all jobs. Show generation result separately from delivery receipt. These
45
+ are read-only routes; viewing them never resumes tasks or starts inference.
46
+
47
+ This proposal supersedes ADR 0013's rejection of native recurring task adapters
48
+ and ADR 0019's removal of these two scheduling features only. Other retired
49
+ features and at-most-once transport safeguards remain unchanged.
50
+
51
+ **Consequences.** The service must be running to act at a deadline. Stored
52
+ checkpoints recover execution but cannot wake a stopped machine or process.
53
+ Schedules remain independent of chat abort/reset. Explicitly aborting their task
54
+ pauses them; startup does not silently recreate a terminal scheduler.
55
+
56
+ **Rejected.** An external cron daemon, a second message pipeline, restoring
57
+ `/prompt`, a timer that reschedules from each process startup, asking the model
58
+ to remember to schedule tomorrow, and claiming exactly-once external delivery.
@@ -0,0 +1,23 @@
1
+ # 0033. Explicit operator run at startup
2
+
3
+ Status: proposed (owner requested one real Workplace English trial)
4
+
5
+ **Problem.** A configured job cannot be exercised on demand through the read-only
6
+ Web UI. Opening another Harness on the live workspace is unsafe.
7
+
8
+ **Decision.** An authorized owning-service restart may pass
9
+ `serve --run-scheduled JOB --request-id ID`. The existing owner admits one native
10
+ background occurrence in the configured job's conversation, after installing its
11
+ extension. It saves the request ID and task ID atomically; repeating that startup
12
+ request returns the same task. Refuse missing/disabled jobs or another live
13
+ occurrence. Do not alter the recurring task or its saved deadline.
14
+
15
+ Normal startup without the flags remains unchanged. The local startup request
16
+ is not stored in settings or installed into launchd. There is no new HTTP route,
17
+ Web action button, alternate writer, polling worker or operating-system job.
18
+ English still enforces the existing per-date card dedupe and learning policy;
19
+ this is not permission to bypass a quota or replay an uncertain send.
20
+
21
+ **Consequences.** This small operator entry requires a safe restart to trigger.
22
+ It is deliberately not a general interactive scheduler-management API. A live
23
+ trial can invoke the configured model and send its card, requiring owner consent.
@@ -0,0 +1,36 @@
1
+ # 0034. Use the service machine's local time for schedules
2
+
3
+ Status: proposed (owner requested the complete local-time change)
4
+
5
+ **Problem.** Daily deadlines, learning dates and schedule history are hard-coded
6
+ for Asia/Shanghai, even when the service runs on a machine in another timezone.
7
+
8
+ **Example.** A daily 07:45 job on a New York machine should run at 07:45 there,
9
+ including after a daylight-saving change, not at 07:45 Shanghai time.
10
+
11
+ **Decision.**
12
+
13
+ - Use the service process's local calendar for daily deadlines and learning dates.
14
+ By default this is the machine timezone; an explicit `TZ` environment override
15
+ is respected and retained by installation and routine restart.
16
+ - Calculate the next daily slot by calendar date, not by adding 24 hours. Use
17
+ JavaScript Date's local-time rules: nonexistent spring-forward times move
18
+ forward through the gap; repeated fall-back times select the first occurrence.
19
+ - Include the service timezone in each configured job's read-only projection.
20
+ The Web UI formats deadlines and history in that timezone, not the browser's.
21
+ - Retain saved absolute deadlines, occurrence dates, task IDs, learning history
22
+ and send receipts. The next computed slot uses local time. A timezone change
23
+ does not authorize regenerating cards, backfilling dates or replaying sends.
24
+ - Six-hour compaction remains an elapsed-time interval, independent of timezone
25
+ and daylight-saving changes.
26
+
27
+ This proposal supersedes only ADR 0032's fixed Asia/Shanghai calendar policy.
28
+ All other scheduling, recovery and at-most-once delivery decisions remain intact.
29
+
30
+ **Consequences.** Moving a deployment or changing `TZ` changes future calendar
31
+ slots. An already saved deadline remains an absolute instant until processed;
32
+ restart does not silently replace its checkpoint.
33
+
34
+ **Rejected.** Changing only README text, hard-coded UTC offsets, adding 24 hours
35
+ for calendar recurrence, using the browser timezone for server schedules, and
36
+ rewriting production learning or receipt data.
@@ -0,0 +1,56 @@
1
+ # 0035. Workspace-owned business extensions
2
+
3
+ Status: accepted
4
+
5
+ **Problem.** Personal business logic, such as English learning, does not belong
6
+ in the reusable messaging framework.
7
+
8
+ **Example.** Changing a personal task should change a workspace extension, not
9
+ framework scheduling, settings, prompts or Web code.
10
+
11
+ **Decision.**
12
+
13
+ - Put personal code and configuration in
14
+ `WORKING_DIR/extensions/<name>/index.ts` and `config.json`. Each native Durable
15
+ extension may provide tools, define multiple tasks and optionally schedule them.
16
+ Both the owner and chat assistant may create extensions; add no permission list
17
+ or extra confirmation gate.
18
+ - Scan direct child directories at startup and on `/reload`. Reject duplicate
19
+ extension/task names. Validate before replacing definitions; failed reloads keep
20
+ the old definitions. Do not execute skills or attachments as extensions.
21
+ - Keep generic daily/interval scheduling, non-overlapping execution, recovery,
22
+ outgoing queues, send receipts and read-only Web history in the framework.
23
+ Six-hour compaction remains built-in maintenance using the same components.
24
+ Durable owns persisted tasks and business state; there is no second pipeline.
25
+ - Reload does not interrupt current calls. The next tool/task invocation uses
26
+ new code and configuration; do not proactively reset saved deadlines. Extensions
27
+ provide native migrations when saved task structures change.
28
+ - Removing an extension stops future scheduling, not current calls, and retains
29
+ history, business data and receipts. Keep definitions needed by unfinished work
30
+ in memory; missing required task code on restart must fail explicitly.
31
+ - Move English code and configuration into its workspace extension. Remove all
32
+ English-specific framework branches and personal job IDs. Preserve existing
33
+ settings, task IDs, checkpoints, deadlines, learning records and send IDs during
34
+ migration; never regenerate saved cards or replay uncertain sends. Verify with
35
+ faux models and temporary storage, then migrate under the single service owner
36
+ with source/configuration rollback copies.
37
+
38
+ ```mermaid
39
+ sequenceDiagram
40
+ participant W as Workspace Extensions
41
+ participant S as Service
42
+ participant D as Durable
43
+
44
+ S->>W: Scan code and configuration
45
+ W-->>S: Tools, tasks and schedules
46
+ S->>D: Register or replace definitions
47
+ D->>D: Wait for the deadline
48
+ D->>W: Invoke task
49
+ W->>D: Persist state and results
50
+ D->>D: Save next deadline
51
+ ```
52
+
53
+ **Consequences.** Workspace extensions are trusted code and need backup with their
54
+ configuration. This is the target design, not an implementation claim. It replaces
55
+ ADR 0032's embedded English logic; Durable ownership, at-most-once delivery and
56
+ ADR 0034's machine-local time rules remain unchanged.
@@ -0,0 +1,37 @@
1
+ # 0036. Workspace policy and a neutral service identity
2
+
3
+ Status: accepted (owner accepted on 2026-10-06)
4
+
5
+ **Problem.** A reusable message service should not hard-code an operator's system
6
+ record layout, fallback model, billing tier or personal launchd identifier.
7
+
8
+ **Example.** One workspace can explicitly retain its current fallback and priority
9
+ tier, while another fails on an unavailable default rather than choosing a model
10
+ or spending preference on the user's behalf.
11
+
12
+ **Decision.**
13
+
14
+ - Keep memory and the other shared native tools built in. ADR 0035 owns personal
15
+ business code and its scheduling configuration.
16
+ - Move `SYSTEM.md` summary loading into an optional workspace extension; its
17
+ path, boundary and byte budget are configuration. Move system-record update
18
+ instructions into workspace `AGENTS.md`, not the framework prompt.
19
+ - `settings.json.modelPolicy.fallback` optionally selects a provider/model pair.
20
+ An absent fallback fails explicitly when the selected default is unavailable.
21
+ Use only an available model with configured authentication.
22
+ - `modelPolicy.codexServiceTier` optionally chooses `default` or `priority`.
23
+ Absence leaves the provider payload unchanged. Reload applies policy to future
24
+ requests; it does not interrupt existing calls.
25
+ - Generate launchd jobs with neutral identity `org.pi-imessage.service`. Do not
26
+ silently rename a loaded controller or start another pipeline. Migrate an
27
+ installed personal-label job only under the operations handover procedure.
28
+ - Existing configuration remains compatible. The offline migration preserves
29
+ unknown settings and explicitly records the prior fallback/tier, rather than
30
+ silently changing live model or cost behavior. It retains source/configuration
31
+ rollback copies and never rewrites Durable state.
32
+
33
+ **Consequences.** The workspace owns and backs up its personal code and policy.
34
+ New installations have no implicit fallback or priority preference. A foreground
35
+ Terminal deployment needs no controller migration when no old-label job exists.
36
+ This supersedes ADR 0004's hard-coded Codex fast wrapper choice only, not its
37
+ native-extension or no-SDK-adapter decisions.
@@ -0,0 +1,30 @@
1
+ # 0037. Restart during in-flight work
2
+
3
+ Status: accepted
4
+
5
+ **Problem.** Routine deployment waits for an idle service. An active chat can keep
6
+ the service busy for a long time, so a finished change stays undeployed.
7
+
8
+ **Example.** A deployment waited while a chat ran a long model request. The owner
9
+ restarted anyway: the old process exited in about one second and the new one
10
+ resumed the same conversation, which continued its tool calls.
11
+
12
+ **Decision.**
13
+
14
+ - Do not wait for idle. Model generations, queued submissions, admitted scheduled
15
+ occurrences and imminent scheduler wakes do not defer a routine restart.
16
+ Durable owns their recovery, and saved deadlines are absolute.
17
+ - Stop only at a moment when no tool is running and no message send is in
18
+ progress. Recheck immediately before stopping.
19
+ - Stop with SIGTERM only. A shutdown timeout stops the deployment; never force-kill,
20
+ steal the lock or start a second pipeline.
21
+ - Accept the recovery costs: an interrupted model request is sent again. A tool
22
+ that started anyway is not replayed; the model sees the interruption. A send
23
+ that started anyway becomes `unknown` and is never resent.
24
+ - After startup, verify that interrupted work continues, and that send receipt
25
+ counts are unchanged apart from new sends.
26
+
27
+ **Consequences.** Deployment no longer depends on chat activity. A restart may
28
+ cost one repeated model request and delay a reply by a few seconds. This changes
29
+ only the idle requirement in the routine restart procedure (`ops/README.md`);
30
+ at-most-once delivery (ADR 0003) and the one-owner rule are unchanged.
@@ -0,0 +1,25 @@
1
+ # 0038. Restart at any time
2
+
3
+ Status: accepted (owner decided on 2026-10-06)
4
+
5
+ **Problem.** ADR 0037 still waits for a moment with no running tool and no send
6
+ in progress. That check adds a step and can still delay a deployment.
7
+
8
+ **Example.** A chat runs a long bash command. Under ADR 0037 the deployment
9
+ waits for it; under this decision the restart proceeds, and the model sees the
10
+ interrupted command after recovery.
11
+
12
+ **Decision.**
13
+
14
+ - A routine restart may stop the service at any time. No task, tool, send or
15
+ scheduler state defers it.
16
+ - Stop with SIGTERM only. A shutdown timeout stops the deployment; never
17
+ force-kill, steal the lock or start a second pipeline.
18
+ - Recovery is Durable's: an interrupted model request is sent again, an
19
+ interrupted tool is not replayed, and an interrupted send becomes `unknown`
20
+ and is never resent.
21
+
22
+ **Consequences.** A restart can lose one reply (left `unknown`) or leave a tool
23
+ half-done for the model to check. This supersedes ADR 0037's stop-moment rule;
24
+ its verification steps, at-most-once delivery (ADR 0003) and the one-owner rule
25
+ remain.
@@ -0,0 +1,24 @@
1
+ # 0039. Rerun interrupted tools by default
2
+
3
+ Status: accepted (owner decided on 2026-10-06)
4
+
5
+ **Problem.** Durable reruns an interrupted tool only when the tool declares
6
+ `replay: "safe"`; its default is `unsafe`. Bash, file edits, image reads and
7
+ workspace tools therefore fail after a restart, although almost all of them can
8
+ simply run again.
9
+
10
+ **Example.** A restart interrupts `bash` listing a directory. Before, the model
11
+ received "interrupted and may have partially run" and had to decide what to do;
12
+ now the command runs again and the turn continues.
13
+
14
+ **Decision.**
15
+
16
+ - The host treats every tool without an explicit `replay` as `safe`, including
17
+ built-in, Durable and workspace extension tools.
18
+ - A tool whose effect must not repeat declares `replay: "unsafe"`.
19
+ - Replies and `send_message` keep at-most-once delivery through their own send
20
+ receipts (ADR 0003): a rerun never resends a `sending` or `unknown` message.
21
+
22
+ **Consequences.** Restarts rarely surface interrupted tools to the model. A
23
+ rerun tool may repeat a partial effect, such as appending to a file twice. This
24
+ supersedes the interrupted-tool clause of ADR 0038.
@@ -0,0 +1,44 @@
1
+ # 0040. Chat progress notices
2
+
3
+ Status: accepted (owner accepted on 2026-10-06; consolidates ADRs 0020–0028 and 0031 without changing behavior)
4
+
5
+ **Problem.** The current progress format is spread over ten ADRs that each
6
+ replace a detail of the previous one.
7
+
8
+ **Example.**
9
+
10
+ ```text
11
+ → [tool] bash: node search.mjs "Shanghai weather" --count 5
12
+ ✓ [tool] bash (0.8s)
13
+ → [subagent/tool] read: path=/tmp/a.jpg
14
+ × [subagent/tool] read (0.1s)
15
+ ```
16
+
17
+ **Decision.**
18
+
19
+ - With `settings.json` `progressMessages: true`, observe native task admission
20
+ and settlement through Durable's commit subscription. No wrapper, polling or
21
+ second execution loop. `pi.generation` tasks are not reported.
22
+ - Send one request notice at admission and one response notice at settlement,
23
+ to the owning reply-enabled chat. Child tasks follow Durable ownership and are
24
+ labelled with their parents, such as `[subagent/tool]`. Health and unrelated
25
+ ownerless conversations stay quiet.
26
+ - Format: status marker first (`→` request, `✓` success, `×` anything else),
27
+ then `[parents/type]`, then the native name. Success requires a completed task
28
+ and a tool result without an error flag. Responses show elapsed time from
29
+ admission, including queueing.
30
+ - Bash requests show the command inline, at most 120 Unicode code points. Screen
31
+ the whole command first: a credential indicator hides it, and URLs and common
32
+ domains are defanged so iMessage shows no link preview. Other tools show
33
+ bounded argument summaries; URLs show only a defanged hostname; timeouts are
34
+ omitted. Never show outputs, thinking, prompts or document contents.
35
+ - Six-hour maintenance compaction is quiet. Manual `/compact` and Durable's
36
+ automatic threshold/overflow compactions are reported.
37
+ - `src/agent/progress-format.ts` holds a transport-independent `ProgressEvent`
38
+ and pure formatting and screening functions; iMessage is one adapter.
39
+ - Each notice uses a direct-send receipt keyed by task ID. Unknown sends are not
40
+ retried, and work admitted before startup is not replayed. Final replies wait
41
+ for queued notices first.
42
+
43
+ **Consequences.** A busy turn sends many notices. Screening is best effort and
44
+ cannot detect every secret. This supersedes ADRs 0020–0028 and 0031.
@@ -0,0 +1,28 @@
1
+ # 0041. Restart and recovery
2
+
3
+ Status: accepted (owner accepted on 2026-10-06; consolidates ADRs 0037–0039 without changing behavior)
4
+
5
+ **Problem.** Restart rules are spread over three ADRs, each replacing part of
6
+ the previous one.
7
+
8
+ **Example.** A chat is running `bash` when a deployment restarts the service.
9
+ The old process exits within seconds, the new one starts, the command runs
10
+ again and the turn continues.
11
+
12
+ **Decision.**
13
+
14
+ - A routine restart may happen at any time; no task, tool, send or scheduler
15
+ state defers it.
16
+ - Stop with SIGTERM only. A shutdown timeout stops the deployment; never
17
+ force-kill, steal the lock or start a second pipeline.
18
+ - Durable recovers everything else. An interrupted model request is sent again.
19
+ A tool without an explicit `replay` reruns; a tool whose effect must not
20
+ repeat declares `replay: "unsafe"`.
21
+ - Replies and `send_message` stay at most once (ADR 0003): an interrupted send
22
+ becomes `unknown` and is never resent.
23
+ - After startup, verify that interrupted work continues and that receipt counts
24
+ change only by new and interrupted sends.
25
+
26
+ **Consequences.** Deployment never waits for chat activity. A restart can cost
27
+ one repeated model request, lose one reply or repeat a partial tool effect;
28
+ the owner accepts these as rare. This supersedes ADRs 0037–0039.
@@ -0,0 +1,44 @@
1
+ # 0042. Background schedules and workspace extensions
2
+
3
+ Status: accepted (owner accepted on 2026-10-06; consolidates ADRs 0019 and 0032–0035 without changing behavior)
4
+
5
+ **Problem.** Scheduling was removed (0019), rebuilt natively (0032–0034) and
6
+ then separated from personal business code (0035). The current rules are
7
+ spread over five ADRs that partly contradict each other.
8
+
9
+ **Example.** A daily 07:45 workspace task and six-hour compaction both keep
10
+ their deadlines across a restart. Changing the task's code changes only
11
+ `WORKING_DIR/extensions/<name>/`, not the framework.
12
+
13
+ **Decision.**
14
+
15
+ - **Retired services stay removed:** cron, reminders, delayed prompts,
16
+ completion watchers, PT Automation and HTTP `/prompt` / `/send`. Their
17
+ endpoints return 404; stored old data is kept but unused.
18
+ - **Workspace extensions** hold personal code: `WORKING_DIR/extensions/<name>/`
19
+ with `index.ts` and `config.json`. Each is a trusted native Durable extension
20
+ with tools, tasks and optional schedules. The owner and the chat assistant
21
+ may both create them. Startup, `/reload` and `reload_extensions` scan direct
22
+ child directories. Duplicate names are rejected; a failed reload keeps the
23
+ old definitions; running calls keep their code.
24
+ - **Framework scheduling** gives each schedule a dedicated conversation with a
25
+ background task whose checkpoint saves the absolute next deadline. Each
26
+ occurrence is a child task; occurrences never overlap. Daily slots run only
27
+ today's slot, without backfill; interval slots skip missed ticks. Six-hour
28
+ compaction uses the same mechanism and stays built in.
29
+ - **Time** is the service machine's local timezone (or `TZ`). Daily slots are
30
+ computed by calendar date, so daylight-saving changes keep the wall-clock
31
+ time. Saved deadlines are never reset by reload, restart or timezone change.
32
+ - **Delivery** commits business state and the outgoing item together. The host
33
+ sends through existing receipts at most once; `unknown` is never resent.
34
+ - **Operator run:** `serve --run-scheduled JOB --request-id ID` admits one
35
+ occurrence at startup; repeating the same request ID returns the same task.
36
+ - **History:** `/scheduled` shows each schedule, its deadline and the latest
37
+ ten occurrences from native task records. Viewing never starts work.
38
+ - **Removal:** removing an extension stops future scheduling only. Unfinished
39
+ work keeps its code in memory; restart fails explicitly if required code is
40
+ missing.
41
+
42
+ **Consequences.** The service must be running to act at a deadline. Workspace
43
+ extensions are trusted code and need backup. This supersedes ADRs 0019 and
44
+ 0032–0035, and the scheduler clause of ADR 0013.
@@ -0,0 +1,23 @@
1
+ # 0043. Remove the legacy migration code
2
+
3
+ Status: accepted (owner decided on 2026-10-06)
4
+
5
+ **Problem.** The one-time cutover from the legacy service is done, but its code
6
+ and runbook remain: `src/migrate/`, the `pi-imessage import` command, a test and
7
+ `ops/CUTOVER.md`. Readers must learn a whole layer that will never run again.
8
+
9
+ **Example.** A new contributor reads the package table, finds `migrate/` next to
10
+ `main.ts`, and spends time on history import rules unrelated to any change.
11
+
12
+ **Decision.**
13
+
14
+ - Delete `src/migrate/`, the `import` CLI command, `test/migrate.test.ts` and
15
+ `ops/CUTOVER.md`.
16
+ - Keep them reachable at the annotated tag `archive/legacy-migration`, the last
17
+ revision that contains them. A tag is fixed and runnable; a wiki copy is not.
18
+ - The rule "never run old and new message pipelines concurrently" stays in
19
+ `AGENTS.md` and `ops/README.md`.
20
+
21
+ **Consequences.** Imported history already lives in Durable storage and is
22
+ unaffected. Rerunning a migration means checking out the tag in a separate
23
+ worktree. This replaces ADRs 0005 and 0009, whose work is complete.
@@ -0,0 +1,32 @@
1
+ # 0044. Organize message sources as channels
2
+
3
+ Status: proposed
4
+
5
+ **Problem.** `transport/` is iMessage-only: it polls `chat.db` and sends through
6
+ Messages.app. A second message source, such as Telegram, has no place to go, and
7
+ the name "transport" suggests a network layer. `transport/http.ts` is the shared
8
+ outgoing HTTP client, not a message source.
9
+
10
+ **Example.** Adding Telegram today would mean putting `telegram-watch.ts` beside
11
+ `watch.ts`, while `agent/` imports `MessageSender` from the iMessage `send.ts`.
12
+
13
+ **Decision.** Apply this when the second channel is implemented, not before
14
+ (no abstraction until needed):
15
+
16
+ - Rename `transport/` to `channels/`, with one directory per channel:
17
+ `channels/imessage/` (`watch.ts`, `send.ts`, `rich-text.ts`,
18
+ `attachments.ts`), `channels/telegram/`, and so on.
19
+ - Put the shared contract in `channels/types.ts`: the incoming message shape and
20
+ `MessageSender`. `agent/` depends on this contract, never on one channel.
21
+ - Move the process HTTP client (ADR 0016) out of the channel package, for example
22
+ to `config/` or a small `net/` package at the bottom layer.
23
+ - Identify chats as `<channel>:<id>` for new channels. Existing iMessage chat
24
+ GUIDs stay unchanged, so `settings.json` allowlists and Durable `Chats`
25
+ records remain valid.
26
+
27
+ **Consequences.** One rename and an import update when the second channel
28
+ arrives; until then the code stays as it is. The layer rule (ADR 0002) is
29
+ unchanged: channels stay below `agent/` and contain no agent logic.
30
+
31
+ **Rejected.** A generic plugin loader for channels: there is one real channel
32
+ today, and workspace extensions (ADR 0042) already cover tool plugins.
@@ -0,0 +1,51 @@
1
+ # 0045. Native chat scheduling tools
2
+
3
+ Status: proposed
4
+
5
+ **Problem.** A simple deferred chat request currently requires the assistant to
6
+ write a trusted workspace extension and reload it. That is useful for reusable
7
+ business code, but unnecessarily complex for an ordinary reminder or agent task.
8
+
9
+ **Example.** In iMessage, "remind me in ten minutes" should create a task through
10
+ `schedule_task`, just as it does in the coding agent. "Every day at 09:00,
11
+ summarize new items" should not require generated TypeScript either.
12
+
13
+ **Decision.**
14
+
15
+ - Add built-in `schedule_task`, `list_scheduled_tasks` and
16
+ `cancel_scheduled_task` tools for chat conversations. The scheduling tool takes
17
+ a time and a prompt, with optional explicit daily or interval repetition.
18
+ Support durations, clock times and absolute datetimes; do not add a cron parser.
19
+ - Bind each task to its originating chat in host code. List and cancellation
20
+ operate only on that chat's interactive schedules, never framework maintenance
21
+ or workspace extension schedules. Return a stable ID and the actual deadline.
22
+ - Use native Durable background tasks and documents in the existing owning
23
+ service. Creation must be atomic and deduplicated by the scheduling tool call;
24
+ interruption must not create a second schedule. Persist absolute deadlines,
25
+ configuration and cancellation. No detached timer, operating-system scheduler,
26
+ legacy job files, HTTP prompt/send endpoint or second pipeline.
27
+ - Execute each occurrence in a fresh isolated agent conversation with the
28
+ normal authorized tools. Send its final result back to the originating chat
29
+ through the existing at-most-once receipts and passive chat records, without
30
+ steering an unrelated active chat turn. A scheduled prompt is a saved user
31
+ request, not a system instruction.
32
+ - Recurring occurrences never overlap and skip missed slots. One-shot tasks
33
+ execute once when overdue, including after restart. Cancellation prevents
34
+ future admission; it does not undo an already admitted occurrence or resend
35
+ uncertain effects. Keep existing restart recovery and unknown-send safeguards.
36
+ - Use the service machine's timezone, including explicit `TZ`, and expose native
37
+ deadlines and occurrence records on the existing read-only Scheduled page.
38
+ The service must be running to execute work; persistence does not wake a
39
+ stopped service or machine.
40
+ - Keep workspace extensions for reusable business tools and tasks. Existing
41
+ extension schedules and six-hour compaction retain their IDs, deadlines and
42
+ behavior. Reload must not disable or reset interactive schedules.
43
+ - Replace the chat prompt's extension-writing requirement for ordinary scheduled
44
+ work with brief instructions to use these tools. Do not remove unrelated chat
45
+ steering or delivery safeguards.
46
+
47
+ **Consequences.** This deliberately replaces ADR 0042's retirement of ordinary
48
+ reminders and delayed agent prompts, but not its retired external services or
49
+ workspace extension contract. It also replaces that clause of ADR 0018. It is a
50
+ small native management interface over Durable, not a return to the old cron
51
+ service. Implementation follows owner acceptance; accepted ADRs stay unchanged.
@@ -0,0 +1,31 @@
1
+ # 0046. Selective command-preview redaction
2
+
3
+ Status: proposed (owner requested `***` value masking on 2026-10-06; implementation tracked in #36)
4
+
5
+ Supersedes only ADR 0040's whole-command credential suppression rule.
6
+
7
+ **Problem.** A mention of `token`, `password`, `.env` or `auth.json` hides the
8
+ entire command, even when it is just a source search or filename.
9
+
10
+ **Example.** `TOKEN=demo123 curl --retry 3` becomes
11
+ `→ [tool] bash: TOKEN=*** curl --retry 3`. `rg 'token' src` remains readable.
12
+
13
+ **Decision.** Replace recognized credential values with `***`, retaining the
14
+ surrounding command instead of a hidden-command placeholder. Cover sensitive
15
+ assignments, options, authorization headers, URL userinfo, structured values,
16
+ known credential prefixes and PEM private-key blocks. Read complete shell words,
17
+ including quoted fragments, escaped spaces and command substitutions. Opaque
18
+ escaped JSON and ambiguous substitutions may lose additional argument text to
19
+ avoid showing a partial credential. Filenames and keyword mentions alone do not
20
+ trigger hiding. Screening remains best effort, not an arbitrary-secret guarantee.
21
+
22
+ Apply masking to the full command before whitespace normalization, URL/domain
23
+ defanging and the existing 120-Unicode-code-point bound. Native execution,
24
+ non-bash summaries, progress ownership, settlement and durable receipts remain
25
+ unchanged. No new scheduler, pipeline, tool execution or delivery replay.
26
+
27
+ **Verification.** Extend the existing isolated messaging regression with exact
28
+ preview examples, quote/escape cases, structured credentials, line continuations,
29
+ substitutions, known prefixes, private keys, keyword-only searches and masking
30
+ before truncation. Existing native execution, ownership and uncertain-send
31
+ regressions remain in force.