@nghyane/arcane 0.1.8 → 0.1.11
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/package.json +6 -6
- package/src/config/settings-schema.ts +0 -10
- package/src/discovery/helpers.ts +1 -6
- package/src/index.ts +1 -0
- package/src/main.ts +3 -0
- package/src/memories/index.ts +3 -3
- package/src/modes/components/model-selector.ts +1 -1
- package/src/modes/components/settings-defs.ts +0 -8
- package/src/modes/components/status-line.ts +15 -40
- package/src/modes/components/user-message.ts +2 -0
- package/src/modes/components/welcome.ts +1 -1
- package/src/modes/interactive-mode.ts +2 -0
- package/src/modes/theme/dark.json +56 -59
- package/src/modes/theme/defaults/dark-catppuccin.json +47 -56
- package/src/modes/theme/defaults/dark-dracula.json +24 -32
- package/src/modes/theme/defaults/dark-gruvbox.json +53 -74
- package/src/modes/theme/defaults/dark-solarized.json +33 -35
- package/src/modes/theme/defaults/dark-tokyo-night.json +57 -67
- package/src/modes/theme/defaults/index.ts +3 -179
- package/src/modes/theme/defaults/light-catppuccin.json +42 -50
- package/src/modes/theme/defaults/light-github.json +68 -94
- package/src/modes/theme/defaults/light-solarized.json +41 -49
- package/src/modes/theme/light.json +14 -12
- package/src/modes/theme/theme-schema.json +4 -0
- package/src/modes/theme/theme.ts +89 -6
- package/src/patch/applicator.ts +12 -4
- package/src/prompts/agents/task.md +1 -1
- package/src/prompts/system/subagent-system-prompt.md +2 -14
- package/src/prompts/system/system-prompt.md +12 -14
- package/src/prompts/tools/task.md +49 -178
- package/src/prompts/tools/todo-write.md +4 -4
- package/src/sdk.ts +15 -16
- package/src/session/session-manager.ts +1 -3
- package/src/task/executor.ts +2 -2
- package/src/task/index.ts +5 -5
- package/src/task/types.ts +7 -20
- package/src/tools/index.ts +16 -33
- package/src/tools/subagent-tool.ts +5 -5
- package/src/tools/todo-write.ts +0 -37
- package/src/tui/output-block.ts +2 -12
- package/src/modes/theme/defaults/alabaster.json +0 -93
- package/src/modes/theme/defaults/amethyst.json +0 -96
- package/src/modes/theme/defaults/anthracite.json +0 -93
- package/src/modes/theme/defaults/basalt.json +0 -91
- package/src/modes/theme/defaults/birch.json +0 -95
- package/src/modes/theme/defaults/dark-abyss.json +0 -91
- package/src/modes/theme/defaults/dark-arctic.json +0 -104
- package/src/modes/theme/defaults/dark-aurora.json +0 -95
- package/src/modes/theme/defaults/dark-cavern.json +0 -91
- package/src/modes/theme/defaults/dark-copper.json +0 -95
- package/src/modes/theme/defaults/dark-cosmos.json +0 -90
- package/src/modes/theme/defaults/dark-cyberpunk.json +0 -102
- package/src/modes/theme/defaults/dark-eclipse.json +0 -91
- package/src/modes/theme/defaults/dark-ember.json +0 -95
- package/src/modes/theme/defaults/dark-equinox.json +0 -90
- package/src/modes/theme/defaults/dark-forest.json +0 -96
- package/src/modes/theme/defaults/dark-github.json +0 -105
- package/src/modes/theme/defaults/dark-lavender.json +0 -95
- package/src/modes/theme/defaults/dark-lunar.json +0 -89
- package/src/modes/theme/defaults/dark-midnight.json +0 -95
- package/src/modes/theme/defaults/dark-monochrome.json +0 -94
- package/src/modes/theme/defaults/dark-monokai.json +0 -98
- package/src/modes/theme/defaults/dark-nebula.json +0 -90
- package/src/modes/theme/defaults/dark-nord.json +0 -97
- package/src/modes/theme/defaults/dark-ocean.json +0 -101
- package/src/modes/theme/defaults/dark-one.json +0 -100
- package/src/modes/theme/defaults/dark-rainforest.json +0 -91
- package/src/modes/theme/defaults/dark-reef.json +0 -91
- package/src/modes/theme/defaults/dark-retro.json +0 -92
- package/src/modes/theme/defaults/dark-rose-pine.json +0 -96
- package/src/modes/theme/defaults/dark-sakura.json +0 -95
- package/src/modes/theme/defaults/dark-slate.json +0 -95
- package/src/modes/theme/defaults/dark-solstice.json +0 -90
- package/src/modes/theme/defaults/dark-starfall.json +0 -91
- package/src/modes/theme/defaults/dark-sunset.json +0 -99
- package/src/modes/theme/defaults/dark-swamp.json +0 -90
- package/src/modes/theme/defaults/dark-synthwave.json +0 -103
- package/src/modes/theme/defaults/dark-taiga.json +0 -91
- package/src/modes/theme/defaults/dark-terminal.json +0 -95
- package/src/modes/theme/defaults/dark-tundra.json +0 -91
- package/src/modes/theme/defaults/dark-twilight.json +0 -91
- package/src/modes/theme/defaults/dark-volcanic.json +0 -91
- package/src/modes/theme/defaults/graphite.json +0 -92
- package/src/modes/theme/defaults/light-arctic.json +0 -107
- package/src/modes/theme/defaults/light-aurora-day.json +0 -91
- package/src/modes/theme/defaults/light-canyon.json +0 -91
- package/src/modes/theme/defaults/light-cirrus.json +0 -90
- package/src/modes/theme/defaults/light-coral.json +0 -95
- package/src/modes/theme/defaults/light-cyberpunk.json +0 -96
- package/src/modes/theme/defaults/light-dawn.json +0 -90
- package/src/modes/theme/defaults/light-dunes.json +0 -91
- package/src/modes/theme/defaults/light-eucalyptus.json +0 -95
- package/src/modes/theme/defaults/light-forest.json +0 -100
- package/src/modes/theme/defaults/light-frost.json +0 -95
- package/src/modes/theme/defaults/light-glacier.json +0 -91
- package/src/modes/theme/defaults/light-gruvbox.json +0 -108
- package/src/modes/theme/defaults/light-haze.json +0 -90
- package/src/modes/theme/defaults/light-honeycomb.json +0 -95
- package/src/modes/theme/defaults/light-lagoon.json +0 -91
- package/src/modes/theme/defaults/light-lavender.json +0 -95
- package/src/modes/theme/defaults/light-meadow.json +0 -91
- package/src/modes/theme/defaults/light-mint.json +0 -95
- package/src/modes/theme/defaults/light-monochrome.json +0 -101
- package/src/modes/theme/defaults/light-ocean.json +0 -99
- package/src/modes/theme/defaults/light-one.json +0 -99
- package/src/modes/theme/defaults/light-opal.json +0 -91
- package/src/modes/theme/defaults/light-orchard.json +0 -91
- package/src/modes/theme/defaults/light-paper.json +0 -95
- package/src/modes/theme/defaults/light-prism.json +0 -90
- package/src/modes/theme/defaults/light-retro.json +0 -98
- package/src/modes/theme/defaults/light-sand.json +0 -95
- package/src/modes/theme/defaults/light-savanna.json +0 -91
- package/src/modes/theme/defaults/light-soleil.json +0 -90
- package/src/modes/theme/defaults/light-sunset.json +0 -99
- package/src/modes/theme/defaults/light-synthwave.json +0 -98
- package/src/modes/theme/defaults/light-tokyo-night.json +0 -111
- package/src/modes/theme/defaults/light-wetland.json +0 -91
- package/src/modes/theme/defaults/light-zenith.json +0 -89
- package/src/modes/theme/defaults/limestone.json +0 -94
- package/src/modes/theme/defaults/mahogany.json +0 -97
- package/src/modes/theme/defaults/marble.json +0 -93
- package/src/modes/theme/defaults/obsidian.json +0 -91
- package/src/modes/theme/defaults/onyx.json +0 -91
- package/src/modes/theme/defaults/pearl.json +0 -93
- package/src/modes/theme/defaults/porcelain.json +0 -91
- package/src/modes/theme/defaults/quartz.json +0 -96
- package/src/modes/theme/defaults/sandstone.json +0 -95
- package/src/modes/theme/defaults/titanium.json +0 -90
- package/src/prompts/system/subagent-submit-reminder.md +0 -11
- package/src/tools/jtd-to-json-schema.ts +0 -247
- package/src/tools/submit-result.ts +0 -152
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
# Task
|
|
2
2
|
|
|
3
|
-
Launch
|
|
3
|
+
Launch a fire-and-forget subagent to execute well-scoped work. Think of it as a productive junior engineer who cannot ask follow-ups once started.
|
|
4
|
+
- **Use for**: Multi-file implementations, cross-layer refactors, mass migrations, boilerplate generation
|
|
5
|
+
- **Don't use for**: Exploratory work, architectural decisions, single-file edits, reading a file
|
|
4
6
|
|
|
5
|
-
##
|
|
6
|
-
Subagents receive the **full system prompt**, including AGENTS.md, context files, and skills. Do NOT repeat project rules, coding conventions, or style guidelines in `context` — they already have them.
|
|
7
|
+
## Subagent capabilities
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
Subagents have no access to your conversation history. They don't know:
|
|
10
|
-
- Decisions you made but didn't write down
|
|
11
|
-
- Which approach you chose among alternatives
|
|
12
|
-
- What you learned from reading files during this session
|
|
13
|
-
- Requirements the user stated only in conversation
|
|
14
|
-
|
|
15
|
-
Subagents CAN grep the parent conversation file for supplementary details.
|
|
9
|
+
Subagents receive the **full system prompt**, including AGENTS.md, context files, and skills. They have no access to your conversation history — they don't know decisions you made, approaches you chose, or requirements stated only in conversation. Subagents CAN grep the parent conversation file for supplementary details.
|
|
16
10
|
---
|
|
17
11
|
|
|
18
12
|
## Parameters
|
|
@@ -22,35 +16,18 @@ Subagents CAN grep the parent conversation file for supplementary details.
|
|
|
22
16
|
Shared background prepended verbatim to every task `assignment`. Use only for session-specific information subagents lack.
|
|
23
17
|
|
|
24
18
|
<critical>
|
|
25
|
-
Do NOT include project rules, coding conventions, or style guidelines — subagents already have AGENTS.md
|
|
19
|
+
Do NOT include project rules, coding conventions, or style guidelines — subagents already have AGENTS.md. Restating any rule from AGENTS.md in `context` is a bug.
|
|
26
20
|
</critical>
|
|
27
|
-
**Before writing each line of context, ask:** "Would this sentence be true for ANY task in this repo, or only for THIS specific batch?" If it applies to any task →
|
|
28
|
-
|
|
29
|
-
WRONG — restating project rules the subagent already has:
|
|
30
|
-
```
|
|
31
|
-
## Constraints
|
|
32
|
-
- Use X import style, not Y (per AGENTS.md)
|
|
33
|
-
- Use Z for private fields per AGENTS.md
|
|
34
|
-
- Run the formatter after changes
|
|
35
|
-
- Follow the logging convention
|
|
36
|
-
```
|
|
37
|
-
Every line above restates a project convention. The subagent reads AGENTS.md. Delete them all.
|
|
38
|
-
|
|
39
|
-
RIGHT — only session-specific decisions the subagent cannot infer from project files:
|
|
40
|
-
```
|
|
41
|
-
## Constraints
|
|
42
|
-
- We decided to use approach A over B (session decision)
|
|
43
|
-
- The migration target type is `Foo` from `bar` package (looked up this session)
|
|
44
|
-
```
|
|
21
|
+
**Before writing each line of context, ask:** "Would this sentence be true for ANY task in this repo, or only for THIS specific batch?" If it applies to any task → the subagent already has it → delete the line.
|
|
45
22
|
|
|
46
23
|
Use template; omit non-applicable sections:
|
|
47
24
|
|
|
48
25
|
````
|
|
49
26
|
## Goal
|
|
50
|
-
One sentence: batch accomplishes together.
|
|
27
|
+
One sentence: what the batch accomplishes together.
|
|
51
28
|
|
|
52
29
|
## Non-goals
|
|
53
|
-
Explicitly exclude tempting scope — what tasks must not touch
|
|
30
|
+
Explicitly exclude tempting scope — what tasks must not touch.
|
|
54
31
|
|
|
55
32
|
## Constraints
|
|
56
33
|
- Task-specific MUST / MUST NOT rules not already in AGENTS.md
|
|
@@ -58,49 +35,43 @@ Explicitly exclude tempting scope — what tasks must not touch/attempt.
|
|
|
58
35
|
|
|
59
36
|
## Reference Files
|
|
60
37
|
- `path/to/file.ext` — pattern demo
|
|
61
|
-
- `path/to/other.ext` — reuse or avoid
|
|
62
38
|
|
|
63
39
|
## API Contract (if tasks produce/consume shared interface)
|
|
64
40
|
```language
|
|
65
|
-
// Exact type definitions, function signatures
|
|
41
|
+
// Exact type definitions, function signatures
|
|
66
42
|
```
|
|
67
43
|
|
|
68
44
|
## Acceptance (global)
|
|
69
45
|
- Definition of "done" for batch
|
|
70
|
-
-
|
|
46
|
+
- For parallel tasks, build/test/lint verification happens AFTER all tasks complete — not inside tasks. Single tasks may self-verify.
|
|
71
47
|
````
|
|
72
|
-
**Belongs in `context`**:
|
|
73
|
-
**
|
|
74
|
-
**Does NOT belong in `context`**: project rules already in AGENTS.md/context files, per-task file lists, one-off requirements (go in `assignment`), and strict response contracts that only apply to one task.
|
|
48
|
+
**Belongs in `context`**: session decisions, reference paths, shared type definitions, API contracts, global acceptance — anything 2+ tasks need that isn't in AGENTS.md.
|
|
49
|
+
**Does NOT belong**: project rules from AGENTS.md, per-task file lists, one-off requirements (go in `assignment`).
|
|
75
50
|
|
|
76
51
|
### `tasks` (required)
|
|
77
52
|
|
|
78
|
-
Array tasks execute in parallel.
|
|
53
|
+
Array of tasks that execute in parallel.
|
|
79
54
|
|
|
80
55
|
|Field|Required|Purpose|
|
|
81
56
|
|---|---|---|
|
|
82
|
-
|`id
|
|
83
|
-
|`description
|
|
84
|
-
|`assignment
|
|
85
|
-
|`skills`||Skill names preload. Use only when changes correctness
|
|
86
|
-
|
|
87
|
-
Outputs are free-form text/JSON from each subtask. If you need strict structure, define it clearly inside each `assignment` and validate at the caller.
|
|
57
|
+
|`id`|yes|CamelCase identifier, max 32 chars|
|
|
58
|
+
|`description`|yes|Short one-liner for UI display only — not seen by subagent|
|
|
59
|
+
|`assignment`|yes|Complete per-task instructions (see below)|
|
|
60
|
+
|`skills`||Skill names to preload. Use only when it changes correctness.|
|
|
88
61
|
---
|
|
89
62
|
|
|
90
63
|
## Writing an assignment
|
|
91
64
|
|
|
92
|
-
<critical
|
|
93
|
-
|
|
94
|
-
`assignment` must contain enough info for agent to act **without asking a clarifying question**.
|
|
95
|
-
**Minimum bar:** assignment under ~8 lines or missing acceptance criteria = too vague. One-liners guaranteed failure.
|
|
65
|
+
<critical>
|
|
66
|
+
`assignment` must contain enough info for the subagent to act **without asking a clarifying question**. One-liners guarantee failure.
|
|
96
67
|
|
|
97
|
-
Use structure
|
|
68
|
+
Use this structure:
|
|
98
69
|
|
|
99
70
|
```
|
|
100
71
|
## Target
|
|
101
72
|
- Files: exact path(s)
|
|
102
73
|
- Symbols/entrypoints: specific functions, types, exports
|
|
103
|
-
- Non-goals: what task must NOT touch
|
|
74
|
+
- Non-goals: what task must NOT touch
|
|
104
75
|
|
|
105
76
|
## Change
|
|
106
77
|
- Step-by-step: add/remove/rename/restructure
|
|
@@ -108,168 +79,68 @@ Use structure every assignment:
|
|
|
108
79
|
|
|
109
80
|
## Edge Cases / Don't Break
|
|
110
81
|
- Tricky case 1: ...
|
|
111
|
-
-
|
|
112
|
-
- Existing behavior must survive: ...
|
|
82
|
+
- Existing behavior that must survive: ...
|
|
113
83
|
|
|
114
84
|
## Acceptance (task-local)
|
|
115
85
|
- Expected behavior or observable result
|
|
116
|
-
- DO NOT include project-wide build/test/lint commands
|
|
86
|
+
- For parallel tasks: DO NOT include project-wide build/test/lint commands
|
|
117
87
|
```
|
|
118
88
|
|
|
119
|
-
`context` carries shared background. `assignment` carries only delta: file-specific instructions, local edge cases, per-task acceptance
|
|
120
|
-
|
|
121
|
-
### Anti-patterns (ban these)
|
|
122
|
-
**Vague assignments** — agent guesses wrong or stalls:
|
|
123
|
-
- "Refactor this to be cleaner."
|
|
124
|
-
- "Migrate to N-API."
|
|
125
|
-
- "Fix the bug in streaming."
|
|
126
|
-
- "Update all constructors in `src/**/*.ts`."
|
|
127
|
-
**Vague context** — forces agent invent conventions:
|
|
128
|
-
- "Use existing patterns."
|
|
129
|
-
- "Follow conventions."
|
|
130
|
-
- "No WASM."
|
|
131
|
-
**Redundant context** — wastes tokens repeating what subagents already have:
|
|
132
|
-
- Restating AGENTS.md rules (coding style, import conventions, formatting commands, logger usage, etc.)
|
|
133
|
-
- Repeating project constraints from context files
|
|
134
|
-
- Listing tool/framework preferences already documented in the repo
|
|
135
|
-
|
|
136
|
-
If a constraint appears in AGENTS.md, it MUST NOT appear in `context`. The subagent has the full system prompt.
|
|
137
|
-
|
|
138
|
-
If tempted to write above, expand using templates.
|
|
139
|
-
**Test/lint commands in parallel tasks** — edit wars:
|
|
140
|
-
Parallel agents share working tree. If two agents run `bun check` or `bun test` concurrently, they see each other's half-finished edits, "fix" phantom errors, loop. **Never tell parallel tasks run project-wide build/test/lint commands.** Each task edits, stops. Caller verifies after all tasks complete.
|
|
141
|
-
**If you can't specify scope yet**, create **Discovery task** first: enumerate files, find callsites, list candidates. Then fan out with explicit paths.
|
|
89
|
+
`context` carries shared background. `assignment` carries only delta: file-specific instructions, local edge cases, per-task acceptance.
|
|
142
90
|
|
|
143
91
|
### Delegate intent, not keystrokes
|
|
144
92
|
|
|
145
|
-
Your role
|
|
146
|
-
**Be specific about:** constraints, naming
|
|
147
|
-
**Delegate:** code reading, approach selection, exact edit locations, implementation details.
|
|
148
|
-
|
|
149
|
-
Micromanaging (you think, agent types):
|
|
150
|
-
```
|
|
151
|
-
assignment: "In src/api/handler.ts, line 47, change `throw err` to `throw new ApiError(err.message, 500)`.
|
|
152
|
-
On line 63, wrap fetch call try/catch return 502 on failure.
|
|
153
|
-
On line 89, add null check before accessing resp.body..."
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
Delegating (agent thinks within constraints):
|
|
157
|
-
```
|
|
158
|
-
assignment: "## Target\n- Files: src/api/handler.ts\n\n## Change\nImprove error handling: replace raw throws
|
|
159
|
-
with typed ApiError instances, add try/catch around external calls, guard against null responses.\n\n
|
|
160
|
-
## Edge Cases / Don't Break\n- Existing error codes in tests must still match\n
|
|
161
|
-
- Don't change public function signatures"
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
First style wastes your time, brittle if code shifts. Second gives agent room to do work.
|
|
93
|
+
Your role is tech lead: set direction, define boundaries, call out pitfalls — then get out of the way. Don't dictate line-by-line edits.
|
|
94
|
+
**Be specific about:** constraints, naming, API contracts, "don't break" items, acceptance criteria.
|
|
95
|
+
**Delegate:** code reading, approach selection, exact edit locations, implementation details.
|
|
165
96
|
</critical>
|
|
166
97
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
</tasks>
|
|
176
|
-
</example>
|
|
177
|
-
|
|
178
|
-
<example type="good" label="Shared rules in context, only deltas in assignment">
|
|
179
|
-
<context>
|
|
180
|
-
## Goal
|
|
181
|
-
Port WASM modules to N-API, matching existing arcane-natives conventions.
|
|
182
|
-
|
|
183
|
-
## Non-goals
|
|
184
|
-
Do not touch TS bindings or downstream consumers — separate phase.
|
|
185
|
-
|
|
186
|
-
## Constraints
|
|
187
|
-
- MUST use `#[napi]` attribute macro on all exports
|
|
188
|
-
- MUST return `napi::Result<T>` for fallible ops; never panic
|
|
189
|
-
- MUST use `spawn_blocking` for filesystem I/O or >1ms work
|
|
190
|
-
...
|
|
191
|
-
|
|
192
|
-
## Acceptance (global)
|
|
193
|
-
- Caller verifies after all tasks: `cargo test -p arcane-natives` and `cargo build -p arcane-natives` with no warnings
|
|
194
|
-
- Individual tasks must NOT run these commands themselves
|
|
195
|
-
</context>
|
|
196
|
-
|
|
197
|
-
<tasks>
|
|
198
|
-
<task name="PortGrep">
|
|
199
|
-
<description>Port grep module to N-API</description>
|
|
200
|
-
<assignment>
|
|
201
|
-
## Target
|
|
202
|
-
- Files: `src/grep.rs`, `src/lib.rs` (registration only)
|
|
203
|
-
- Symbols: search, search_multi, compile_pattern
|
|
204
|
-
|
|
205
|
-
## Change
|
|
206
|
-
- Implement three N-API exports in grep.rs:
|
|
207
|
-
- `search(pattern: JsString, path: JsString, env: Env) -> napi::Result<Vec<Match>>`
|
|
208
|
-
...
|
|
209
|
-
|
|
210
|
-
## Acceptance (task-local)
|
|
211
|
-
- Three functions exported with correct signatures (caller verifies build after all tasks)
|
|
212
|
-
</assignment>
|
|
213
|
-
</task>
|
|
214
|
-
|
|
215
|
-
<task name="PortHighlight">
|
|
216
|
-
<description>Port highlight module to N-API</description>
|
|
217
|
-
<assignment>
|
|
218
|
-
## Target
|
|
219
|
-
- Files: `src/highlight.rs`, `src/lib.rs` (registration only)
|
|
220
|
-
...
|
|
221
|
-
</assignment>
|
|
222
|
-
</task>
|
|
223
|
-
</tasks>
|
|
224
|
-
</example>
|
|
98
|
+
### Anti-patterns
|
|
99
|
+
**Vague assignments** — subagent guesses wrong or stalls:
|
|
100
|
+
- "Refactor this to be cleaner."
|
|
101
|
+
- "Fix the bug in streaming."
|
|
102
|
+
- "Update all constructors in `src/**/*.ts`."
|
|
103
|
+
**Test/lint in parallel tasks** — edit wars:
|
|
104
|
+
Parallel agents share working tree. If two agents run `bun check` concurrently, they see each other's half-finished edits, "fix" phantom errors, loop. **Never tell parallel tasks to run project-wide build/test/lint.** Each task edits, stops. Caller verifies after all complete. Single-task launches may include verification.
|
|
105
|
+
**If you can't specify scope yet**, create a **Discovery task** first: enumerate files, find callsites, list candidates. Then fan out with explicit paths.
|
|
225
106
|
---
|
|
226
107
|
|
|
227
108
|
## Task scope
|
|
228
109
|
|
|
229
|
-
Each task small, well-defined
|
|
230
|
-
**Signs task too broad:**
|
|
231
|
-
|
|
232
|
-
- Assignment says "update all" / "migrate everything" / "refactor across"
|
|
233
|
-
- Scope covers entire package or directory tree
|
|
234
|
-
**Fix:** enumerate files first (grep/glob discovery), then fan out one task per file or small cluster.
|
|
110
|
+
Each task: small, well-defined — **at most 3-5 files**.
|
|
111
|
+
**Signs task is too broad:** file paths use globs, assignment says "update all" / "migrate everything", scope covers entire package.
|
|
112
|
+
**Fix:** enumerate files first (grep/glob), then fan out one task per file or small cluster.
|
|
235
113
|
---
|
|
236
114
|
|
|
237
115
|
## Parallelization
|
|
238
116
|
**Test:** Can task B produce correct output without seeing task A's result?
|
|
239
117
|
- **Yes** → parallelize
|
|
240
|
-
- **No** →
|
|
118
|
+
- **No** → sequential (A completes, then launch B with A's output in context)
|
|
241
119
|
|
|
242
120
|
### Must be sequential
|
|
243
121
|
|
|
244
122
|
|First|Then|Reason|
|
|
245
123
|
|---|---|---|
|
|
246
124
|
|Define types/interfaces|Implement consumers|Consumers need contract|
|
|
247
|
-
|Create API exports|Write bindings/callers|Callers need
|
|
248
|
-
|Scaffold structure|Implement bodies|Bodies need shape|
|
|
125
|
+
|Create API exports|Write bindings/callers|Callers need signatures|
|
|
249
126
|
|Core module|Dependent modules|Dependents import from core|
|
|
250
|
-
|Schema/DB migration|Application logic|Logic depends on new schema shape|
|
|
251
127
|
|
|
252
128
|
### Safe to parallelize
|
|
253
129
|
- Independent modules, no cross-imports
|
|
254
130
|
- Tests for already-implemented code
|
|
255
131
|
- Isolated file-scoped refactors
|
|
256
|
-
- Documentation for stable APIs
|
|
257
|
-
|
|
258
|
-
### Phased execution
|
|
259
132
|
|
|
260
|
-
|
|
261
|
-
**Phase 1 —
|
|
262
|
-
**Phase 2 — Parallel
|
|
133
|
+
### Multi-phase pattern
|
|
134
|
+
**Phase 1 — Sequential**: define shared contracts (types, interfaces, schemas).
|
|
135
|
+
**Phase 2 — Parallel**: fan out tasks consuming same known interface.
|
|
263
136
|
**Phase 3 — Integration** (do yourself): wire modules, fix mismatches, verify builds.
|
|
264
|
-
**Phase 4 — Dependent layer**: fan out tasks consuming Phase 2 outputs.
|
|
265
137
|
---
|
|
266
138
|
|
|
267
139
|
## Pre-flight checklist
|
|
268
140
|
|
|
269
141
|
Before calling tool, verify:
|
|
270
|
-
- [ ] `context` includes only session-specific info not already in AGENTS.md
|
|
271
|
-
- [ ] Each
|
|
272
|
-
- [ ]
|
|
273
|
-
- [ ]
|
|
274
|
-
- [ ]
|
|
275
|
-
- [ ] No task runs project-wide build/test/lint — you do after all tasks complete
|
|
142
|
+
- [ ] `context` includes only session-specific info not already in AGENTS.md
|
|
143
|
+
- [ ] Each assignment has Target, Change, Edge Cases, Acceptance sections
|
|
144
|
+
- [ ] Assignments reference exact file paths (no globs)
|
|
145
|
+
- [ ] Scope small, file paths explicit
|
|
146
|
+
- [ ] Parallel tasks don't run project-wide build/test/lint — you do after all tasks complete (single tasks may self-verify)
|
|
@@ -18,11 +18,11 @@ Use proactively:
|
|
|
18
18
|
- in_progress: working
|
|
19
19
|
- completed: finished
|
|
20
20
|
2. **Task Management**:
|
|
21
|
-
- Update status
|
|
22
|
-
- Mark
|
|
23
|
-
-
|
|
21
|
+
- Update status each turn
|
|
22
|
+
- Mark completed after each code execution finishes — do not defer to a later turn
|
|
23
|
+
- Multiple tasks may be in_progress simultaneously when working in parallel
|
|
24
24
|
- Remove tasks no longer relevant
|
|
25
|
-
-
|
|
25
|
+
- Mark tasks completed as they finish, regardless of list order
|
|
26
26
|
3. **Task Completion Requirements**:
|
|
27
27
|
- ONLY mark completed when FULLY accomplished
|
|
28
28
|
- On errors/blockers/inability to finish, keep in_progress
|
package/src/sdk.ts
CHANGED
|
@@ -72,6 +72,7 @@ import {
|
|
|
72
72
|
loadSshTool,
|
|
73
73
|
PythonTool,
|
|
74
74
|
ReadTool,
|
|
75
|
+
type SubagentContext,
|
|
75
76
|
setPreferredImageProvider,
|
|
76
77
|
setPreferredSearchProvider,
|
|
77
78
|
type Tool,
|
|
@@ -157,12 +158,8 @@ export interface CreateAgentSessionOptions {
|
|
|
157
158
|
/** Tool names explicitly requested (enables disabled-by-default tools) */
|
|
158
159
|
toolNames?: string[];
|
|
159
160
|
|
|
160
|
-
/**
|
|
161
|
-
|
|
162
|
-
/** Whether to include the submit_result tool by default */
|
|
163
|
-
requireSubmitResultTool?: boolean;
|
|
164
|
-
/** Task recursion depth (for subagent sessions). Default: 0 */
|
|
165
|
-
taskDepth?: number;
|
|
161
|
+
/** Whether this is a subagent session. Default: false */
|
|
162
|
+
isSubagent?: boolean;
|
|
166
163
|
/** Parent task ID prefix for nested artifact naming (e.g., "6-Extensions") */
|
|
167
164
|
parentTaskPrefix?: string;
|
|
168
165
|
|
|
@@ -223,6 +220,7 @@ export {
|
|
|
223
220
|
PythonTool,
|
|
224
221
|
ReadTool,
|
|
225
222
|
WriteTool,
|
|
223
|
+
type SubagentContext,
|
|
226
224
|
type ToolSession,
|
|
227
225
|
};
|
|
228
226
|
|
|
@@ -629,8 +627,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
629
627
|
|
|
630
628
|
// For subagent sessions using GitHub Copilot, add X-Initiator header
|
|
631
629
|
// to ensure proper billing (agent-initiated vs user-initiated)
|
|
632
|
-
const
|
|
633
|
-
const forceCopilotAgentInitiator =
|
|
630
|
+
const isSubagent = options.isSubagent ?? false;
|
|
631
|
+
const forceCopilotAgentInitiator = isSubagent;
|
|
634
632
|
if (forceCopilotAgentInitiator && model?.provider === "github-copilot") {
|
|
635
633
|
model = {
|
|
636
634
|
...model,
|
|
@@ -722,9 +720,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
722
720
|
contextFiles,
|
|
723
721
|
skills,
|
|
724
722
|
eventBus,
|
|
725
|
-
|
|
726
|
-
requireSubmitResultTool: options.requireSubmitResultTool,
|
|
727
|
-
taskDepth: options.taskDepth ?? 0,
|
|
723
|
+
isSubagent: options.isSubagent ?? false,
|
|
728
724
|
getSessionFile: () => sessionManager.getSessionFile() ?? null,
|
|
729
725
|
getSessionId: () => sessionManager.getSessionId?.() ?? null,
|
|
730
726
|
getSessionSpawns: () => options.spawns ?? "*",
|
|
@@ -736,10 +732,12 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
736
732
|
if (model) return formatModelString(model);
|
|
737
733
|
return undefined;
|
|
738
734
|
},
|
|
739
|
-
|
|
735
|
+
subagentContext: {
|
|
736
|
+
getCompactContext: () => session.formatCompactContext(),
|
|
737
|
+
authStorage,
|
|
738
|
+
modelRegistry,
|
|
739
|
+
},
|
|
740
740
|
settings,
|
|
741
|
-
authStorage,
|
|
742
|
-
modelRegistry,
|
|
743
741
|
};
|
|
744
742
|
|
|
745
743
|
// Initialize internal URL router for internal protocols (agent://, artifact://, memory://, skill://, rule://)
|
|
@@ -798,7 +796,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
798
796
|
});
|
|
799
797
|
time("discoverAndLoadMCPTools");
|
|
800
798
|
mcpManager = mcpResult.manager;
|
|
801
|
-
toolSession.
|
|
799
|
+
if (!toolSession.subagentContext) toolSession.subagentContext = {};
|
|
800
|
+
toolSession.subagentContext.mcpManager = mcpManager;
|
|
802
801
|
|
|
803
802
|
// If we extracted Exa API keys from MCP configs and EXA_AARCANE_KEY isn't set, use the first one
|
|
804
803
|
if (mcpResult.exaApiKeys.length > 0 && !$env.EXA_AARCANE_KEY) {
|
|
@@ -1273,7 +1272,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1273
1272
|
settings,
|
|
1274
1273
|
modelRegistry,
|
|
1275
1274
|
agentDir,
|
|
1276
|
-
|
|
1275
|
+
isSubagent,
|
|
1277
1276
|
});
|
|
1278
1277
|
|
|
1279
1278
|
return {
|
|
@@ -124,8 +124,6 @@ export interface SessionInitEntry extends SessionEntryBase {
|
|
|
124
124
|
task: string;
|
|
125
125
|
/** Tools available to the agent */
|
|
126
126
|
tools: string[];
|
|
127
|
-
/** Output schema if structured output was requested */
|
|
128
|
-
outputSchema?: unknown;
|
|
129
127
|
}
|
|
130
128
|
|
|
131
129
|
/** Mode change entry - tracks agent mode transitions. */
|
|
@@ -1685,7 +1683,7 @@ export class SessionManager {
|
|
|
1685
1683
|
}
|
|
1686
1684
|
|
|
1687
1685
|
/** Append session init metadata (for subagent debugging/replay). Returns entry id. */
|
|
1688
|
-
appendSessionInit(init: { systemPrompt: string; task: string; tools: string[]
|
|
1686
|
+
appendSessionInit(init: { systemPrompt: string; task: string; tools: string[] }): string {
|
|
1689
1687
|
const entry: SessionInitEntry = {
|
|
1690
1688
|
type: "session_init",
|
|
1691
1689
|
id: generateId(this.#byId),
|
package/src/task/executor.ts
CHANGED
|
@@ -107,7 +107,7 @@ export interface ExecutorOptions {
|
|
|
107
107
|
id: string;
|
|
108
108
|
modelOverride?: string | string[];
|
|
109
109
|
thinkingLevel?: ThinkingLevel;
|
|
110
|
-
|
|
110
|
+
isSubagent?: boolean;
|
|
111
111
|
enableLsp?: boolean;
|
|
112
112
|
signal?: AbortSignal;
|
|
113
113
|
onProgress?: (progress: AgentProgress) => void;
|
|
@@ -682,7 +682,7 @@ export async function runAgent(options: ExecutorOptions): Promise<SingleResult>
|
|
|
682
682
|
sessionManager,
|
|
683
683
|
hasUI: false,
|
|
684
684
|
spawns: "",
|
|
685
|
-
|
|
685
|
+
isSubagent: true,
|
|
686
686
|
parentTaskPrefix: id,
|
|
687
687
|
enableLsp: lspEnabled,
|
|
688
688
|
skipPythonPreflight,
|
package/src/task/index.ts
CHANGED
|
@@ -93,7 +93,7 @@ export class TaskTool implements AgentTool<TaskSchema, TaskToolDetails, Theme> {
|
|
|
93
93
|
|
|
94
94
|
try {
|
|
95
95
|
await fs.mkdir(effectiveArtifactsDir, { recursive: true });
|
|
96
|
-
const compactContext = this.session.getCompactContext?.();
|
|
96
|
+
const compactContext = this.session.subagentContext?.getCompactContext?.();
|
|
97
97
|
let contextFilePath: string | undefined;
|
|
98
98
|
if (compactContext) {
|
|
99
99
|
contextFilePath = path.join(effectiveArtifactsDir, "context.md");
|
|
@@ -164,7 +164,7 @@ export class TaskTool implements AgentTool<TaskSchema, TaskToolDetails, Theme> {
|
|
|
164
164
|
description: rendered.description,
|
|
165
165
|
index: 0,
|
|
166
166
|
id: uniqueId,
|
|
167
|
-
|
|
167
|
+
isSubagent: true,
|
|
168
168
|
modelOverride,
|
|
169
169
|
sessionFile,
|
|
170
170
|
persistArtifacts: !!artifactsDir,
|
|
@@ -177,10 +177,10 @@ export class TaskTool implements AgentTool<TaskSchema, TaskToolDetails, Theme> {
|
|
|
177
177
|
progressMap.set(0, { ...structuredClone(progress) });
|
|
178
178
|
emitProgress();
|
|
179
179
|
},
|
|
180
|
-
authStorage: this.session.authStorage,
|
|
181
|
-
modelRegistry: this.session.modelRegistry,
|
|
180
|
+
authStorage: this.session.subagentContext?.authStorage,
|
|
181
|
+
modelRegistry: this.session.subagentContext?.modelRegistry,
|
|
182
182
|
settings: this.session.settings,
|
|
183
|
-
mcpManager: this.session.mcpManager,
|
|
183
|
+
mcpManager: this.session.subagentContext?.mcpManager,
|
|
184
184
|
contextFiles,
|
|
185
185
|
skills: resolvedSkills,
|
|
186
186
|
preloadedSkills,
|
package/src/task/types.ts
CHANGED
|
@@ -24,26 +24,13 @@ export const TASK_SUBAGENT_EVENT_CHANNEL = "task:subagent:event";
|
|
|
24
24
|
/** EventBus channel for aggregated subagent progress */
|
|
25
25
|
export const TASK_SUBAGENT_PROGRESS_CHANNEL = "task:subagent:progress";
|
|
26
26
|
|
|
27
|
-
/** Single task item for
|
|
28
|
-
export
|
|
29
|
-
id:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
description: "Short one-liner for UI display only — not seen by the subagent",
|
|
35
|
-
}),
|
|
36
|
-
assignment: Type.String({
|
|
37
|
-
description:
|
|
38
|
-
"Complete per-task instructions the subagent executes. Must follow the Target/Change/Edge Cases/Acceptance structure. Only include per-task deltas — shared background belongs in `context`.",
|
|
39
|
-
}),
|
|
40
|
-
skills: Type.Optional(
|
|
41
|
-
Type.Array(Type.String(), {
|
|
42
|
-
description: "Skill names to preload into the subagent. Use only where it changes correctness.",
|
|
43
|
-
}),
|
|
44
|
-
),
|
|
45
|
-
});
|
|
46
|
-
export type TaskItem = Static<typeof taskItemSchema>;
|
|
27
|
+
/** Single task item for execution */
|
|
28
|
+
export interface TaskItem {
|
|
29
|
+
id: string;
|
|
30
|
+
description: string;
|
|
31
|
+
assignment: string;
|
|
32
|
+
skills?: string[];
|
|
33
|
+
}
|
|
47
34
|
|
|
48
35
|
/** Task schema — single task with optional context */
|
|
49
36
|
export const taskSchema = Type.Object({
|
package/src/tools/index.ts
CHANGED
|
@@ -31,7 +31,6 @@ import { PythonTool } from "./python";
|
|
|
31
31
|
import { ReadTool } from "./read";
|
|
32
32
|
import { ReviewerTool } from "./reviewer-tool";
|
|
33
33
|
import { loadSshTool } from "./ssh";
|
|
34
|
-
import { SubmitResultTool } from "./submit-result";
|
|
35
34
|
import { TodoWriteTool } from "./todo-write";
|
|
36
35
|
import { UndoEditTool } from "./undo-edit";
|
|
37
36
|
import { WriteTool } from "./write";
|
|
@@ -94,7 +93,6 @@ export { OracleTool } from "./oracle";
|
|
|
94
93
|
export { PythonTool, type PythonToolDetails, type PythonToolOptions } from "./python";
|
|
95
94
|
export { ReadTool, type ReadToolDetails, type ReadToolInput } from "./read";
|
|
96
95
|
export { loadSshTool, type SSHToolDetails, SshTool } from "./ssh";
|
|
97
|
-
export { SubmitResultTool } from "./submit-result";
|
|
98
96
|
export { type TodoItem, TodoWriteTool, type TodoWriteToolDetails } from "./todo-write";
|
|
99
97
|
export { UndoEditTool, type UndoEditToolDetails } from "./undo-edit";
|
|
100
98
|
export { WriteTool, type WriteToolDetails, type WriteToolInput } from "./write";
|
|
@@ -108,6 +106,14 @@ export type ContextFileEntry = {
|
|
|
108
106
|
depth?: number;
|
|
109
107
|
};
|
|
110
108
|
|
|
109
|
+
/** Forwarded context for spawning subagent processes */
|
|
110
|
+
export interface SubagentContext {
|
|
111
|
+
authStorage?: import("../session/auth-storage").AuthStorage;
|
|
112
|
+
modelRegistry?: import("../config/model-registry").ModelRegistry;
|
|
113
|
+
mcpManager?: import("../mcp/manager").MCPManager;
|
|
114
|
+
getCompactContext?: () => string;
|
|
115
|
+
}
|
|
116
|
+
|
|
111
117
|
/** Session context for tool factories */
|
|
112
118
|
export interface ToolSession {
|
|
113
119
|
/** Current working directory */
|
|
@@ -128,12 +134,8 @@ export interface ToolSession {
|
|
|
128
134
|
hasEditTool?: boolean;
|
|
129
135
|
/** Event bus for tool/extension communication */
|
|
130
136
|
eventBus?: EventBus;
|
|
131
|
-
/**
|
|
132
|
-
|
|
133
|
-
/** Whether to include the submit_result tool by default */
|
|
134
|
-
requireSubmitResultTool?: boolean;
|
|
135
|
-
/** Task recursion depth (0 = top-level, 1 = first child, etc.) */
|
|
136
|
-
taskDepth?: number;
|
|
137
|
+
/** Whether this session is a subagent (spawned by task tool) */
|
|
138
|
+
isSubagent?: boolean;
|
|
137
139
|
/** Get session file */
|
|
138
140
|
getSessionFile: () => string | null;
|
|
139
141
|
/** Get session ID */
|
|
@@ -148,20 +150,14 @@ export interface ToolSession {
|
|
|
148
150
|
getModelString?: () => string | undefined;
|
|
149
151
|
/** Get the current session model string, regardless of how it was chosen */
|
|
150
152
|
getActiveModelString?: () => string | undefined;
|
|
151
|
-
/**
|
|
152
|
-
|
|
153
|
-
/** Model registry for passing to subagents (avoids re-discovery) */
|
|
154
|
-
modelRegistry?: import("../config/model-registry").ModelRegistry;
|
|
155
|
-
/** MCP manager for proxying MCP calls through parent */
|
|
156
|
-
mcpManager?: import("../mcp/manager").MCPManager;
|
|
153
|
+
/** Context for spawning subagent processes (only used by task/subagent tools) */
|
|
154
|
+
subagentContext?: SubagentContext;
|
|
157
155
|
/** Internal URL router for agent:// and skill:// URLs */
|
|
158
156
|
internalRouter?: InternalUrlRouter;
|
|
159
157
|
/** Agent output manager for unique agent:// IDs across task invocations */
|
|
160
158
|
agentOutputManager?: AgentOutputManager;
|
|
161
159
|
/** Settings instance for passing to subagents */
|
|
162
160
|
settings: Settings;
|
|
163
|
-
/** Get compact conversation context for subagents (excludes tool results, system prompts) */
|
|
164
|
-
getCompactContext?: () => string;
|
|
165
161
|
}
|
|
166
162
|
|
|
167
163
|
type ToolFactory = (session: ToolSession) => Tool | null | Promise<Tool | null>;
|
|
@@ -191,10 +187,6 @@ export const BUILTIN_TOOLS: Record<string, ToolFactory> = {
|
|
|
191
187
|
write: s => new WriteTool(s),
|
|
192
188
|
};
|
|
193
189
|
|
|
194
|
-
export const HIDDEN_TOOLS: Record<string, ToolFactory> = {
|
|
195
|
-
submit_result: s => new SubmitResultTool(s),
|
|
196
|
-
};
|
|
197
|
-
|
|
198
190
|
export type ToolName = keyof typeof BUILTIN_TOOLS;
|
|
199
191
|
|
|
200
192
|
export type PythonToolMode = "ipy-only" | "bash-only" | "both";
|
|
@@ -232,7 +224,6 @@ function getPythonModeFromEnv(): PythonToolMode | null {
|
|
|
232
224
|
*/
|
|
233
225
|
export async function createTools(session: ToolSession, toolNames?: string[]): Promise<Tool[]> {
|
|
234
226
|
time("createTools:start");
|
|
235
|
-
const includeSubmitResult = session.requireSubmitResultTool === true;
|
|
236
227
|
const enableLsp = session.enableLsp ?? true;
|
|
237
228
|
const requestedTools = toolNames && toolNames.length > 0 ? [...new Set(toolNames)] : undefined;
|
|
238
229
|
const pythonMode = getPythonModeFromEnv() ?? session.settings.get("python.toolMode");
|
|
@@ -278,12 +269,12 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
|
|
|
278
269
|
) {
|
|
279
270
|
requestedTools.push("bash");
|
|
280
271
|
}
|
|
281
|
-
const allTools: Record<string, ToolFactory> = { ...BUILTIN_TOOLS
|
|
272
|
+
const allTools: Record<string, ToolFactory> = { ...BUILTIN_TOOLS };
|
|
282
273
|
const isToolAllowed = (name: string) => {
|
|
283
274
|
if (name === "lsp") return enableLsp;
|
|
284
275
|
if (name === "bash") return allowBash;
|
|
285
276
|
if (name === "python") return allowPython;
|
|
286
|
-
if (name === "todo_write") return
|
|
277
|
+
if (name === "todo_write") return session.settings.get("todo.enabled");
|
|
287
278
|
if (name === "find") return session.settings.get("find.enabled");
|
|
288
279
|
if (name === "grep") return session.settings.get("grep.enabled");
|
|
289
280
|
if (name === "notebook") return session.settings.get("notebook.enabled");
|
|
@@ -295,25 +286,17 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
|
|
|
295
286
|
if (name === "librarian") return session.settings.get("librarian.enabled");
|
|
296
287
|
if (name === "oracle") return session.settings.get("oracle.enabled");
|
|
297
288
|
if (name === "task") {
|
|
298
|
-
|
|
299
|
-
const currentDepth = session.taskDepth ?? 0;
|
|
300
|
-
return maxDepth < 0 || currentDepth < maxDepth;
|
|
289
|
+
return !session.isSubagent;
|
|
301
290
|
}
|
|
302
291
|
return true;
|
|
303
292
|
};
|
|
304
|
-
if (includeSubmitResult && requestedTools && !requestedTools.includes("submit_result")) {
|
|
305
|
-
requestedTools.push("submit_result");
|
|
306
|
-
}
|
|
307
293
|
|
|
308
294
|
const filteredRequestedTools = requestedTools?.filter(name => name in allTools && isToolAllowed(name));
|
|
309
295
|
|
|
310
296
|
const entries =
|
|
311
297
|
filteredRequestedTools !== undefined
|
|
312
298
|
? filteredRequestedTools.map(name => [name, allTools[name]] as const)
|
|
313
|
-
: [
|
|
314
|
-
...Object.entries(BUILTIN_TOOLS).filter(([name]) => isToolAllowed(name)),
|
|
315
|
-
...(includeSubmitResult ? ([["submit_result", HIDDEN_TOOLS.submit_result]] as const) : []),
|
|
316
|
-
];
|
|
299
|
+
: [...Object.entries(BUILTIN_TOOLS).filter(([name]) => isToolAllowed(name))];
|
|
317
300
|
|
|
318
301
|
const results = await Promise.all(
|
|
319
302
|
entries.map(async ([name, factory]) => {
|