taskchef 6.0.0 → 6.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskchef",
3
- "version": "6.0.0",
3
+ "version": "6.1.0",
4
4
  "description": "Dispatch work from a data-only workspace to visible Codex project tasks.",
5
5
  "author": {
6
6
  "name": "Favo Yang",
@@ -33,6 +33,9 @@
33
33
  "$taskchef-delegate Dispatch this request to the right project.",
34
34
  "$taskchef-report Report on work in the TaskChef task history."
35
35
  ],
36
- "brandColor": "#D97706"
36
+ "brandColor": "#D97706",
37
+ "composerIcon": "./assets/taskchef.svg",
38
+ "logo": "./assets/taskchef.svg",
39
+ "logoDark": "./assets/taskchef-dark.svg"
37
40
  }
38
41
  }
@@ -0,0 +1,9 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
2
+ <rect x="2" y="2" width="44" height="44" rx="11" fill="#F59E0B"/>
3
+ <path d="M15 37V27.5C11.9 26.3 10 23.6 10 20.5C10 16.4 13.4 13 17.5 13C19 10 21.2 8.5 24 8.5C26.8 8.5 29 10 30.5 13C34.6 13 38 16.4 38 20.5C38 23.6 36.1 26.3 33 27.5V37H15Z" fill="#FFFBEB"/>
4
+ <path d="M19 24L22 27L28.5 20.5" stroke="#78350F" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
5
+ <path d="M24 28V32M24 32H19M24 32H29" stroke="#78350F" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
6
+ <circle cx="19" cy="32" r="2" fill="#78350F"/>
7
+ <circle cx="29" cy="32" r="2" fill="#78350F"/>
8
+ <path d="M15 37H33" stroke="#78350F" stroke-width="3" stroke-linecap="round"/>
9
+ </svg>
@@ -0,0 +1,9 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
2
+ <rect x="2" y="2" width="44" height="44" rx="11" fill="#D97706"/>
3
+ <path d="M15 37V27.5C11.9 26.3 10 23.6 10 20.5C10 16.4 13.4 13 17.5 13C19 10 21.2 8.5 24 8.5C26.8 8.5 29 10 30.5 13C34.6 13 38 16.4 38 20.5C38 23.6 36.1 26.3 33 27.5V37H15Z" fill="#FFF7ED"/>
4
+ <path d="M19 24L22 27L28.5 20.5" stroke="#7C2D12" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
5
+ <path d="M24 28V32M24 32H19M24 32H29" stroke="#7C2D12" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
6
+ <circle cx="19" cy="32" r="2" fill="#7C2D12"/>
7
+ <circle cx="29" cy="32" r="2" fill="#7C2D12"/>
8
+ <path d="M15 37H33" stroke="#7C2D12" stroke-width="3" stroke-linecap="round"/>
9
+ </svg>
@@ -4,63 +4,213 @@ TaskChef stores a durable local task history while Codex owns execution. The
4
4
  dispatcher records intent, the executor registers its own identity, and only
5
5
  the executor reports semantic outcomes.
6
6
 
