@tekmidian/pai 0.17.0 → 0.18.1

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 (119) hide show
  1. package/dist/auto-route-tE6ymgYb.mjs +86 -0
  2. package/dist/auto-route-tE6ymgYb.mjs.map +1 -0
  3. package/dist/checkpoint-block-CkvwYA5y.mjs +1062 -0
  4. package/dist/checkpoint-block-CkvwYA5y.mjs.map +1 -0
  5. package/dist/cli/index.mjs +6 -5
  6. package/dist/cli/index.mjs.map +1 -1
  7. package/dist/cli/program.d.mts.map +1 -1
  8. package/dist/cli/program.mjs +7 -5
  9. package/dist/cli/program.mjs.map +1 -1
  10. package/dist/clusters-CRXU2T6Z.mjs +201 -0
  11. package/dist/clusters-CRXU2T6Z.mjs.map +1 -0
  12. package/dist/config-7UiKVmbE.mjs +203 -0
  13. package/dist/config-7UiKVmbE.mjs.map +1 -0
  14. package/dist/config-CcdkNSWa.mjs +204 -0
  15. package/dist/config-CcdkNSWa.mjs.map +1 -0
  16. package/dist/daemon/index.mjs +9 -9
  17. package/dist/daemon-DPHtKQB2.mjs +1576 -0
  18. package/dist/daemon-DPHtKQB2.mjs.map +1 -0
  19. package/dist/daemon-Pm6crudb.mjs +1576 -0
  20. package/dist/daemon-Pm6crudb.mjs.map +1 -0
  21. package/dist/daemon-mcp/index.mjs +2 -2
  22. package/dist/detector-BGw8SNWe.mjs +74 -0
  23. package/dist/detector-BGw8SNWe.mjs.map +1 -0
  24. package/dist/factory-1UI19STL.mjs +72 -0
  25. package/dist/factory-1UI19STL.mjs.map +1 -0
  26. package/dist/indexer-backend-B93q9ICi.mjs +299 -0
  27. package/dist/indexer-backend-B93q9ICi.mjs.map +1 -0
  28. package/dist/ipc-client-aVKVERjJ.mjs +152 -0
  29. package/dist/ipc-client-aVKVERjJ.mjs.map +1 -0
  30. package/dist/kg-entity-r8duqhi9.mjs +176 -0
  31. package/dist/kg-entity-r8duqhi9.mjs.map +1 -0
  32. package/dist/latent-ideas-CHrgdkSW.mjs +191 -0
  33. package/dist/latent-ideas-CHrgdkSW.mjs.map +1 -0
  34. package/dist/main-resolver-BozXCqpl.mjs +1340 -0
  35. package/dist/main-resolver-BozXCqpl.mjs.map +1 -0
  36. package/dist/neighborhood-jPQBkbB-.mjs +135 -0
  37. package/dist/neighborhood-jPQBkbB-.mjs.map +1 -0
  38. package/dist/note-context-D2S2sR38.mjs +126 -0
  39. package/dist/note-context-D2S2sR38.mjs.map +1 -0
  40. package/dist/pick-44g9gnCi.mjs +12329 -0
  41. package/dist/pick-44g9gnCi.mjs.map +1 -0
  42. package/dist/pick-BLU3NUzF.mjs +12602 -0
  43. package/dist/pick-BLU3NUzF.mjs.map +1 -0
  44. package/dist/pick-BROEyWxI.mjs +12665 -0
  45. package/dist/pick-BROEyWxI.mjs.map +1 -0
  46. package/dist/pick-BRdJ4gpT.mjs +12666 -0
  47. package/dist/pick-BRdJ4gpT.mjs.map +1 -0
  48. package/dist/pick-B_ZSZxR4.mjs +12301 -0
  49. package/dist/pick-B_ZSZxR4.mjs.map +1 -0
  50. package/dist/pick-Bl-g6BzM.mjs +12300 -0
  51. package/dist/pick-Bl-g6BzM.mjs.map +1 -0
  52. package/dist/pick-C1Gfz3nN.mjs +12587 -0
  53. package/dist/pick-C1Gfz3nN.mjs.map +1 -0
  54. package/dist/pick-Cj2seRfQ.mjs +12531 -0
  55. package/dist/pick-Cj2seRfQ.mjs.map +1 -0
  56. package/dist/pick-CpZSdQcU.mjs +12587 -0
  57. package/dist/pick-CpZSdQcU.mjs.map +1 -0
  58. package/dist/pick-DAHBqsS_.mjs +12665 -0
  59. package/dist/pick-DAHBqsS_.mjs.map +1 -0
  60. package/dist/pick-HsJkYu5D.mjs +12500 -0
  61. package/dist/pick-HsJkYu5D.mjs.map +1 -0
  62. package/dist/pick-SxeegWzK.mjs +12126 -0
  63. package/dist/pick-SxeegWzK.mjs.map +1 -0
  64. package/dist/pick-Y-Bnmlqx.mjs +12571 -0
  65. package/dist/pick-Y-Bnmlqx.mjs.map +1 -0
  66. package/dist/pick-sXVKiZhC.mjs +12498 -0
  67. package/dist/pick-sXVKiZhC.mjs.map +1 -0
  68. package/dist/postgres-D96XWfwI.mjs +891 -0
  69. package/dist/postgres-D96XWfwI.mjs.map +1 -0
  70. package/dist/query-feedback-CdBJ2icj.mjs +76 -0
  71. package/dist/query-feedback-CdBJ2icj.mjs.map +1 -0
  72. package/dist/runtime-paths-B0P1TvUr.mjs +50 -0
  73. package/dist/runtime-paths-B0P1TvUr.mjs.map +1 -0
  74. package/dist/sqlite-CR9aMImG.mjs +271 -0
  75. package/dist/sqlite-CR9aMImG.mjs.map +1 -0
  76. package/dist/state-DTvy-jRB.mjs +102 -0
  77. package/dist/state-DTvy-jRB.mjs.map +1 -0
  78. package/dist/themes-HzMKPTas.mjs +148 -0
  79. package/dist/themes-HzMKPTas.mjs.map +1 -0
  80. package/dist/tools-DuorP_SS.mjs +1939 -0
  81. package/dist/tools-DuorP_SS.mjs.map +1 -0
  82. package/dist/trace-Bf7OprC5.mjs +137 -0
  83. package/dist/trace-Bf7OprC5.mjs.map +1 -0
  84. package/dist/vault-indexer-qAfX09RY.mjs +536 -0
  85. package/dist/vault-indexer-qAfX09RY.mjs.map +1 -0
  86. package/dist/work-queue-worker-Bov9eWMC.mjs +1856 -0
  87. package/dist/work-queue-worker-Bov9eWMC.mjs.map +1 -0
  88. package/dist/zettelkasten-DcZk-XSm.mjs +1063 -0
  89. package/dist/zettelkasten-DcZk-XSm.mjs.map +1 -0
  90. package/docs/commands/README.md +7 -0
  91. package/docs/commands/backup.md +1 -1
  92. package/docs/commands/clear-names.md +1 -1
  93. package/docs/commands/daemon.md +1 -1
  94. package/docs/commands/db.md +1 -1
  95. package/docs/commands/end.md +1 -1
  96. package/docs/commands/help.md +1 -1
  97. package/docs/commands/identity.md +65 -0
  98. package/docs/commands/kg.md +1 -1
  99. package/docs/commands/mcp.md +1 -1
  100. package/docs/commands/memory.md +1 -1
  101. package/docs/commands/notify.md +1 -1
  102. package/docs/commands/observation.md +1 -1
  103. package/docs/commands/obsidian.md +1 -1
  104. package/docs/commands/pause.md +1 -1
  105. package/docs/commands/project.md +1 -1
  106. package/docs/commands/projects.md +1 -1
  107. package/docs/commands/registry.md +1 -1
  108. package/docs/commands/restore.md +1 -1
  109. package/docs/commands/session.md +1 -1
  110. package/docs/commands/sessions.md +1 -1
  111. package/docs/commands/setup.md +1 -1
  112. package/docs/commands/shell-init.md +1 -1
  113. package/docs/commands/skill.md +1 -1
  114. package/docs/commands/task.md +15 -2
  115. package/docs/commands/topic.md +1 -1
  116. package/docs/commands/update.md +1 -1
  117. package/docs/commands/zettel.md +1 -1
  118. package/docs/task-bus.md +185 -0
  119. package/package.json +1 -1
