@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.
- package/dist/auto-route-tE6ymgYb.mjs +86 -0
- package/dist/auto-route-tE6ymgYb.mjs.map +1 -0
- package/dist/checkpoint-block-CkvwYA5y.mjs +1062 -0
- package/dist/checkpoint-block-CkvwYA5y.mjs.map +1 -0
- package/dist/cli/index.mjs +6 -5
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/program.d.mts.map +1 -1
- package/dist/cli/program.mjs +7 -5
- package/dist/cli/program.mjs.map +1 -1
- package/dist/clusters-CRXU2T6Z.mjs +201 -0
- package/dist/clusters-CRXU2T6Z.mjs.map +1 -0
- package/dist/config-7UiKVmbE.mjs +203 -0
- package/dist/config-7UiKVmbE.mjs.map +1 -0
- package/dist/config-CcdkNSWa.mjs +204 -0
- package/dist/config-CcdkNSWa.mjs.map +1 -0
- package/dist/daemon/index.mjs +9 -9
- package/dist/daemon-DPHtKQB2.mjs +1576 -0
- package/dist/daemon-DPHtKQB2.mjs.map +1 -0
- package/dist/daemon-Pm6crudb.mjs +1576 -0
- package/dist/daemon-Pm6crudb.mjs.map +1 -0
- package/dist/daemon-mcp/index.mjs +2 -2
- package/dist/detector-BGw8SNWe.mjs +74 -0
- package/dist/detector-BGw8SNWe.mjs.map +1 -0
- package/dist/factory-1UI19STL.mjs +72 -0
- package/dist/factory-1UI19STL.mjs.map +1 -0
- package/dist/indexer-backend-B93q9ICi.mjs +299 -0
- package/dist/indexer-backend-B93q9ICi.mjs.map +1 -0
- package/dist/ipc-client-aVKVERjJ.mjs +152 -0
- package/dist/ipc-client-aVKVERjJ.mjs.map +1 -0
- package/dist/kg-entity-r8duqhi9.mjs +176 -0
- package/dist/kg-entity-r8duqhi9.mjs.map +1 -0
- package/dist/latent-ideas-CHrgdkSW.mjs +191 -0
- package/dist/latent-ideas-CHrgdkSW.mjs.map +1 -0
- package/dist/main-resolver-BozXCqpl.mjs +1340 -0
- package/dist/main-resolver-BozXCqpl.mjs.map +1 -0
- package/dist/neighborhood-jPQBkbB-.mjs +135 -0
- package/dist/neighborhood-jPQBkbB-.mjs.map +1 -0
- package/dist/note-context-D2S2sR38.mjs +126 -0
- package/dist/note-context-D2S2sR38.mjs.map +1 -0
- package/dist/pick-44g9gnCi.mjs +12329 -0
- package/dist/pick-44g9gnCi.mjs.map +1 -0
- package/dist/pick-BLU3NUzF.mjs +12602 -0
- package/dist/pick-BLU3NUzF.mjs.map +1 -0
- package/dist/pick-BROEyWxI.mjs +12665 -0
- package/dist/pick-BROEyWxI.mjs.map +1 -0
- package/dist/pick-BRdJ4gpT.mjs +12666 -0
- package/dist/pick-BRdJ4gpT.mjs.map +1 -0
- package/dist/pick-B_ZSZxR4.mjs +12301 -0
- package/dist/pick-B_ZSZxR4.mjs.map +1 -0
- package/dist/pick-Bl-g6BzM.mjs +12300 -0
- package/dist/pick-Bl-g6BzM.mjs.map +1 -0
- package/dist/pick-C1Gfz3nN.mjs +12587 -0
- package/dist/pick-C1Gfz3nN.mjs.map +1 -0
- package/dist/pick-Cj2seRfQ.mjs +12531 -0
- package/dist/pick-Cj2seRfQ.mjs.map +1 -0
- package/dist/pick-CpZSdQcU.mjs +12587 -0
- package/dist/pick-CpZSdQcU.mjs.map +1 -0
- package/dist/pick-DAHBqsS_.mjs +12665 -0
- package/dist/pick-DAHBqsS_.mjs.map +1 -0
- package/dist/pick-HsJkYu5D.mjs +12500 -0
- package/dist/pick-HsJkYu5D.mjs.map +1 -0
- package/dist/pick-SxeegWzK.mjs +12126 -0
- package/dist/pick-SxeegWzK.mjs.map +1 -0
- package/dist/pick-Y-Bnmlqx.mjs +12571 -0
- package/dist/pick-Y-Bnmlqx.mjs.map +1 -0
- package/dist/pick-sXVKiZhC.mjs +12498 -0
- package/dist/pick-sXVKiZhC.mjs.map +1 -0
- package/dist/postgres-D96XWfwI.mjs +891 -0
- package/dist/postgres-D96XWfwI.mjs.map +1 -0
- package/dist/query-feedback-CdBJ2icj.mjs +76 -0
- package/dist/query-feedback-CdBJ2icj.mjs.map +1 -0
- package/dist/runtime-paths-B0P1TvUr.mjs +50 -0
- package/dist/runtime-paths-B0P1TvUr.mjs.map +1 -0
- package/dist/sqlite-CR9aMImG.mjs +271 -0
- package/dist/sqlite-CR9aMImG.mjs.map +1 -0
- package/dist/state-DTvy-jRB.mjs +102 -0
- package/dist/state-DTvy-jRB.mjs.map +1 -0
- package/dist/themes-HzMKPTas.mjs +148 -0
- package/dist/themes-HzMKPTas.mjs.map +1 -0
- package/dist/tools-DuorP_SS.mjs +1939 -0
- package/dist/tools-DuorP_SS.mjs.map +1 -0
- package/dist/trace-Bf7OprC5.mjs +137 -0
- package/dist/trace-Bf7OprC5.mjs.map +1 -0
- package/dist/vault-indexer-qAfX09RY.mjs +536 -0
- package/dist/vault-indexer-qAfX09RY.mjs.map +1 -0
- package/dist/work-queue-worker-Bov9eWMC.mjs +1856 -0
- package/dist/work-queue-worker-Bov9eWMC.mjs.map +1 -0
- package/dist/zettelkasten-DcZk-XSm.mjs +1063 -0
- package/dist/zettelkasten-DcZk-XSm.mjs.map +1 -0
- package/docs/commands/README.md +7 -0
- package/docs/commands/backup.md +1 -1
- package/docs/commands/clear-names.md +1 -1
- package/docs/commands/daemon.md +1 -1
- package/docs/commands/db.md +1 -1
- package/docs/commands/end.md +1 -1
- package/docs/commands/help.md +1 -1
- package/docs/commands/identity.md +65 -0
- package/docs/commands/kg.md +1 -1
- package/docs/commands/mcp.md +1 -1
- package/docs/commands/memory.md +1 -1
- package/docs/commands/notify.md +1 -1
- package/docs/commands/observation.md +1 -1
- package/docs/commands/obsidian.md +1 -1
- package/docs/commands/pause.md +1 -1
- package/docs/commands/project.md +1 -1
- package/docs/commands/projects.md +1 -1
- package/docs/commands/registry.md +1 -1
- package/docs/commands/restore.md +1 -1
- package/docs/commands/session.md +1 -1
- package/docs/commands/sessions.md +1 -1
- package/docs/commands/setup.md +1 -1
- package/docs/commands/shell-init.md +1 -1
- package/docs/commands/skill.md +1 -1
- package/docs/commands/task.md +15 -2
- package/docs/commands/topic.md +1 -1
- package/docs/commands/update.md +1 -1
- package/docs/commands/zettel.md +1 -1
- package/docs/task-bus.md +185 -0
- package/package.json +1 -1
package/docs/commands/task.md
CHANGED
|
@@ -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 <
|
|
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
|
|
package/docs/commands/topic.md
CHANGED
|
@@ -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
|
|
package/docs/commands/update.md
CHANGED
|
@@ -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
|
|
package/docs/commands/zettel.md
CHANGED
|
@@ -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
|
|
package/docs/task-bus.md
ADDED
|
@@ -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.
|