@kingcrab/pi-imessage 1.1.1 → 1.2.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 (84) hide show
  1. package/README.md +4 -6
  2. package/dist/agent/behavior.js +7 -13
  3. package/dist/agent/chats.js +7 -8
  4. package/dist/agent/commands.js +16 -11
  5. package/dist/agent/harness.js +6 -0
  6. package/dist/agent/progress.js +30 -4
  7. package/dist/agent/prompt.js +41 -24
  8. package/dist/agent/run.js +5 -4
  9. package/dist/agent/scheduling.js +11 -34
  10. package/dist/cli.js +42 -5
  11. package/dist/config/settings.js +4 -0
  12. package/dist/extensions/browser.js +7 -3
  13. package/dist/extensions/codemode.js +16 -0
  14. package/dist/extensions/final-text.js +12 -0
  15. package/dist/extensions/schedules.js +1 -1
  16. package/dist/extensions/subagent.js +3 -12
  17. package/dist/extensions/workspace.js +6 -2
  18. package/dist/main.js +42 -49
  19. package/dist/transport/watch.js +7 -1
  20. package/dist/web/app.js +63 -121
  21. package/dist/web/server.js +7 -14
  22. package/dist/web/style.css +0 -6
  23. package/dist/web/tasks.js +12 -120
  24. package/docs/adr/{0004-native-extensions.md → 0003-native-extensions.md} +1 -1
  25. package/docs/adr/{0006-jsonl-storage.md → 0004-jsonl-storage.md} +1 -1
  26. package/docs/adr/{0007-images-by-path.md → 0005-images-by-path.md} +1 -1
  27. package/docs/adr/{0010-test-budget.md → 0006-test-budget.md} +1 -1
  28. package/docs/adr/{0011-reconcile-unsent-answers.md → 0007-reconcile-unsent-answers.md} +2 -2
  29. package/docs/adr/{0012-run-in-owned-conversation.md → 0008-run-in-owned-conversation.md} +5 -5
  30. package/docs/adr/{0032-native-background-schedules.md → 0009-native-background-schedules.md} +1 -1
  31. package/docs/adr/0010-framework-and-workspace.md +27 -0
  32. package/docs/adr/README.md +24 -48
  33. package/docs/api.md +16 -8
  34. package/docs/architecture.md +19 -8
  35. package/docs/browser.md +7 -7
  36. package/docs/install.md +109 -0
  37. package/docs/workspace-extensions.md +8 -4
  38. package/package.json +4 -5
  39. package/dist/agent/compaction.js +0 -51
  40. package/dist/agent/error-log.js +0 -37
  41. package/dist/extensions/restart.js +0 -100
  42. package/docs/adr/0003-replies-at-most-once.md +0 -11
  43. package/docs/adr/0005-history-migration.md +0 -11
  44. package/docs/adr/0008-compaction-and-run.md +0 -11
  45. package/docs/adr/0009-one-shot-cutover.md +0 -11
  46. package/docs/adr/0013-thin-adapters-around-durable.md +0 -18
  47. package/docs/adr/0014-ephemeral-private-storage.md +0 -13
  48. package/docs/adr/0015-ordinary-stop-keeps-native-inbox.md +0 -21
  49. package/docs/adr/0016-process-http-transport.md +0 -21
  50. package/docs/adr/0017-browser-cli-owned-scope.md +0 -22
  51. package/docs/adr/0018-tasks-without-prompt-api.md +0 -19
  52. package/docs/adr/0019-remove-scheduled-services.md +0 -41
  53. package/docs/adr/0020-chat-task-progress.md +0 -41
  54. package/docs/adr/0021-readable-progress-without-link-previews.md +0 -33
  55. package/docs/adr/0022-progress-admission-and-settlement.md +0 -35
  56. package/docs/adr/0023-retain-progress-type-prefixes.md +0 -18
  57. package/docs/adr/0024-status-marker-before-type-prefix.md +0 -13
  58. package/docs/adr/0025-reusable-progress-and-command-preview.md +0 -49
  59. package/docs/adr/0026-inline-command-only-requests.md +0 -16
  60. package/docs/adr/0027-command-preview-width.md +0 -10
  61. package/docs/adr/0028-command-preview-120.md +0 -8
  62. package/docs/adr/0030-shared-web-read-cache.md +0 -33
  63. package/docs/adr/0031-quiet-compaction-progress.md +0 -32
  64. package/docs/adr/0033-operator-scheduled-run.md +0 -23
  65. package/docs/adr/0034-machine-local-schedule-time.md +0 -36
  66. package/docs/adr/0035-external-business-task-extensions.md +0 -56
  67. package/docs/adr/0036-workspace-policy-and-neutral-service-id.md +0 -37
  68. package/docs/adr/0037-restart-during-in-flight-work.md +0 -30
  69. package/docs/adr/0038-restart-any-time.md +0 -25
  70. package/docs/adr/0039-rerun-interrupted-tools.md +0 -24
  71. package/docs/adr/0040-chat-progress-notices.md +0 -44
  72. package/docs/adr/0041-restart-and-recovery.md +0 -28
  73. package/docs/adr/0042-background-schedules-and-workspace-extensions.md +0 -44
  74. package/docs/adr/0043-remove-legacy-migration.md +0 -23
  75. package/docs/adr/0044-message-channels.md +0 -32
  76. package/docs/adr/0045-chat-scheduling-tools.md +0 -51
  77. package/docs/adr/0046-selective-command-redaction.md +0 -31
  78. package/docs/adr/0047-one-scheduling-path.md +0 -158
  79. package/docs/adr/0048-quiet-attachment-reads.md +0 -11
  80. package/docs/adr/0049-per-chat-progress-notices.md +0 -21
  81. package/docs/adr/0052-host-owned-self-restart.md +0 -53
  82. package/docs/adr/0053-service-log-errors.md +0 -44
  83. package/ops/README.md +0 -250
  84. package/ops/preflight.mjs +0 -28
