taskchef 5.12.0 → 6.0.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 +1 -1
- package/BACKLOG.md +6 -15
- package/README.md +30 -40
- package/SPEC.md +92 -369
- package/assets/e2e-benchmark-example.json +37 -33
- package/docs/delegation-design.md +75 -176
- package/index.js +3 -11
- package/package.json +1 -2
- package/scripts/e2e-benchmark.js +101 -412
- package/skills/taskchef-bootstrap/SKILL.md +2 -3
- package/skills/taskchef-delegate/SKILL.md +60 -138
- package/skills/taskchef-report/SKILL.md +12 -8
- package/src/cli.js +2 -1
- package/src/delegation.js +24 -201
- package/src/mcp.js +10 -10
- package/src/workspace.js +128 -61
- package/hooks/hooks.json +0 -18
- package/hooks/taskchef-initial-prompt.js +0 -17
- package/src/hook.js +0 -96
|
@@ -1,178 +1,77 @@
|
|
|
1
1
|
# Delegation and result design
|
|
2
2
|
|
|
3
|
-
TaskChef
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
##
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
There is no result-event file: each callback replaces the latest snapshot on the
|
|
79
|
-
same JSONL line.
|
|
80
|
-
Result instructions forbid secrets, transcripts, and raw command output; the
|
|
81
|
-
server also caps the stored summary at 2,000 characters.
|
|
82
|
-
|
|
83
|
-
## Locking and conflicts
|
|
84
|
-
|
|
85
|
-
All configuration, identity, and result writes use the existing cross-process
|
|
86
|
-
workspace lock. A writer acquires the lock, rereads and validates the complete
|
|
87
|
-
JSONL file, changes one exact task, and publishes a complete replacement with
|
|
88
|
-
an atomic rename. Concurrent writers therefore cannot create partial JSON,
|
|
89
|
-
duplicate entries, or lose changes to different tasks. Sequential callbacks for
|
|
90
|
-
the same task use last accepted write wins; normal executor turns are already
|
|
91
|
-
sequential.
|
|
92
|
-
|
|
93
|
-
SQLite is postponed because this file-level write volume is tiny and the
|
|
94
|
-
existing lock provides the property users need. SQLite becomes worthwhile only
|
|
95
|
-
if TaskChef later adds high-frequency event history or many continuous writers.
|
|
96
|
-
|
|
97
|
-
## Result trust
|
|
98
|
-
|
|
99
|
-
The MCP server does not receive an independently authenticated caller task ID
|
|
100
|
-
from the model transport. It validates that the supplied task exists and that
|
|
101
|
-
the supplied durable thread ID exactly matches the recorded thread. The turn ID
|
|
102
|
-
is stored as evidence but remains model-supplied. A trusted plugin install,
|
|
103
|
-
local-only MCP server, bounded summary, and exact task/thread match are the
|
|
104
|
-
current trust boundary.
|
|
105
|
-
|
|
106
|
-
This is sufficient for a lightweight personal dispatcher, but not a
|
|
107
|
-
multi-tenant authorization boundary. Transport-authenticated caller identity is
|
|
108
|
-
postponed until Codex exposes it.
|
|
109
|
-
|
|
110
|
-
## Fresh reporting without reading every task
|
|
111
|
-
|
|
112
|
-
A stored result is cached evidence, not permanent truth. Overview reports:
|
|
113
|
-
|
|
114
|
-
1. Load `tasks.jsonl` once.
|
|
115
|
-
2. Always consider working, needs-input, unresolved, and legacy entries.
|
|
116
|
-
3. Consider completed or failed entries updated in the last seven days.
|
|
117
|
-
4. Take one recent-thread metadata snapshot for all selected tasks. Include an
|
|
118
|
-
older terminal task in an overview when the snapshot shows it is active or
|
|
119
|
-
awaiting native approval.
|
|
120
|
-
5. A null-thread/null-turn `failed` snapshot written by MCP is a fresh creation
|
|
121
|
-
failure and needs no live task lookup because no executor exists.
|
|
122
|
-
6. Treat only `updatedBy: mcp` as a semantic cache. Dispatcher- and hook-written
|
|
123
|
-
`working` snapshots require a targeted live read; an inactive task with no
|
|
124
|
-
callback has an unknown outcome.
|
|
125
|
-
7. In a broad overview, use an MCP result directly when identity is certain and
|
|
126
|
-
the task is inactive; do not fan out detailed reads over idle terminal tasks
|
|
127
|
-
solely because their timestamps are newer.
|
|
128
|
-
8. Active or awaiting-approval metadata overrides the cached result directly.
|
|
129
|
-
For a focused task, title, or project report, read each selected inactive
|
|
130
|
-
task at most once when matched metadata is newer than the callback by any
|
|
131
|
-
amount. Batch targeted immediate reads, at most eight tasks per call, also
|
|
132
|
-
for a missing callback, uncertain or contradictory state, or an explicitly
|
|
133
|
-
fully-live request.
|
|
134
|
-
9. If an anomaly triggers a detailed read, compare its latest structured turn
|
|
135
|
-
ID and native turn state with stored `turnId`. A newer turn without a
|
|
136
|
-
callback makes the cache stale. An interrupted or cancelled callback turn
|
|
137
|
-
cannot prove completion.
|
|
138
|
-
|
|
139
|
-
An explicit task, title, or project report bypasses the seven-day overview
|
|
140
|
-
filter. Old terminal tasks skipped from an overview are counted so the user
|
|
141
|
-
knows history was intentionally omitted.
|
|
142
|
-
|
|
143
|
-
The cheap operation is the single list/metadata snapshot, not one read per
|
|
144
|
-
historical task. It is sufficient to expose active and native-approval state for
|
|
145
|
-
many recent tasks at once. It does not prove completion; semantic outcomes come
|
|
146
|
-
from MCP callbacks. Detailed thread reads are the exceptional fallback.
|
|
147
|
-
Timestamps are a pragmatic anomaly filter; turn IDs and native turn state
|
|
148
|
-
provide the stronger check whenever a targeted response is necessary.
|
|
149
|
-
|
|
150
|
-
## Permission and follow-up example
|
|
151
|
-
|
|
152
|
-
1. Delegation records one `working` entry with null identity.
|
|
153
|
-
2. The dispatcher verifies and resolves the child thread; the initial hook then
|
|
154
|
-
records its initial turn without trusting the inherited session ID.
|
|
155
|
-
3. The executor reaches a real product decision and calls `report_result` with
|
|
156
|
-
`needs_input` plus “Approve deployment to production.”
|
|
157
|
-
4. The user opens that executor and approves. The same hook reads the matching
|
|
158
|
-
task and injects the new turn ID without changing the stored snapshot. Until
|
|
159
|
-
the final callback, a report sees newer/active live metadata and labels the
|
|
160
|
-
cached needs-input result stale.
|
|
161
|
-
5. The executor finishes and calls `report_result` with `completed`, the new
|
|
162
|
-
turn ID, and a concise outcome. The same JSONL line now contains the completed
|
|
163
|
-
snapshot.
|
|
164
|
-
|
|
165
|
-
If step 3 were merely Codex asking for filesystem or command approval, no MCP
|
|
166
|
-
callback would be written. Reporting would show “awaiting native approval” from
|
|
167
|
-
live task state.
|
|
168
|
-
|
|
169
|
-
## Explicitly postponed
|
|
170
|
-
|
|
171
|
-
- append-only result or transition events
|
|
172
|
-
- lifecycle event types beyond `UserPromptSubmit`
|
|
173
|
-
- fork tracking or result merging
|
|
174
|
-
- SQLite
|
|
175
|
-
- indefinite polling, reconciliation schedules, daemons, and dispatcher wakeups
|
|
176
|
-
- durable report watermarks
|
|
177
|
-
- transcript or assistant-prose classification
|
|
178
|
-
- transport-authenticated caller thread/turn identity
|
|
3
|
+
TaskChef stores a durable local task history while Codex owns execution. The
|
|
4
|
+
dispatcher records intent, the executor registers its own identity, and only
|
|
5
|
+
the executor reports semantic outcomes.
|
|
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
|
|
26
|
+
|
|
27
|
+
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`.
|
|
64
|
+
|
|
65
|
+
## Legacy recovery
|
|
66
|
+
|
|
67
|
+
`taskchef task resolve` is retained only for unresolved schema 1-3 records.
|
|
68
|
+
Operators must establish one exact marker match and one unique durable child
|
|
69
|
+
ID. Schema 4 self-linking records reject manual resolution. History is read
|
|
70
|
+
compatibly and is not eagerly rewritten.
|
|
71
|
+
|
|
72
|
+
## Dashboard and reports
|
|
73
|
+
|
|
74
|
+
The dashboard deep link uses only the stored self-linked child ID. File watcher
|
|
75
|
+
events surface linking and results without user interaction. Reporting may
|
|
76
|
+
compare current native metadata with cached semantic results, but it never
|
|
77
|
+
writes inferred lifecycle state.
|
package/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export {
|
|
|
9
9
|
filterTasks,
|
|
10
10
|
importProjects,
|
|
11
11
|
initializeWorkspace,
|
|
12
|
+
linkTask,
|
|
12
13
|
listProjects,
|
|
13
14
|
prepareDispatch,
|
|
14
15
|
readConfig,
|
|
@@ -17,7 +18,6 @@ export {
|
|
|
17
18
|
recordTask,
|
|
18
19
|
reportTaskResult,
|
|
19
20
|
resolveTask,
|
|
20
|
-
startTaskFromHook,
|
|
21
21
|
requireSafeId,
|
|
22
22
|
removeProject,
|
|
23
23
|
validateConfig,
|
|
@@ -31,20 +31,14 @@ export {
|
|
|
31
31
|
|
|
32
32
|
export {
|
|
33
33
|
EXECUTOR_OWNERSHIP_PARAGRAPH,
|
|
34
|
+
EXECUTOR_LINK_PARAGRAPH,
|
|
34
35
|
EXECUTOR_RESULT_PARAGRAPH,
|
|
35
|
-
THREAD_RESOLUTION_CHECKPOINTS_MS,
|
|
36
|
-
THREAD_RESOLUTION_CLOCK_SKEW_MS,
|
|
37
|
-
THREAD_RESOLUTION_RECENT_LIMIT,
|
|
38
|
-
THREAD_RESOLUTION_TIMEOUT_MS,
|
|
39
36
|
createAndRecordDelegation,
|
|
40
|
-
filterThreadCandidates,
|
|
41
|
-
hasExactTaskChefMarker,
|
|
42
37
|
isProvisionalThreadId,
|
|
43
|
-
|
|
38
|
+
normalizeCodexThreadId,
|
|
44
39
|
normalizeDurableThreadId,
|
|
45
40
|
parseTaskChefMarker,
|
|
46
41
|
prepareDelegation,
|
|
47
|
-
structuredDelegatedInputs,
|
|
48
42
|
taskChefMarker,
|
|
49
43
|
} from "./src/delegation.js";
|
|
50
44
|
|
|
@@ -69,5 +63,3 @@ export {
|
|
|
69
63
|
} from "./src/dashboard.js";
|
|
70
64
|
|
|
71
65
|
export { createTaskChefMcpServer } from "./src/mcp.js";
|
|
72
|
-
|
|
73
|
-
export { INITIAL_LINK_CHECKPOINTS_MS, handleInitialPromptHook } from "./src/hook.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "taskchef",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "A non-blocking interactive dispatcher for visible Codex tasks.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Favo Yang",
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
"BACKLOG.md",
|
|
25
25
|
"bin",
|
|
26
26
|
"docs/delegation-design.md",
|
|
27
|
-
"hooks",
|
|
28
27
|
"index.js",
|
|
29
28
|
"mcp",
|
|
30
29
|
"SPEC.md",
|