7
- ## Lifecycle
8
-
9
- 1. `prepare_dispatch` returns a fresh task UUID, exact marker, timestamp, and
10
- configured projects.
11
- 2. The dispatcher calls `record_task` with the complete marked instruction and
12
- `threadId: null` before native creation.
13
- 3. The dispatcher creates the Codex task and returns immediately. A durable or
14
- provisional creation result is never treated as authority to link the
15
- record.
16
- 4. As its first TaskChef action, the executor reads its own durable native
17
- thread ID and calls `link_task(taskId, threadId)`.
18
- 5. Before ending a turn with a semantic outcome, the executor reads that exact
19
- thread, takes the current turn ID, and calls `report_result`.
20
-
21
- There is no task listing, candidate read, marker search, wait, retry loop,
22
- transcript read, or hook in the dispatch path. The existing filesystem watcher
23
- notices the atomic `link_task` rewrite and immediately refreshes the dashboard.
24
-
25
- ## Identity guarantees
7
+ ## Key terminology
8
+
9
+ The central identity rule is: **the executor child links itself**. The
10
+ dispatcher may create the child, but it never treats its own thread, a parent
11
+ thread, or a provisional creation handle as the executor's durable identity.
12
+
13
+ | Term | Meaning |
14
+ | --- | --- |
15
+ | TaskChef task ID | Stable UUID allocated by `prepare_dispatch`; it identifies the durable TaskChef record. |
16
+ | Exact marker | First-line correlation marker copied into the executor instruction; it binds that instruction to the pre-recorded TaskChef task. |
17
+ | Source or parent thread ID | The dispatcher/delegator context; never valid as the executor identity. |
18
+ | Executor thread ID | The child's own durable `CODEX_THREAD_ID`; the executor supplies it to `link_task`. |
19
+ | Provisional client thread ID | Temporary native creation handle; useful for creation UI, but never identity authority. |
20
+ | Turn ID | Current native turn UUIDv7 read from the exact executor thread; it proves result freshness. |
21
+ | `tasks.jsonl` | Durable append/rewrite history whose latest snapshot is shown by TaskChef. |
22
+
23
+ The diagrams below are intentionally small. Calls into **TaskChef MCP** name
24
+ the MCP function being invoked. Notes beside `tasks.jsonl` name the fields that
25
+ step populates or replaces.
26
+
27
+ ## Workflow 1: Prepare and record intent
28
+
29
+ The dispatcher first asks TaskChef to allocate routing and correlation values.
30
+ `prepare_dispatch` does not write a record. The dispatcher then embeds the exact
31
+ marker in the instruction and calls `record_task` **before** native creation, so
32
+ an executor can self-link as soon as its first turn starts.
33
+
34
+ ```mermaid
35
+ sequenceDiagram
36
+ autonumber
37
+ actor U as User
38
+ participant D as Dispatcher
39
+ participant M as TaskChef MCP
40
+ participant W as tasks.jsonl
41
+
42
+ U->>D: Delegation request
43
+ D->>M: prepare_dispatch()
44
+ M-->>D: taskId, marker, preparedAt, projects
45
+ Note over D,M: Allocate identity and routing only#59; no record written
46
+ D->>M: record_task(id, project, title, marked instruction, threadId=null)
47
+ M->>W: Append schema 4 snapshot
48
+ Note right of W: id, project, title, instruction, createdAt<br>threadId=null, status=working, summary=null, turnId=null<br>updatedAt=createdAt, updatedBy=dispatcher
49
+ M-->>D: Recorded task snapshot
50
+ ```
51
+
52
+ ## Workflow 2: Create and self-link the executor
53
+
54
+ After recording, the dispatcher creates the native Codex task and returns
55
+ immediately. A durable or provisional ID returned to the dispatcher is not
56
+ trusted as executor identity. The child reads its own `CODEX_THREAD_ID` and
57
+ uses `link_task` as its first TaskChef action.
26
58
 
27
59
  The exact marker correlates the child instruction with the pre-created record.
