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.
- package/.codex-plugin/plugin.json +5 -2
- package/assets/taskchef-dark.svg +9 -0
- package/assets/taskchef.svg +9 -0
- package/docs/delegation-design.md +205 -55
- package/package.json +2 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "taskchef",
|
|
3
|
-
"version": "6.
|
|
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
|
-
##
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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.
|
|
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": {
|