taskchef 7.27.1 → 7.28.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/package.json +2 -1
- package/scripts/roles/resolve_roles.py +172 -0
- package/skills/taskchef-bootstrap/SKILL.md +26 -109
- package/skills/taskchef-bootstrap/references/project-index.md +119 -0
- package/skills/taskchef-copilot/SKILL.md +1 -1
- package/skills/taskchef-delegate/SKILL.md +8 -1
- package/skills/taskchef-delegate/references/model-roles.md +49 -0
- package/src/dashboard/dist/app.js +39 -39
- package/src/dashboard/dist/app.js.map +1 -1
- package/src/dashboard/react/App.test.tsx +1 -0
- package/src/dashboard/react/App.tsx +11 -1
- package/src/dashboard/react/components/ModelSettings.test.tsx +53 -0
- package/src/dashboard/react/components/ModelSettings.tsx +61 -0
- package/src/dashboard.js +11 -0
- package/src/mcp.js +2 -0
- package/src/model-roles.js +44 -0
- package/src/workspace.js +5 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "taskchef",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.28.0",
|
|
4
4
|
"description": "A non-blocking interactive dispatcher for visible Codex tasks.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Favo Yang",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"docs/images/reported-work-duration-mobile.jpg",
|
|
38
38
|
"index.js",
|
|
39
39
|
"mcp",
|
|
40
|
+
"scripts/roles",
|
|
40
41
|
"scripts/benchmark-dispatch-prepare.js",
|
|
41
42
|
"scripts/e2e-benchmark.js",
|
|
42
43
|
"src",
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Read native Codex agent preferences without applying their instruction layers.
|
|
3
|
+
|
|
4
|
+
Requires Python 3.11+. Standalone, standard library only. TaskChef packages an
|
|
5
|
+
identical copy; neither installation imports the other at runtime.
|
|
6
|
+
"""
|
|
7
|
+
import argparse
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
import sys
|
|
12
|
+
import tomllib
|
|
13
|
+
|
|
14
|
+
ROLES = ('planner', 'implementer', 'reviewer')
|
|
15
|
+
EFFORTS = ('none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'ultra')
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def read_layer(directory):
|
|
19
|
+
found = {}
|
|
20
|
+
problems = []
|
|
21
|
+
try:
|
|
22
|
+
with os.scandir(directory) as entries:
|
|
23
|
+
files = sorted(Path(entry.path) for entry in entries if entry.name.endswith('.toml'))
|
|
24
|
+
for file in files:
|
|
25
|
+
try:
|
|
26
|
+
if file.stat().st_size > 65536:
|
|
27
|
+
raise ValueError('profile exceeds 64 KiB')
|
|
28
|
+
with file.open('rb') as stream:
|
|
29
|
+
data = tomllib.load(stream)
|
|
30
|
+
name = data.get('name')
|
|
31
|
+
if name not in ROLES:
|
|
32
|
+
if file.stem in ROLES:
|
|
33
|
+
raise ValueError('name must match the role filename')
|
|
34
|
+
continue
|
|
35
|
+
errors = []
|
|
36
|
+
for field in ('description', 'developer_instructions'):
|
|
37
|
+
if not isinstance(data.get(field), str) or not data[field].strip():
|
|
38
|
+
errors.append(f'{field} must be a nonempty string')
|
|
39
|
+
model = data.get('model')
|
|
40
|
+
effort = data.get('model_reasoning_effort')
|
|
41
|
+
entry = {'source': str(file), 'model': model, 'effort': effort, 'problems': errors}
|
|
42
|
+
if name in found:
|
|
43
|
+
entry['problems'].append('duplicate role name in the same directory')
|
|
44
|
+
found[name] = entry
|
|
45
|
+
except (OSError, ValueError) as error:
|
|
46
|
+
# Do not expose TOML lines, which can contain unrelated private data.
|
|
47
|
+
message = f'{file}: unreadable or malformed agent TOML ({type(error).__name__})'
|
|
48
|
+
problems.append(message)
|
|
49
|
+
if file.stem in ROLES:
|
|
50
|
+
found[file.stem] = {'source': str(file), 'model': None, 'effort': None, 'problems': [message]}
|
|
51
|
+
except FileNotFoundError:
|
|
52
|
+
return found, problems
|
|
53
|
+
except OSError:
|
|
54
|
+
message = f'{directory}: cannot read agent directory'
|
|
55
|
+
problems.append(message)
|
|
56
|
+
found = {role: {'source': str(directory), 'model': None, 'effort': None, 'problems': [message]} for role in ROLES}
|
|
57
|
+
return found, problems
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def resolve(project=None, codex_home=None, explicit_model=None, explicit_effort=None):
|
|
61
|
+
home = Path(codex_home or os.environ.get('CODEX_HOME') or Path.home() / '.codex').expanduser().resolve()
|
|
62
|
+
personal, problems = read_layer(home / 'agents')
|
|
63
|
+
local, local_problems = read_layer(Path(project).resolve() / '.codex' / 'agents') if project else ({}, [])
|
|
64
|
+
problems += local_problems
|
|
65
|
+
catalog = None
|
|
66
|
+
catalog_source = str(home / 'models_cache.json')
|
|
67
|
+
try:
|
|
68
|
+
cache = json.loads(Path(catalog_source).read_text())
|
|
69
|
+
if not isinstance(cache, dict) or not isinstance(cache.get('models'), list):
|
|
70
|
+
raise ValueError('invalid catalog')
|
|
71
|
+
for model in cache['models']:
|
|
72
|
+
if not isinstance(model, dict) or not isinstance(model.get('slug'), str):
|
|
73
|
+
raise ValueError('invalid model entry')
|
|
74
|
+
levels = model.get('supported_reasoning_levels')
|
|
75
|
+
if not isinstance(levels, list) or any(not isinstance(level, dict) or not isinstance(level.get('effort'), str) for level in levels):
|
|
76
|
+
raise ValueError('invalid effort catalog')
|
|
77
|
+
catalog = {model['slug']: model for model in cache['models']}
|
|
78
|
+
except FileNotFoundError:
|
|
79
|
+
pass
|
|
80
|
+
except (OSError, ValueError, KeyError, TypeError):
|
|
81
|
+
problems.append('Local Codex model catalog is unreadable or malformed; validate availability with the current native tool.')
|
|
82
|
+
results = []
|
|
83
|
+
for role in ROLES:
|
|
84
|
+
entry = local.get(role, personal.get(role))
|
|
85
|
+
source = entry['source'] if entry else None
|
|
86
|
+
model = entry['model'] if entry else None
|
|
87
|
+
effort = entry['effort'] if entry else None
|
|
88
|
+
errors = list(entry['problems']) if entry else []
|
|
89
|
+
if explicit_model is not None:
|
|
90
|
+
model, effort = explicit_model, explicit_effort
|
|
91
|
+
effective_source = 'explicit user model choice'
|
|
92
|
+
errors = []
|
|
93
|
+
else:
|
|
94
|
+
effective_source = source
|
|
95
|
+
if explicit_effort is not None:
|
|
96
|
+
effort = explicit_effort
|
|
97
|
+
if model is not None and (not isinstance(model, str) or not model.strip() or len(model) > 256):
|
|
98
|
+
errors.append('model must be a nonempty string of at most 256 characters')
|
|
99
|
+
if effort is not None and effort not in EFFORTS:
|
|
100
|
+
errors.append('reasoning effort is unsupported')
|
|
101
|
+
status = 'invalid' if errors else 'configured' if (model is not None or effort is not None) else 'missing'
|
|
102
|
+
availability = 'not checked; native tool must validate before dispatch'
|
|
103
|
+
if model and not errors and catalog is not None:
|
|
104
|
+
if model not in catalog:
|
|
105
|
+
errors.append('model absent from local Codex catalog; confirm against the current native tool before dispatch')
|
|
106
|
+
status = 'unavailable'
|
|
107
|
+
else:
|
|
108
|
+
supported = [v.get('effort') for v in catalog[model].get('supported_reasoning_levels', []) if isinstance(v, dict)]
|
|
109
|
+
if effort and effort not in supported:
|
|
110
|
+
errors.append('effort absent from local model catalog; confirm against the current native tool')
|
|
111
|
+
status = 'unavailable'
|
|
112
|
+
availability = 'present in cached catalog; current native tool is authoritative'
|
|
113
|
+
overrides = {}
|
|
114
|
+
if status == 'configured':
|
|
115
|
+
if model is not None:
|
|
116
|
+
overrides['model'] = model
|
|
117
|
+
if effort is not None:
|
|
118
|
+
overrides['thinking'] = effort
|
|
119
|
+
results.append({'role': role, 'source': source, 'effectiveSource': effective_source,
|
|
120
|
+
'model': model, 'effort': effort, 'status': status,
|
|
121
|
+
'availability': availability, 'problems': errors,
|
|
122
|
+
'taskOverrides': overrides,
|
|
123
|
+
'subagentOverrides': {('reasoning_effort' if k == 'thinking' else k): v for k, v in overrides.items()},
|
|
124
|
+
'fallback': 'inherit parent settings' if role == 'reviewer' else 'native new-task default (not guaranteed dispatcher inheritance)'})
|
|
125
|
+
return {'roles': results, 'problems': problems, 'catalogSource': catalog_source if catalog is not None else None,
|
|
126
|
+
'precedence': 'explicit user model (and its explicit effort) > project role > personal role > native defaults; explicit effort alone overrides role effort',
|
|
127
|
+
'scope': 'Model and effort only; agent instructions, tools, permissions, and other TOML keys are not applied by this adapter.'}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def setup(role, model, effort, codex_home=None):
|
|
131
|
+
home = Path(codex_home or os.environ.get('CODEX_HOME') or Path.home() / '.codex').expanduser().resolve()
|
|
132
|
+
existing, problems = read_layer(home / 'agents')
|
|
133
|
+
if role in existing or problems:
|
|
134
|
+
return {'created': False, 'role': role, 'problems': problems or ['existing role preserved'], 'source': existing.get(role, {}).get('source')}
|
|
135
|
+
if not model.strip() or len(model) > 256 or effort not in EFFORTS:
|
|
136
|
+
raise ValueError('invalid model or effort')
|
|
137
|
+
directory = home / 'agents'
|
|
138
|
+
directory.mkdir(parents=True, exist_ok=True)
|
|
139
|
+
target = directory / f'{role}.toml'
|
|
140
|
+
data = {'name': role, 'description': f'{role.capitalize()} model preferences',
|
|
141
|
+
'developer_instructions': f'Perform the assigned {role} work within the user\'s requested scope.',
|
|
142
|
+
'model': model, 'model_reasoning_effort': effort}
|
|
143
|
+
try:
|
|
144
|
+
with target.open('x') as stream:
|
|
145
|
+
stream.write(''.join(f'{key} = {json.dumps(value)}\n' for key, value in data.items()))
|
|
146
|
+
except FileExistsError:
|
|
147
|
+
return {'created': False, 'role': role, 'source': str(target), 'problems': ['existing file preserved']}
|
|
148
|
+
return {'created': True, 'role': role, 'source': str(target), 'model': model, 'effort': effort}
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def main():
|
|
152
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
153
|
+
parser.add_argument('--project')
|
|
154
|
+
parser.add_argument('--codex-home')
|
|
155
|
+
parser.add_argument('--role', choices=ROLES)
|
|
156
|
+
parser.add_argument('--model')
|
|
157
|
+
parser.add_argument('--effort')
|
|
158
|
+
parser.add_argument('--setup', action='store_true')
|
|
159
|
+
args = parser.parse_args()
|
|
160
|
+
if args.setup:
|
|
161
|
+
if not (args.role and args.model and args.effort):
|
|
162
|
+
parser.error('--setup requires --role, --model, and --effort')
|
|
163
|
+
result = setup(args.role, args.model, args.effort, args.codex_home)
|
|
164
|
+
else:
|
|
165
|
+
result = resolve(args.project, args.codex_home, args.model, args.effort)
|
|
166
|
+
if args.role:
|
|
167
|
+
result['roles'] = [r for r in result['roles'] if r['role'] == args.role]
|
|
168
|
+
print(json.dumps(result, indent=2))
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
if __name__ == '__main__':
|
|
172
|
+
main()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: taskchef-bootstrap
|
|
3
|
-
description: "Initialize
|
|
3
|
+
description: "Initialize or repair the TaskChef dispatcher workspace and manage its local Codex project index. Use for setup, doctor, import, or reindex requests; not dispatch or executor reporting."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# TaskChef Bootstrap
|
|
@@ -50,118 +50,35 @@ all deterministic workspace operations.
|
|
|
50
50
|
End without dispatching unless the user
|
|
51
51
|
separately requested work.
|
|
52
52
|
|
|
53
|
-
##
|
|
53
|
+
## Project index operations
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
For adding, importing, removing, listing, or reindexing projects, read
|
|
56
|
+
[project index](references/project-index.md). Preserve exact canonical local
|
|
57
|
+
Codex project identity and existing curated entries; opening a folder is not
|
|
58
|
+
proof of registration. Completion requires verifying the intended index entry.
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
Remote connection projects are outside the v1 contract. Never index the
|
|
62
|
-
TaskChef dispatcher workspace or a directory containing it; the dispatcher is
|
|
63
|
-
the inbox, while indexed Codex projects own delegated work.
|
|
60
|
+
## Optional model roles
|
|
64
61
|
|
|
65
|
-
|
|
62
|
+
Offer planner, implementer, and reviewer profiles during setup. Model and effort
|
|
63
|
+
preferences belong in user configuration, never defaults hard-coded in skills.
|
|
64
|
+
If the user provides values, configure them without asking again. Otherwise
|
|
65
|
+
explain the optional profiles and retain native defaults until values are chosen.
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
are not matches.
|
|
71
|
-
2. Index the exact path with the existing `project add <canonical-path> --name
|
|
72
|
-
<curated-name> --description <curated-description> --json` CLI workflow.
|
|
73
|
-
Despite the command's historical `add` name, this writes one TaskChef index
|
|
74
|
-
entry for an existing Codex project. The CLI detects Git status, the exact
|
|
75
|
-
Git root, and a canonical GitHub `origin` when no repository option is
|
|
76
|
-
supplied. Repeated `--github-repo <canonical-url>` arguments replace that
|
|
77
|
-
detection and form the complete advertised repository list, so repeat the
|
|
78
|
-
origin explicitly when it should remain routable. Use `--no-github` when the
|
|
79
|
-
user intentionally wants an empty list.
|
|
80
|
-
3. Run `project list --json` and require one indexed entry with the exact
|
|
81
|
-
canonical path and intended routing metadata. Only then report that the
|
|
82
|
-
Codex project is ready for delegation through TaskChef.
|
|
67
|
+
Run `python3 <plugin-root>/scripts/roles/resolve_roles.py` to preview personal
|
|
68
|
+
roles. Python 3.11+ is required for this optional helper. Create each requested
|
|
69
|
+
missing profile with:
|
|
83
70
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
1. Create the folder only when the user explicitly asked to create it. Preserve
|
|
87
|
-
unrelated existing contents. Do not initialize Git unless requested or
|
|
88
|
-
clearly required by the user's broader task. Resolve the resulting existing
|
|
89
|
-
folder with `realpath`.
|
|
90
|
-
2. Register or open that exact canonical folder with the supported
|
|
91
|
-
`<validated-codex-cli> app <canonical-path>` mechanism. Reuse a validated CLI
|
|
92
|
-
path supplied by the current Codex Desktop environment when available. Use
|
|
93
|
-
the same resolver contract as `workspace init --register-codex` otherwise:
|
|
94
|
-
an explicit `--codex-cli` path takes precedence over `TASKCHEF_CODEX_CLI`;
|
|
95
|
-
each must resolve to an executable that passes `app --help`. Without an
|
|
96
|
-
override, inspect `codex` executables from `PATH`, prefer a validated
|
|
97
|
-
candidate whose path contains `Contents/Resources`, and otherwise validate
|
|
98
|
-
only the first executable `codex` in PATH order. Never assume an arbitrary
|
|
99
|
-
shell `codex`, invoke `codex add`, or hard-code an application bundle path.
|
|
100
|
-
3. Re-list native local Codex projects and require an exact canonical-path
|
|
101
|
-
match. Opening is a request, not proof that Codex saved the project. If the
|
|
102
|
-
exact match is absent, report that the folder was opened or registration was
|
|
103
|
-
requested but Codex registration remains unverified; do not index it in
|
|
104
|
-
TaskChef or call it delegation-ready.
|
|
105
|
-
4. After Codex verification, index the project as in the existing-project path.
|
|
106
|
-
Run `project list --json` and verify the exact TaskChef index entry. Report
|
|
107
|
-
delegation readiness only after both the native Codex match and TaskChef
|
|
108
|
-
indexing are verified.
|
|
109
|
-
|
|
110
|
-
For a managed `*-workspace` Codex project, advertise every relevant child or
|
|
111
|
-
subrepository with repeated `--github-repo <canonical-github-url>` arguments,
|
|
112
|
-
including the workspace repository itself when it can own issue or pull-request
|
|
113
|
-
links. These explicit values are the complete list; automatic origin detection
|
|
114
|
-
does not supplement them. This lets TaskChef route each canonical GitHub URL to
|
|
115
|
-
the correct workspace rather than guessing from the folder name.
|
|
116
|
-
|
|
117
|
-
### Reindex after Codex changes
|
|
118
|
-
|
|
119
|
-
When the user asks TaskChef to reindex or catch up after saving more projects in
|
|
120
|
-
Codex, list native local Codex projects once and run `project list --json` once
|
|
121
|
-
before mutation. Compare exact canonical paths, then index each requested
|
|
122
|
-
eligible Codex project that is missing from TaskChef by following the
|
|
123
|
-
appropriate path above, sharing the batch verification instead of relisting
|
|
124
|
-
after each write. After all additions, run `project list --json` once more and
|
|
125
|
-
verify every intended canonical path and its routing metadata before reporting
|
|
126
|
-
the index as current.
|
|
127
|
-
|
|
128
|
-
Do not call `project add` for a path already in the TaskChef index; it rejects
|
|
129
|
-
duplicate paths and must not be presented as a metadata refresh. Preserve
|
|
130
|
-
existing curated entries, and do not remove entries merely because they are
|
|
131
|
-
absent from the current Codex list. Refreshing or removing an existing entry
|
|
132
|
-
requires an explicit user request and the project-management workflows below.
|
|
133
|
-
|
|
134
|
-
## Manage the project index
|
|
135
|
-
|
|
136
|
-
1. Bulk import with `project import <file|-> --json`. Input is a JSON array of
|
|
137
|
-
objects containing `path` plus optional `name`, `description`, and
|
|
138
|
-
`githubRepos`, which is always a JSON array of GitHub repository URLs. Before
|
|
139
|
-
importing, list native local Codex projects once, canonicalize every input
|
|
140
|
-
path, and require an exact local-project match for every entry. Reject or
|
|
141
|
-
report every unmatched path instead of indexing it. Import merges by
|
|
142
|
-
canonical path, preserves an existing name or description when omitted, and
|
|
143
|
-
unions existing and imported repository lists without duplicates. Use
|
|
144
|
-
`--replace` only when the user explicitly requests replacement. Run
|
|
145
|
-
`project list --json` afterward and verify every imported entry.
|
|
146
|
-
2. Inspect indexed projects with `project list --json`. Remove by name with
|
|
147
|
-
`project remove`. Existing task entries keep their project snapshots.
|
|
148
|
-
|
|
149
|
-
Example managed-workspace import entry:
|
|
150
|
-
|
|
151
|
-
```json
|
|
152
|
-
{
|
|
153
|
-
"name": "skills-workspace",
|
|
154
|
-
"path": "/workspace/skills-workspace",
|
|
155
|
-
"githubRepos": [
|
|
156
|
-
"https://github.com/example/skill-one",
|
|
157
|
-
"https://github.com/example/skill-two"
|
|
158
|
-
],
|
|
159
|
-
"description": "Manages the listed child skill repositories."
|
|
160
|
-
}
|
|
71
|
+
```sh
|
|
72
|
+
python3 <plugin-root>/scripts/roles/resolve_roles.py --setup --role <role> --model <requested-model> --effort <requested-effort>
|
|
161
73
|
```
|
|
162
74
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
75
|
+
This authorized role setup may create `$CODEX_HOME/agents/<role>.toml` (default
|
|
76
|
+
`~/.codex/agents/`) outside the dispatcher workspace. Existing definitions,
|
|
77
|
+
including custom filenames, are preserved. Report conflicts and diagnostics;
|
|
78
|
+
never overwrite a custom role. Re-run the preview and check model/effort against
|
|
79
|
+
the available native interface. Missing roles are optional: TaskChef omits
|
|
80
|
+
new-task overrides; reviewers inherit parent settings. Native new-task defaults
|
|
81
|
+
are not guaranteed dispatcher inheritance. Read the delegate's
|
|
82
|
+
[role resolution](../taskchef-delegate/references/model-roles.md) for precedence
|
|
83
|
+
and adapter limits. Open the dashboard's `/#settings` preview to show the
|
|
84
|
+
configured sources, requested effective settings, fallback, and problems.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Project index operations
|
|
2
|
+
|
|
3
|
+
Resolve the plugin root and use its CLI as described in SKILL.md.
|
|
4
|
+
|
|
5
|
+
## Index Codex projects
|
|
6
|
+
|
|
7
|
+
TaskChef's project index is the local list of Codex projects available for
|
|
8
|
+
delegation. It stores canonical paths and routing metadata such as curated
|
|
9
|
+
names, descriptions, Git status, and GitHub repositories. It does not index
|
|
10
|
+
repository contents or create a second kind of project.
|
|
11
|
+
|
|
12
|
+
Index only Codex projects local to the TaskChef workspace's execution host.
|
|
13
|
+
Remote connection projects are outside the v1 contract. Never index the
|
|
14
|
+
TaskChef dispatcher workspace or a directory containing it; the dispatcher is
|
|
15
|
+
the inbox, while indexed Codex projects own delegated work.
|
|
16
|
+
|
|
17
|
+
### Existing Codex project
|
|
18
|
+
|
|
19
|
+
1. List native local Codex projects once. Resolve the requested existing folder
|
|
20
|
+
with `realpath` and require an exact canonical-path match in that list. A
|
|
21
|
+
similar name, a parent or child directory, and a remote connection project
|
|
22
|
+
are not matches.
|
|
23
|
+
2. Index the exact path with the existing `project add <canonical-path> --name
|
|
24
|
+
<curated-name> --description <curated-description> --json` CLI workflow.
|
|
25
|
+
Despite the command's historical `add` name, this writes one TaskChef index
|
|
26
|
+
entry for an existing Codex project. The CLI detects Git status, the exact
|
|
27
|
+
Git root, and a canonical GitHub `origin` when no repository option is
|
|
28
|
+
supplied. Repeated `--github-repo <canonical-url>` arguments replace that
|
|
29
|
+
detection and form the complete advertised repository list, so repeat the
|
|
30
|
+
origin explicitly when it should remain routable. Use `--no-github` when the
|
|
31
|
+
user intentionally wants an empty list.
|
|
32
|
+
3. Run `project list --json` and require one indexed entry with the exact
|
|
33
|
+
canonical path and intended routing metadata. Only then report that the
|
|
34
|
+
Codex project is ready for delegation through TaskChef.
|
|
35
|
+
|
|
36
|
+
### New or not-yet-saved Codex folder
|
|
37
|
+
|
|
38
|
+
1. Create the folder only when the user explicitly asked to create it. Preserve
|
|
39
|
+
unrelated existing contents. Do not initialize Git unless requested or
|
|
40
|
+
clearly required by the user's broader task. Resolve the resulting existing
|
|
41
|
+
folder with `realpath`.
|
|
42
|
+
2. Register or open that exact canonical folder with the supported
|
|
43
|
+
`<validated-codex-cli> app <canonical-path>` mechanism. Reuse a validated CLI
|
|
44
|
+
path supplied by the current Codex Desktop environment when available. Use
|
|
45
|
+
the same resolver contract as `workspace init --register-codex` otherwise:
|
|
46
|
+
an explicit `--codex-cli` path takes precedence over `TASKCHEF_CODEX_CLI`;
|
|
47
|
+
each must resolve to an executable that passes `app --help`. Without an
|
|
48
|
+
override, inspect `codex` executables from `PATH`, prefer a validated
|
|
49
|
+
candidate whose path contains `Contents/Resources`, and otherwise validate
|
|
50
|
+
only the first executable `codex` in PATH order. Never assume an arbitrary
|
|
51
|
+
shell `codex`, invoke `codex add`, or hard-code an application bundle path.
|
|
52
|
+
3. Re-list native local Codex projects and require an exact canonical-path
|
|
53
|
+
match. Opening is a request, not proof that Codex saved the project. If the
|
|
54
|
+
exact match is absent, report that the folder was opened or registration was
|
|
55
|
+
requested but Codex registration remains unverified; do not index it in
|
|
56
|
+
TaskChef or call it delegation-ready.
|
|
57
|
+
4. After Codex verification, index the project as in the existing-project path.
|
|
58
|
+
Run `project list --json` and verify the exact TaskChef index entry. Report
|
|
59
|
+
delegation readiness only after both the native Codex match and TaskChef
|
|
60
|
+
indexing are verified.
|
|
61
|
+
|
|
62
|
+
For a managed `*-workspace` Codex project, advertise every relevant child or
|
|
63
|
+
subrepository with repeated `--github-repo <canonical-github-url>` arguments,
|
|
64
|
+
including the workspace repository itself when it can own issue or pull-request
|
|
65
|
+
links. These explicit values are the complete list; automatic origin detection
|
|
66
|
+
does not supplement them. This lets TaskChef route each canonical GitHub URL to
|
|
67
|
+
the correct workspace rather than guessing from the folder name.
|
|
68
|
+
|
|
69
|
+
### Reindex after Codex changes
|
|
70
|
+
|
|
71
|
+
When the user asks TaskChef to reindex or catch up after saving more projects in
|
|
72
|
+
Codex, list native local Codex projects once and run `project list --json` once
|
|
73
|
+
before mutation. Compare exact canonical paths, then index each requested
|
|
74
|
+
eligible Codex project that is missing from TaskChef by following the
|
|
75
|
+
appropriate path above, sharing the batch verification instead of relisting
|
|
76
|
+
after each write. After all additions, run `project list --json` once more and
|
|
77
|
+
verify every intended canonical path and its routing metadata before reporting
|
|
78
|
+
the index as current.
|
|
79
|
+
|
|
80
|
+
Do not call `project add` for a path already in the TaskChef index; it rejects
|
|
81
|
+
duplicate paths and must not be presented as a metadata refresh. Preserve
|
|
82
|
+
existing curated entries, and do not remove entries merely because they are
|
|
83
|
+
absent from the current Codex list. Refreshing or removing an existing entry
|
|
84
|
+
requires an explicit user request and the project-management workflows below.
|
|
85
|
+
|
|
86
|
+
## Manage the project index
|
|
87
|
+
|
|
88
|
+
1. Bulk import with `project import <file|-> --json`. Input is a JSON array of
|
|
89
|
+
objects containing `path` plus optional `name`, `description`, and
|
|
90
|
+
`githubRepos`, which is always a JSON array of GitHub repository URLs. Before
|
|
91
|
+
importing, list native local Codex projects once, canonicalize every input
|
|
92
|
+
path, and require an exact local-project match for every entry. Reject or
|
|
93
|
+
report every unmatched path instead of indexing it. Import merges by
|
|
94
|
+
canonical path, preserves an existing name or description when omitted, and
|
|
95
|
+
unions existing and imported repository lists without duplicates. Use
|
|
96
|
+
`--replace` only when the user explicitly requests replacement. Run
|
|
97
|
+
`project list --json` afterward and verify every imported entry.
|
|
98
|
+
2. Inspect indexed projects with `project list --json`. Remove by name with
|
|
99
|
+
`project remove`. Existing task entries keep their project snapshots.
|
|
100
|
+
|
|
101
|
+
Example managed-workspace import entry:
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"name": "skills-workspace",
|
|
106
|
+
"path": "/workspace/skills-workspace",
|
|
107
|
+
"githubRepos": [
|
|
108
|
+
"https://github.com/example/skill-one",
|
|
109
|
+
"https://github.com/example/skill-two"
|
|
110
|
+
],
|
|
111
|
+
"description": "Manages the listed child skill repositories."
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
TaskChef accepts configuration schema version 2 only. Its optional exact
|
|
116
|
+
`dashboard` object contains boolean `autostart`; absence means enabled and
|
|
117
|
+
`false` opts out of MCP-lifecycle dashboard startup without disabling manual
|
|
118
|
+
`$taskchef-dashboard` recovery. `githubRepos` is always an array; unsupported
|
|
119
|
+
configuration is rejected without being rewritten.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: taskchef-copilot
|
|
3
|
-
description: "Explain
|
|
3
|
+
description: "Explain TaskChef outcomes from cached briefs or continue an explicitly selected assignment in its existing task. Handles historical $taskchef-report requests; dashboard monitoring is separate."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# TaskChef Copilot
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: taskchef-delegate
|
|
3
|
-
description: "Dispatch
|
|
3
|
+
description: "Dispatch work received in the canonical TaskChef workspace into Codex tasks. Elsewhere, use only for explicit delegation of separate work; an existing executor keeps its assignment."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# TaskChef Delegate
|
|
@@ -49,6 +49,13 @@ stop and report that the TaskChef plugin must be reloaded or installed.
|
|
|
49
49
|
3. Route against configured project `name`, `description`, and canonical
|
|
50
50
|
`githubRepos`; use `path` only as checkout identity. Require exactly one
|
|
51
51
|
match and an exact native-project path. Ask instead of guessing.
|
|
52
|
+
Select `planner` for a requested planning assignment and `implementer` for
|
|
53
|
+
coding work. Use the matched project's `projectModelRoles` from preparation;
|
|
54
|
+
resolve explicit user choices and follow [model roles](references/model-roles.md).
|
|
55
|
+
Small coding changes need no separate planning task. For a planning/coding
|
|
56
|
+
split, the saved plan is the handoff to a separately requested implementation
|
|
57
|
+
assignment; do not switch models during a turn or coordinate phases automatically.
|
|
58
|
+
Resolve configuration problems before recording the task.
|
|
52
59
|
4. Build each executor instruction in this exact shape:
|
|
53
60
|
|
|
54
61
|
- Begin with the actual assignment on the first line and keep its complete
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Dispatch model roles
|
|
2
|
+
|
|
3
|
+
Preparation includes personal and per-project model previews. Use the exact
|
|
4
|
+
matched project's preview. Role preferences use native Codex agent TOML under
|
|
5
|
+
`$CODEX_HOME/agents/` (default `~/.codex/agents/`) and that project's
|
|
6
|
+
`.codex/agents/`; they are optional. The resolver requires Python 3.11+.
|
|
7
|
+
|
|
8
|
+
Select `planner` for a planning assignment or `implementer` for coding. Pass
|
|
9
|
+
its `taskOverrides` as native `model` and `thinking` arguments only after checking
|
|
10
|
+
those values against the current create-task tool's supported model/effort
|
|
11
|
+
choices. A missing role means omit both arguments and use the native new-task
|
|
12
|
+
default. This is not guaranteed to inherit the dispatcher's model.
|
|
13
|
+
|
|
14
|
+
Explicit user model choices take precedence over the project role, personal
|
|
15
|
+
role, and native defaults. An explicit model without explicit effort omits effort and uses the native
|
|
16
|
+
interface's omission behavior; do not mix in a different role's effort or claim
|
|
17
|
+
a specific effective effort without evidence. Explicit effort
|
|
18
|
+
alone replaces the resolved role effort. Project roles replace personal roles
|
|
19
|
+
as a unit. To resolve explicit choices, or recheck a preview after configuration
|
|
20
|
+
changes, run:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
python3 <plugin-root>/scripts/roles/resolve_roles.py --project <project-path> --role implementer --model <user-model> --effort <user-effort>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Omit flags the user did not specify. Resolve the plugin root from this skill's
|
|
27
|
+
real path, two parents above the skill directory. Do not substitute dispatcher
|
|
28
|
+
paths for the target project or infer model names from skill prose.
|
|
29
|
+
|
|
30
|
+
Report malformed profiles, duplicate names, unavailable models/efforts, and
|
|
31
|
+
resolver failures. Do not quietly fall back and claim preferences were honored.
|
|
32
|
+
The local model catalog is advisory: explain if a current native tool disproves
|
|
33
|
+
its stale warning. Otherwise resolve the problem or obtain a valid explicit
|
|
34
|
+
choice before task creation. Native creation failures retain normal TaskChef
|
|
35
|
+
failure reporting. A preparation without role fields supports historical
|
|
36
|
+
installations: check role files before deciding that no preferences exist.
|
|
37
|
+
|
|
38
|
+
Only model and effort are adapted. The native agent file's instructions, tools,
|
|
39
|
+
permissions, and other settings are not applied by create-task arguments. A
|
|
40
|
+
role name in a title is not a native role selector. If the native interface adds
|
|
41
|
+
a role selector, use it only with verified effective settings.
|
|
42
|
+
|
|
43
|
+
For a plan-to-implementation handoff, a planner assignment can save
|
|
44
|
+
`plans/addition.md` describing a pure addition function and the acceptance
|
|
45
|
+
example `2 + 3 = 5`. A later implementer assignment reads that exact plan,
|
|
46
|
+
implements the function, runs the example, and uses fresh reviewer subagents.
|
|
47
|
+
The dispatcher returns after each creation; it does not wait for or launch
|
|
48
|
+
subsequent phases automatically. A small addition change can instead go
|
|
49
|
+
straight to the implementer.
|