28
- The executor must use its native current thread ID, never the delegation
29
- `sourceThreadId`, parent task, inherited session identity, title, or provisional
30
- client ID.
31
-
32
- `link_task` runs under the workspace lock. It permits one atomic
33
- `null`-to-durable transition, rejects malformed or provisional IDs, rejects a
34
- thread already owned by another TaskChef task, rejects a different retry, and
35
- returns the existing snapshot for an identical retry.
36
-
37
- Custom MCP does not currently authenticate the calling Codex task. The thread
38
- ID is therefore a cooperative assertion inside TaskChef's local single-user
39
- trust boundary. The design prevents accidental parent/child confusion but does
40
- not claim resistance to a deliberately forged local MCP call.
41
-
42
- ## Failure and retry behavior
43
-
44
- If native creation fails after recording, the dispatcher writes one terminal
45
- `failed` result with null thread and turn IDs and a bounded summary. If the
46
- executor is interrupted, cancelled, cannot see `link_task`, or gets a rejected
47
- link, the record remains `working` with `threadId: null`. That visible
48
- link-pending state is retryable on a later turn. TaskChef never guesses or
49
- recovers identity through the dashboard.
50
-
51
- ## Result freshness
52
-
53
- Linked results require an exact thread-ID match and a non-null current turn ID.
54
- For self-linked schema 4 journeys, the native time-ordered Codex UUID must be
55
- strictly newer for every changed result; exact same-turn retries remain safe.
56
- Identical `report_result` retries are safe. A follow-up or resumed executor must
57
- read its exact task again and report the new turn ID; reusing the initial turn
58
- cannot establish freshness.
59
-
60
- The latest snapshot fields are `status`, bounded `summary`, `turnId`,
61
- `updatedAt`, and `updatedBy`. Historical `updatedBy: hook` values remain
62
- readable, but new installations contain no hook and new writes use `dispatcher`
63
- or `mcp`.
60
+ `link_task` atomically permits one `null`-to-durable transition, rejects a
61
+ malformed or reused ID, and makes the dashboard deep link target the child—not
62
+ the source, parent, or dispatcher thread.
63
+
64
+ ```mermaid
65
+ sequenceDiagram
66
+ autonumber
67
+ actor U as User
68
+ participant D as Dispatcher
69
+ participant C as Codex native tasks
70
+ participant E as Executor child
71
+ participant M as TaskChef MCP
72
+ participant W as tasks.jsonl
73
+ participant V as Dashboard
74
+
75
+ D->>C: Create task with marked instruction
76
+ C-->>D: Durable threadId or provisional clientThreadId
77
+ Note over D,C: Creation result is not executor identity authority
78
+ D-->>U: Created-task directive#59; dispatcher returns immediately
79
+ C->>E: Start initial executor turn
80
+ E->>E: Read own CODEX_THREAD_ID
81
+ E->>M: link_task(taskId, child threadId)
82
+ M->>W: Atomic identity registration
83
+ Note right of W: Set threadId=child UUIDv7<br>Set updatedAt and updatedBy=mcp<br>Keep status=working, summary=null, turnId=null
84
+ M-->>E: Self-linked task snapshot
85
+ W-->>V: Filesystem watcher refresh
86
+ Note right of V: Deep link targets the exact executor child
87
+ ```
88
+
89
+ ## Workflow 3: Report the current turn
90
+
91
+ Before ending with a semantic outcome, the executor reads its exact native
92
+ thread and obtains that turn's current UUIDv7. It then calls `report_result`
93
+ with its matching self-linked thread ID. The status is `completed`, `failed`,
94
+ or `needs_input`; the summary is concise and bounded.
95
+
96
+ Changed results must use a strictly newer turn ID. An identical same-turn retry
97
+ is idempotent, but reusing an old turn ID for a changed result cannot establish
98
+ freshness.
99
+
100
+ ```mermaid
101
+ sequenceDiagram
102
+ autonumber
103
+ participant E as Executor child
104
+ participant C as Codex native tasks
105
+ participant M as TaskChef MCP
106
+ participant W as tasks.jsonl
107
+ participant V as Dashboard
108
+
109
+ E->>C: Exact read of this executor thread
110
+ C-->>E: Current turnId UUIDv7
111
+ E->>M: report_result(taskId, threadId, turnId, status, summary)
112
+ M->>W: Store semantic result
113
+ Note right of W: Replace status, summary, turnId<br>Set updatedAt and updatedBy=mcp
114
+ M-->>E: Updated task snapshot
115
+ W-->>V: Filesystem watcher refresh
116
+ ```
117
+
118
+ ## Workflow 4: Resume after `needs_input`
119
+
120
+ `needs_input` is a semantic pause, not a native approval prompt. After the user
121
+ responds or resumes the task, the executor reads the exact task again. The new
122
+ turn ID, rather than the initial one, accompanies the updated result.
123
+
124
+ ```mermaid
125
+ sequenceDiagram
126
+ autonumber
127
+ actor U as User
128
+ participant E as Executor child
129
+ participant C as Codex native tasks
130
+ participant M as TaskChef MCP
131
+ participant W as tasks.jsonl
132
+ participant V as Dashboard
133
+
134
+ E-->>U: Request decision or information
135
+ U->>E: Follow up or resume
136
+ E->>C: Exact native read after follow-up
137
+ C-->>E: Newer current turnId UUIDv7
138
+ E->>M: report_result(taskId, threadId, newer turnId, completed, summary)
139
+ M->>W: Replace latest semantic result
140
+ Note right of W: status=completed, new summary, newer turnId<br>updatedAt refreshed, updatedBy=mcp
141
+ M-->>E: Completed task snapshot
142
+ W-->>V: Filesystem watcher refresh
143
+ ```
144
+
145
+ ## Workflow 5: Creation and linking failures
146
+
147
+ Because `record_task` happens first, native creation failure remains visible:
148
+ the dispatcher reports one terminal failure while both identity fields stay
149
+ null. The dispatcher makes exactly one native creation call and never retries
150
+ it. TaskChef never guesses an executor identity from recent tasks, titles,
151
+ transcripts, or dashboard activity.
152
+
153
+ For linking, outcome depends on where interruption occurs. Before commit, an
154
+ eligible record remains link-pending. If the atomic write commits but its reply
155
+ is lost, the record is already linked and an identical retry returns that
156
+ snapshot. Inspect rejections before retrying; identity conflicts and terminal
157
+ records must not be blindly retried.
158
+
159
+ ```mermaid
160
+ sequenceDiagram
161
+ autonumber
162
+ actor U as User
163
+ participant D as Dispatcher
164
+ participant C as Codex native tasks
165
+ participant E as Executor child
166
+ participant M as TaskChef MCP
167
+ participant W as tasks.jsonl
168
+
169
+ alt Native creation fails after record_task
170
+ D->>C: Create task with marked instruction
171
+ C--xD: Creation error
172
+ D->>M: report_result(taskId, null, null, failed, bounded summary)
173
+ M->>W: Store terminal creation failure
174
+ Note right of W: Keep threadId=null and turnId=null<br>Set status=failed, summary, updatedAt, updatedBy=mcp
175
+ M-->>D: Failed task snapshot
176
+ D-->>U: Creation failure with preserved TaskChef taskId
177
+ else Initial link stops before commit
178
+ E--xM: link_task(taskId, child threadId)
179
+ Note right of W: Remains threadId=null, status=working<br>Eligible link-pending record may retry later
180
+ else Link commits but response is lost
181
+ E->>M: link_task(taskId, child threadId)
182
+ M->>W: Commit child threadId
183
+ M--xE: Response lost
184
+ E->>M: Identical link_task retry
185
+ M-->>E: Return existing linked snapshot
186
+ end
187
+ ```
188
+
189
+ ## MCP calls and field transitions
190
+
191
+ | Step | Caller | Operation | Key input | Task record effect |
192
+ | --- | --- | --- | --- | --- |
193
+ | 1 | Dispatcher | `prepare_dispatch` | No task identity supplied | Returns `taskId`, exact `marker`, `preparedAt`, and configured `projects`; does not write `tasks.jsonl`. |
194
+ | 2 | Dispatcher | `record_task` | `id`, `project`, `title`, marked `instruction`, `threadId: null` | Appends schema 4 with `createdAt`; sets `status: working`, `summary: null`, `turnId: null`, `updatedAt: createdAt`, `updatedBy: dispatcher`. |
195
+ | 3 | Dispatcher | Native Codex task creation—not MCP | Target project plus marked instruction | Does not change the TaskChef record. A returned durable or provisional ID is not identity authority. |
196
+ | 4 | Executor | `link_task` | Marked `taskId` plus its own `CODEX_THREAD_ID` | Atomically changes `threadId` from `null` to the canonical child UUIDv7; refreshes `updatedAt` and sets `updatedBy: mcp`. |
197
+ | 5 | Executor | `report_result` | Exact `taskId`, self-linked `threadId`, current `turnId`, semantic `status`, concise `summary` | Replaces the latest `status`, `summary`, and `turnId`; refreshes `updatedAt` and sets `updatedBy: mcp`. Changed follow-up results require a newer UUIDv7 `turnId`. |
198
+ | Failure | Dispatcher | `report_result` after native creation error | `taskId`, `threadId: null`, `turnId: null`, `status: failed`, bounded `summary` | Preserves the pre-created record and null identity while storing a terminal creation failure. |
199
+
200
+ ## Design boundaries
201
+
202
+ There is no task listing, candidate read, marker search, wait, polling loop,
203
+ native creation retry, transcript read, or hook in the dispatch path. The
204
+ filesystem watcher notices atomic TaskChef writes and refreshes only the
205
+ dashboard; reports read current state on demand.
206
+
207
+ Custom MCP does not authenticate the calling Codex task. The executor thread ID
208
+ is therefore a cooperative assertion inside TaskChef's local single-user trust
209
+ boundary. The design prevents accidental parent/child confusion but does not
210
+ claim resistance to a deliberately forged local MCP call.
211
+
212
+ Historical `updatedBy: hook` values remain readable, but new installations
213
+ contain no hook and new writes use `dispatcher` or `mcp`.
64
214
 
65
215
  ## Legacy recovery
66
216
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskchef",
3
- "version": "6.0.0",
3
+ "version": "6.1.0",
4
4
  "description": "A non-blocking interactive dispatcher for visible Codex tasks.",
5
5
  "license": "MIT",
6
6
  "author": "Favo Yang",
@@ -39,6 +39,7 @@
39
39
  },
40
40
  "devDependencies": {
41
41
  "conventional-changelog-conventionalcommits": "^10.3.0",
42
+ "mermaid": "^11.17.0",
42
43
  "yaml": "^2.9.0"
43
44
  },
44
45
  "scripts": {