@@ -16,6 +16,7 @@ pai task <subcommand> [options]
16
16
 
17
17
  | Command | Description |
18
18
  |---------|-------------|
19
+ | [`pai task projects`](#pai-task-projects) | Show which sessions can be given work from the tracker, and create the missing projects |
19
20
  | [`pai task list`](#pai-task-list) | List open tasks on the bus |
20
21
  | [`pai task add <title>`](#pai-task-add-title) | File a task onto the bus |
21
22
  | [`pai task dispatch`](#pai-task-dispatch) | Hand open tasks to the PAI sessions that own them |
@@ -24,6 +25,18 @@ pai task <subcommand> [options]
24
25
  | [`pai task config`](#pai-task-config) | View or change task bus settings without running the full setup wizard |
25
26
  | [`pai task done <id>`](#pai-task-done-id) | Mark a task complete on the tracker |
26
27
 
28
+ ### pai task projects
29
+
30
+ Show which sessions can be given work from the tracker, and create the missing projects
31
+
32
+ **Options**
33
+
34
+ | Option | Description | Default |
35
+ |--------|-------------|---------|
36
+ | `--create <names...>` | Create tracker projects for these session names | |
37
+ | `--create-all` | Create a project for every session that has none | |
38
+
39
+
27
40
  ### pai task list
28
41
 
29
42
  List open tasks on the bus
@@ -55,7 +68,7 @@ File a task onto the bus
55
68
  |--------|-------------|---------|
56
69
  | `--owner <project>` | PAI project that owns this (adds a pai: label) | |
57
70
  | `--body <text>` | Full procedure and reasoning — not just a restatement of the title | |
58
- | `--due <date>` | Due date (ISO or natural language) | |
71
+ | `--due <when>` | Due date: ISO, natural language, or a recurrence ("every monday at 9") | |
59
72
  | `--priority <p>` | p1 (highest) … p4 (default) | |
60
73
  | `--url <url>` | Reference — prefer a hook:// URL over a file path | |
61
74
  | `--into <sub-project>` | File into this sub-project under the bus root, creating it if absent | |
@@ -142,7 +155,7 @@ Mark a task complete on the tracker
142
155
 
143
156
  ## See also
144
157
 
145
- [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai session`](session.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai topic`](topic.md) · [`pai update`](update.md) · [`pai zettel`](zettel.md)
158
+ [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai identity`](identity.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai session`](session.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai topic`](topic.md) · [`pai update`](update.md) · [`pai zettel`](zettel.md)
146
159
 
147
160
  Run `pai help <area>` to read any of these in the terminal.
148
161
 
@@ -40,7 +40,7 @@ Exit code 1 if a shift is detected (useful for hooks).
40
40
 
41
41
  ## See also
42
42
 
43
- [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai session`](session.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai update`](update.md) · [`pai zettel`](zettel.md)
43
+ [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai identity`](identity.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai session`](session.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai update`](update.md) · [`pai zettel`](zettel.md)
44
44
 
45
45
  Run `pai help <area>` to read any of these in the terminal.
46
46
 
@@ -12,7 +12,7 @@ pai update
12
12
 
13
13
  ## See also
14
14
 
15
- [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai session`](session.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai zettel`](zettel.md)
15
+ [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai identity`](identity.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai session`](session.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai zettel`](zettel.md)
16
16
 
17
17
  Run `pai help <area>` to read any of these in the terminal.
18
18
 
@@ -145,7 +145,7 @@ pai zettel health
145
145
 
146
146
  ## See also
147
147
 
148
- [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai session`](session.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai update`](update.md)
148
+ [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai identity`](identity.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai session`](session.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai update`](update.md)
149
149
 
150
150
  Run `pai help <area>` to read any of these in the terminal.
151
151
 
@@ -0,0 +1,185 @@
1
+ # Task bus — using a tracker as an input channel
2
+
3
+ File a task from your phone. A session picks it up, does the work, and ticks it off.
4
+
5
+ This document is the setup guide. For why the design splits the way it does, see
6
+ `Notes/docs/task-bus.md`.
7
+
8
+ ---
9
+
10
+ ## Two paths, and they are not the same feature
11
+
12
+ Tasks can reach a session two ways. They have very different setup costs, and
13
+ only one of them carries comments.
14
+
15
+ | | **Path 1 — PAI polls** | **Path 2 — webhooks** |
16
+ |---|---|---|
17
+ | Who runs it | PAI (`src/tasks/poller.ts`), launchd | AIBroker receiver |
18
+ | Latency | One poll interval | Immediate |
19
+ | New tasks | yes | yes |
20
+ | **Comments on a task** | **no** | **yes** |
21
+ | **Reminders (`reminder:fired`)** | **no** | **yes** |
22
+ | Needs a public HTTPS endpoint | no | yes |
23
+ | Needs an OAuth grant | no | yes |
24
+ | Platform | any | macOS + iTerm2 |
25
+
26
+ Path 2 is a strict superset in capability **and** in setup cost. Start with
27
+ path 1; add path 2 when you want to talk back to a task rather than only file
28
+ one.
29
+
30
+ The distinction that matters most: **a comment is how you correct work already
31
+ dispatched** — "no, do it this way instead". On path 1 that correction is
32
+ silently dropped, because nothing is subscribed to it. If you intend to have a
33
+ conversation with a task, you need path 2.
34
+
35
+ Scheduling note: **due dates push nothing.** Only reminders fire. A task due
36
+ Tuesday sits there; a task with a reminder for Tuesday arrives. This is why path
37
+ 2 needs no timer anywhere.
38
+
39
+ ---
40
+
41
+ ## Path 1 — PAI polls
42
+
43
+ ### 1. Get a Todoist API token
44
+
45
+ Todoist → Settings → Integrations → Developer → API token.
46
+
47
+ ### 2. Configure
48
+
49
+ In `~/.config/pai/config.json`:
50
+
51
+ ```jsonc
52
+ {
53
+ "tasks": {
54
+ "enabled": true,
55
+ "autoDispatch": true, // false = report ownership, do not dispatch
56
+ "providers": {
57
+ "todoist": {
58
+ "enabled": true,
59
+ "apiKey": "<your API token>",
60
+ "rootProjectId": "<id of the parent project holding your session projects>",
61
+ "findingsSectionId": "<id of the section where findings are filed>"
62
+ }
63
+ }
64
+ }
65
+ }
66
+ ```
67
+
68
+ `rootProjectId` is the **parent** project. Each session that should own work gets
69
+ a sub-project under it, named after the session:
70
+
71
+ ```
72
+ Claude 🤖 ← rootProjectId
73
+ ├── PAI
74
+ ├── AIBroker
75
+ ├── Jobs Matthias
76
+ └── Jobs Grazyna
77
+ ```
78
+
79
+ Ownership is the sub-project a task sits in. Filing from a phone is then one
80
+ project pick rather than remembering a label.
81
+
82
+ Never resolve a project by name-search at dispatch time — record the id. Two
83
+ projects can share a name, and the search will not tell you.
84
+
85
+ ### 3. Install the schedule
86
+
87
+ ```sh
88
+ pai task schedule install # launchd, StartInterval
89
+ pai task schedule status
90
+ ```
91
+
92
+ A tick with nothing to do costs one API call and no tokens — it carries no LLM.
93
+
94
+ ### 4. Check it
95
+
96
+ ```sh
97
+ pai task list # what the bus can see
98
+ pai task dispatch --dry-run # who would receive what
99
+ pai task poll # run one tick by hand
100
+ ```
101
+
102
+ ### Without AIBroker
103
+
104
+ Path 1 degrades rather than breaking. With AIBroker, PAI dispatches and spawns
105
+ sessions. Without it, PAI reports:
106
+
107
+ ```
108
+ 3 tasks belong to BirnPartners — run `pai birnpartners`
109
+ ```
110
+
111
+ Same feature, you do the routing. This is deliberate: PAI ships cross-platform,
112
+ AIBroker is macOS + iTerm2, and putting the task logic in AIBroker would make
113
+ this degradation impossible.
114
+
115
+ ---
116
+
117
+ ## Path 2 — webhooks
118
+
119
+ Owned by AIBroker. **The procedure lives in AIBroker's `docs/todoist.md`** and is
120
+ maintained there; it is not duplicated here, because a copied procedure drifts.
121
+
122
+ What you will need:
123
+
124
+ - A **public HTTPS endpoint on port 443** terminating TLS and forwarding to the
125
+ receiver on `127.0.0.1:8766`. Tailscale Funnel, Cloudflare Tunnel, or Caddy on
126
+ a real domain all work.
127
+ - A Todoist app in the **App Management** console, with a client id and secret.
128
+ - Event subscriptions — at minimum `item:added`, `item:completed`,
129
+ `note:added`, `reminder:fired`.
130
+ - `TODOIST_CLIENT_SECRET`, `TODOIST_CLIENT_ID`, `TODOIST_INGRESS_PROJECTS` and
131
+ `TODOIST_DEFAULT_OWNER` in `~/.aibroker/env`.
132
+ - **An OAuth grant, completed per user** — `aibroker todoist auth`.
133
+
134
+ ### Four facts that cost real time
135
+
136
+ These are recorded here because each one fails *silently* and you will not
137
+ diagnose it from the symptom.
138
+
139
+ **1. The callback URL cannot contain a port.** Todoist rejects it —
140
+ "must use HTTPS and cannot specify ports for security reasons". The App
141
+ Management form does not surface the error: it accepts the text, Activate
142
+ appears to do nothing, and the status stays "Not configured" forever. With
143
+ Tailscale this means Funnel on **443**, not Serve and not 8443. Serve is
144
+ tailnet-only and Todoist's servers are not in your tailnet.
145
+
146
+ **2. Testing from inside your own tailnet proves nothing.** MagicDNS resolves
147
+ the Funnel hostname to its tailnet address, so `curl` connects peer-to-peer and
148
+ returns a convincing 401 while the public path is entirely untested. Force the
149
+ public ingress with `curl --resolve` against an address from a public DNS
150
+ server.
151
+
152
+ **3. Creating the app does not switch on delivery to your own account.**
153
+ Webhooks are enabled per user by an OAuth round trip, and the console's
154
+ "Install for myself" button is not that flow. `aibroker todoist auth`. The
155
+ console's "Number of users" is not a reliable signal — it has read 0 for an
156
+ account that had genuinely authorised. Trust `aibroker todoist status`.
157
+
158
+ **4. A lapsed grant looks like a healthy channel.** Webhooks are verified with
159
+ the client *secret*, not the token, so **task delivery keeps working**. What
160
+ breaks is everything needing the API: comment routing (a comment payload has no
161
+ project or labels, so the parent must be fetched) and replying on a task. The
162
+ signature is `401` with `error_code 477` and a `retry_after` that climbs —
163
+ 3, 7, 65, 129 seconds. That climb is throttling stacked on a dead credential, so
164
+ retrying makes it worse. The reliable tell is the consent dialog appearing again
165
+ for a URL that used to redirect straight through. Fix: `aibroker todoist auth`
166
+ and one click.
167
+
168
+ ---
169
+
170
+ ## Conventions
171
+
172
+ **Duplicate titles.** Two open tasks with the same title in one project is a
173
+ real hazard: a reply lands on the sibling you are not watching, and it is
174
+ indistinguishable from being ignored. On delivery the receiver counts open
175
+ tasks sharing a title and appends a note naming the count. Say which id you
176
+ answered on.
177
+
178
+ **Agent-authored content is marked** so a reply posted by a session does not
179
+ come back as a fresh instruction and loop.
180
+
181
+ **A dispatch that cannot land must be loud.** If the target session is gone and
182
+ no project mapping exists, the work cannot be delivered — that is recorded as
183
+ its own outcome and escalated, never dropped quietly. Deleting a project when
184
+ its session disappears is wrong: tasks filed against a dormant session queue
185
+ and dispatch when it next launches.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekmidian/pai",
3
- "version": "0.17.0",
3
+ "version": "0.18.1",
4
4
  "description": "PAI Knowledge OS — Personal AI Infrastructure with federated memory and project management",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",