@@ -1,13 +0,0 @@
1
- # 0024. Status marker before the type prefix
2
-
3
- Status: accepted (owner explicitly corrected marker placement on 2026-10-05)
4
-
5
- Supersedes the prefix-first display order in ADR 0023 only. Preserve all
6
- native routing, safe descriptions, settlement verification and receipt rules.
7
-
8
- **Example.** `→ [tool] bash: Check the weather`, then `✓ [tool] bash (0.8s)`.
9
- Child tools use `→ [subagent/tool] read: path=…`. Failure uses `×` first.
10
-
11
- **Decision.** Put the status marker at the very beginning, immediately followed
12
- by the retained bracketed type/parent label. Ask for short everyday action
13
- wording instead of implementation jargon. Omit timeout and raw commands.
@@ -1,49 +0,0 @@
1
- # 0025. Reusable progress data and short command previews
2
-
3
- Status: accepted (owner approved option 5, then clarified request/response names and app reuse on 2026-10-05)
4
-
5
- Supersedes the command-opaque/request-name display rules of ADR 0021 and the
6
- request display examples of ADR 0024. Native lifecycle, routing, receipt IDs,
7
- uncertain-effect handling and response formatting are unchanged.
8
-
9
- **Problem.** The owner wants readable request purposes, a useful short bash
10
- preview, no tool names in any request, and reusable rules for a future app.
11
-
12
- **Example.**
13
-
14
- ```text
15
- → [tool] Check the weather
16
- node search.mjs "Shanghai weather" --count 5
17
- ✓ [tool] bash (0.8s)
18
- ```
19
-
20
- **Decision.**
21
-
22
- - Requests keep the leading arrow and bracketed type/parent label. Tool names
23
- do not appear as separate request labels or parenthetical suffixes. Responses
24
- keep the deployed format: marker, type/parent label, native name and elapsed
25
- time. This latest clarification replaces the earlier proposed hidden-bash
26
- response and option-5 parenthetical response examples.
27
- - Bash requests add a second line with at most 100 Unicode code points,
28
- including a trailing ellipsis when truncated. Screen the whole command
29
- before truncation. Recognized credential indicators suppress the entire
30
- preview; explicit URLs and common bare domains are defanged. Native
31
- execution and timeout enforcement remain unchanged.
32
- - Screening is conservative and best effort, not a guarantee against arbitrary
33
- unknown secrets. Do not restore raw tool outputs or document-content notices.
34
- - `src/agent/progress-format.ts` defines a transport-independent structured
35
- ProgressEvent and pure summarization, screening and text formatting functions.
36
- The native observer creates safe request/response events; iMessage is the
37
- current plain-text adapter. Future apps can render event fields and reuse
38
- the safety functions without parsing iMessage text or copying its lifecycle.
39
- - The event retains the native name internally, allowing app rendering and
40
- response formatting, even though request text omits it. Raw command strings
41
- do not belong in exported progress events; only screened previews do.
42
- - No app transport, new scheduler, listener, database or delivery replay is
43
- introduced in this change. A future app connection must wire its own
44
- delivery/receipt policy explicitly.
45
-
46
- **Verification.** Isolated regressions cover the request/response event format,
47
- all-request name omission, native command execution/failure, preview length and
48
- Unicode, screening before truncation, credential suppression, URL defanging,
49
- child attribution, unknown receipts and no restart replay.
@@ -1,16 +0,0 @@
1
- # 0026. Inline command-only requests
2
-
3
- Status: accepted (owner specified `bash: <command>` and a 50-character limit on 2026-10-05)
4
-
5
- Supersedes the request-name omission, second-line preview and 100-character
6
- limit in ADR 0025. Preserve shared ProgressEvent data, screening, native
7
- execution, ownership, response formatting and receipt/recovery rules.
8
-
9
- **Example.** `→ [tool] bash: printf hi`, then `✓ [tool] bash (0.8s)`.
10
- Other tools retain the screenshot format, e.g. `→ [tool] read: path=/tmp/a.jpg`.
11
-
12
- **Decision.** Requests show native name and safe arguments inline. Bash uses
13
- only its screened command preview, not purpose/description text. The preview
14
- is at most 50 Unicode code points including an ellipsis when truncated.
15
- Screen the entire original command before truncation. No actual execution
16
- limit or output handling changes. Response notices remain unchanged.
@@ -1,10 +0,0 @@
1
- # 0027. Modest command preview width
2
-
3
- Status: accepted (owner delegated a slightly longer preview on 2026-10-05)
4
-
5
- Supersedes only ADR 0026's fixed 50-character width. The current default is
6
- 80 Unicode code points, including a trailing ellipsis when truncated. This
7
- balances useful context with phone readability. Keep the same inline
8
- `→ [tool] bash: <screened command>` format and unchanged response notices.
9
- Whole-command screening still occurs before truncation; no purpose text,
10
- raw output, tool execution or channel architecture changes.
@@ -1,8 +0,0 @@
1
- # 0028. Use 120 characters for command previews
2
-
3
- Status: accepted (owner selected120 after viewing80/120/150/180 examples on 2026-10-05)
4
-
5
- Supersedes only ADR 0027's80-character default. Show at most120 Unicode code
6
- points in the command portion, including a trailing ellipsis when truncated.
7
- Retain the inline command-only request, existing response, whole-command
8
- screening before truncation and transport-independent event/formatter.
@@ -1,33 +0,0 @@
1
- # 0030. Share a versioned web read cache
2
-
3
- Status: rejected (owner decided on 2026-10-06: a cold read takes about 40 ms, and every commit invalidated the cache anyway; the cache was removed)
4
-
5
- **Context.** The chat overview requests each conversation separately and repeats
6
- reads on refresh and navigation. Large native payloads include model-only data
7
- that the page never renders. Time-based caching would hide recent changes.
8
-
9
- **Decision.** Keep one bounded, process-local cache in `web/`, shared by pages
10
- and read-only APIs. Read through the owning Harness, never its storage files.
11
- Every non-empty Durable commit changes the native cache version. File-backed
12
- views validate inode, size and nanosecond modification/change timestamps on
13
- each access; enumerate memory namespaces on each request to detect additions
14
- and removals. Coalesce concurrent reads and recheck the version after loading;
15
- retry if it changed. Do not retain rejected reads or oversized results.
16
-
17
- Limit the cache to 128 entries and a 16 MiB serialized-size budget using
18
- least-recently-used eviction. This budget is not an exact JavaScript heap limit.
19
- Do not cache model health requests or resolved registry-dependent agent choices.
20
-
21
- Embed display-only chat data in the initial HTML and batch overview refreshes.
22
- Keep existing native data response shapes. SSE readiness includes a process and
23
- revision marker so the client can detect changes between HTML loading and stream
24
- attachment, without always fetching the initial view twice. Refreshes already
25
- in flight do not discard subsequent change notices.
26
-
27
- **Consequences.** Restart discards the cache. There is no second durable state,
28
- execution log, writer or model call. A response reflects versions checked while
29
- it is read; changes during network transit still require a later refresh. File
30
- freshness relies on filesystem metadata, not a fixed stale-data interval.
31
-
32
- **Rejected.** Browser-local copies as the shared cache, fixed cache TTLs,
33
- persistent materialized views, and rebuilding all page data on every commit.
@@ -1,32 +0,0 @@
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.
@@ -1,23 +0,0 @@
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.
@@ -1,36 +0,0 @@
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.
@@ -1,56 +0,0 @@
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.
@@ -1,37 +0,0 @@
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.
@@ -1,30 +0,0 @@
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.
@@ -1,25 +0,0 @@
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.
@@ -1,24 +0,0 @@
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.
@@ -1,44 +0,0 @@
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.
@@ -1,28 +0,0 @@
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.
@@ -1,44 +0,0 @@
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.
@@ -1,23 +0,0 @@
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.
@@ -1,32 +0,0 @@
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.
@@ -1,51 +0,0 @@
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.