@nyxa/nyx-agent 0.4.1 → 0.6.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/README.md +58 -9
- package/dist/cli.js +13 -16
- package/dist/commands/init.js +112 -462
- package/dist/commands/run.js +17 -3
- package/dist/commands/update.js +1 -0
- package/dist/config/loadConfig.js +17 -3
- package/dist/config/schema.js +29 -146
- package/dist/runtime/files.js +1 -0
- package/dist/runtime/git.js +1 -0
- package/dist/runtime/gitLifecycle.js +19 -57
- package/dist/runtime/harness.js +26 -0
- package/dist/runtime/ledger.js +1 -0
- package/dist/runtime/paths.js +1 -12
- package/dist/runtime/prompts.js +103 -0
- package/dist/runtime/runPhase.js +85 -254
- package/dist/runtime/runPipeline.js +479 -0
- package/dist/runtime/schemas.js +52 -0
- package/dist/runtime/scm.js +80 -0
- package/dist/runtime/time.js +1 -0
- package/dist/runtime/validateResult.js +2 -3
- package/dist/runtime/workItems.js +43 -118
- package/package.json +2 -5
- package/dist/runtime/buildPrompt.js +0 -54
- package/dist/runtime/effectiveConfig.js +0 -14
- package/dist/runtime/renderTemplate.js +0 -28
- package/dist/runtime/runWorkflow.js +0 -680
- package/dist/runtime/validateWorkItem.js +0 -212
- package/dist/runtime/workItemAnnotations.js +0 -39
- package/docs/nyxagent-v0-spec.md +0 -742
- package/templates/default/prompts/closure.md +0 -30
- package/templates/default/prompts/execution.md +0 -11
- package/templates/default/prompts/finalize.md +0 -7
- package/templates/default/prompts/global-review.md +0 -24
- package/templates/default/prompts/global-revision.md +0 -9
- package/templates/default/prompts/pull-request.md +0 -23
- package/templates/default/prompts/repair-result.md +0 -29
- package/templates/default/prompts/review.md +0 -18
- package/templates/default/prompts/revision.md +0 -7
- package/templates/default/prompts/selection.md +0 -46
- package/templates/default/schemas/closure.schema.json +0 -35
- package/templates/default/schemas/global-review.schema.json +0 -60
- package/templates/default/schemas/pull-request.schema.json +0 -44
- package/templates/default/schemas/review.schema.json +0 -60
- package/templates/default/schemas/selection.schema.json +0 -135
package/docs/nyxagent-v0-spec.md
DELETED
|
@@ -1,742 +0,0 @@
|
|
|
1
|
-
# NyxAgent v0 Spec
|
|
2
|
-
|
|
3
|
-
## Purpose
|
|
4
|
-
|
|
5
|
-
NyxAgent is a lightweight orchestration CLI for repeatedly launching coding
|
|
6
|
-
agents against work items without carrying long-lived agent context across
|
|
7
|
-
tasks or phases.
|
|
8
|
-
|
|
9
|
-
The tool is primarily built for personal use, but the v0 architecture should be
|
|
10
|
-
simple, explicit, and configurable enough for other repositories and harnesses.
|
|
11
|
-
|
|
12
|
-
NyxAgent is an orchestrator. It does not own project-specific development,
|
|
13
|
-
review, tracking, or closure policy. Those policies live in prompts and project
|
|
14
|
-
configuration.
|
|
15
|
-
|
|
16
|
-
## Goals
|
|
17
|
-
|
|
18
|
-
- Install a `.nyxagent/` folder into a project with sensible templates.
|
|
19
|
-
- Select an ordered work-item queue once, then run a configurable phase workflow
|
|
20
|
-
for up to `max_iterations` confirmed work items.
|
|
21
|
-
- Launch a fresh harness process for each phase.
|
|
22
|
-
- Keep workflow structure generic through phase transitions and outcomes.
|
|
23
|
-
- Keep prompts focused on agent behavior, not runtime mechanics.
|
|
24
|
-
- Capture complete run artifacts for audit and debugging.
|
|
25
|
-
- Support Codex and Claude-style harnesses through configurable commands.
|
|
26
|
-
- Support structured phase results through a common XML result contract.
|
|
27
|
-
|
|
28
|
-
## Non-Goals For v0
|
|
29
|
-
|
|
30
|
-
- No native classification of work items as plans, PRDs, or tasks.
|
|
31
|
-
- No native Git commit or issue close logic in the engine.
|
|
32
|
-
- No resume command.
|
|
33
|
-
- No fully general DAG/workflow engine.
|
|
34
|
-
- No local `loop.ts` copied into `.nyxagent/`.
|
|
35
|
-
- No automatic mutation of work item files by the engine.
|
|
36
|
-
|
|
37
|
-
## CLI
|
|
38
|
-
|
|
39
|
-
Package and binary naming:
|
|
40
|
-
|
|
41
|
-
- npm package: `nyx-agent` or `@nyxa/nyx-agent`
|
|
42
|
-
- CLI binary: `nyxagent`
|
|
43
|
-
- project directory: `.nyxagent`
|
|
44
|
-
|
|
45
|
-
Initial commands:
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
nyxagent init
|
|
49
|
-
nyxagent init --missing
|
|
50
|
-
nyxagent run
|
|
51
|
-
nyxagent update
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
`nyxagent init` is interactive by default and scriptable through flags.
|
|
55
|
-
|
|
56
|
-
`nyxagent update [version]` self-updates the global install. It resolves the
|
|
57
|
-
target from the npm registry (`latest` by default, or an explicit version /
|
|
58
|
-
dist-tag), guards against accidental downgrades when following a moving tag, and
|
|
59
|
-
reinstalls globally with the detected package manager (npm/pnpm/yarn/bun,
|
|
60
|
-
overridable with `--package-manager`). Use `--check` to report without
|
|
61
|
-
installing and `-y`/`--yes` to skip the confirmation prompt.
|
|
62
|
-
|
|
63
|
-
If `.nyxagent/` already exists:
|
|
64
|
-
|
|
65
|
-
- default behavior: refuse and explain
|
|
66
|
-
- `--missing`: add only missing template files
|
|
67
|
-
- no `--force` in v0
|
|
68
|
-
|
|
69
|
-
## Installed Project Layout
|
|
70
|
-
|
|
71
|
-
```text
|
|
72
|
-
.nyxagent/
|
|
73
|
-
config.toml
|
|
74
|
-
state.json
|
|
75
|
-
prompts/
|
|
76
|
-
selection.md
|
|
77
|
-
execution.md
|
|
78
|
-
review.md
|
|
79
|
-
revision.md
|
|
80
|
-
closure.md
|
|
81
|
-
pull-request.md
|
|
82
|
-
repair-result.md
|
|
83
|
-
schemas/
|
|
84
|
-
selection.schema.json
|
|
85
|
-
review.schema.json
|
|
86
|
-
closure.schema.json
|
|
87
|
-
pull-request.schema.json
|
|
88
|
-
runs/
|
|
89
|
-
worktrees/ # created when [git].mode = "worktree"
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
Configuration, prompts, schemas, and run artifacts are kept under
|
|
93
|
-
`.nyxagent/`.
|
|
94
|
-
|
|
95
|
-
Work items may live outside `.nyxagent/` when configured through
|
|
96
|
-
`[work_items]`.
|
|
97
|
-
|
|
98
|
-
## Configuration
|
|
99
|
-
|
|
100
|
-
Primary config format: TOML.
|
|
101
|
-
|
|
102
|
-
Secrets are not stored in `config.toml`. v0 does not require `.env`.
|
|
103
|
-
|
|
104
|
-
Example:
|
|
105
|
-
|
|
106
|
-
```toml
|
|
107
|
-
[workflow]
|
|
108
|
-
entry_phase = "selection"
|
|
109
|
-
max_iterations = 5
|
|
110
|
-
|
|
111
|
-
[model]
|
|
112
|
-
name = "gpt-5.5"
|
|
113
|
-
reasoning_level = "medium"
|
|
114
|
-
|
|
115
|
-
[harness]
|
|
116
|
-
preset = "codex"
|
|
117
|
-
command = "codex"
|
|
118
|
-
args = [
|
|
119
|
-
"exec",
|
|
120
|
-
"--model", "{{model.name}}",
|
|
121
|
-
"-c", "model_reasoning_effort=\"{{model.reasoning_level}}\"",
|
|
122
|
-
"-"
|
|
123
|
-
]
|
|
124
|
-
prompt_input = "stdin"
|
|
125
|
-
|
|
126
|
-
[repair]
|
|
127
|
-
max_attempts = 1
|
|
128
|
-
prompt = "prompts/repair-result.md"
|
|
129
|
-
|
|
130
|
-
[work_items]
|
|
131
|
-
source = "local"
|
|
132
|
-
path = "issues"
|
|
133
|
-
max_candidates = 50
|
|
134
|
-
excerpt_chars = 800
|
|
135
|
-
|
|
136
|
-
[[phases]]
|
|
137
|
-
id = "selection"
|
|
138
|
-
prompt = "prompts/selection.md"
|
|
139
|
-
output_schema = "schemas/selection.schema.json"
|
|
140
|
-
required_output = true
|
|
141
|
-
max_visits_per_iteration = 1
|
|
142
|
-
|
|
143
|
-
[phases.transitions]
|
|
144
|
-
selected = "execution"
|
|
145
|
-
no_work = "stop_run"
|
|
146
|
-
|
|
147
|
-
[[phases]]
|
|
148
|
-
id = "execution"
|
|
149
|
-
prompt = "prompts/execution.md"
|
|
150
|
-
next = "review"
|
|
151
|
-
max_visits_per_iteration = 3
|
|
152
|
-
|
|
153
|
-
[[phases]]
|
|
154
|
-
id = "review"
|
|
155
|
-
prompt = "prompts/review.md"
|
|
156
|
-
output_schema = "schemas/review.schema.json"
|
|
157
|
-
required_output = true
|
|
158
|
-
max_visits_per_iteration = 3
|
|
159
|
-
|
|
160
|
-
[phases.harness]
|
|
161
|
-
args = [
|
|
162
|
-
"exec",
|
|
163
|
-
"--model", "{{model.name}}",
|
|
164
|
-
"-c", "model_reasoning_effort=\"{{model.reasoning_level}}\"",
|
|
165
|
-
"--sandbox", "read-only",
|
|
166
|
-
"-"
|
|
167
|
-
]
|
|
168
|
-
|
|
169
|
-
[phases.transitions]
|
|
170
|
-
approved = "closure"
|
|
171
|
-
changes_requested = "execution"
|
|
172
|
-
|
|
173
|
-
[[phases]]
|
|
174
|
-
id = "closure"
|
|
175
|
-
prompt = "prompts/closure.md"
|
|
176
|
-
output_schema = "schemas/closure.schema.json"
|
|
177
|
-
required_output = true
|
|
178
|
-
max_visits_per_iteration = 1
|
|
179
|
-
|
|
180
|
-
[phases.harness]
|
|
181
|
-
args = [
|
|
182
|
-
"exec",
|
|
183
|
-
"--model", "{{model.name}}",
|
|
184
|
-
"-c", "model_reasoning_effort=\"{{model.reasoning_level}}\"",
|
|
185
|
-
"-c", "sandbox_workspace_write.network_access=true",
|
|
186
|
-
"-"
|
|
187
|
-
]
|
|
188
|
-
|
|
189
|
-
[phases.transitions]
|
|
190
|
-
closed = "next_iteration"
|
|
191
|
-
failed = "stop_run"
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
For GitHub sources, init also adds `workflow.final_phase = "pull_request"`, a
|
|
195
|
-
`[git]` block, and a `pull_request` phase (see "Git Lifecycle and the PRD Pull
|
|
196
|
-
Request").
|
|
197
|
-
|
|
198
|
-
### Config Semantics
|
|
199
|
-
|
|
200
|
-
- `workflow.max_iterations` is the maximum number of distinct confirmed work
|
|
201
|
-
items in a run.
|
|
202
|
-
- `phases[*].max_visits_per_iteration` prevents infinite loops inside one work
|
|
203
|
-
item.
|
|
204
|
-
- `model.reasoning_level` is a harness-neutral string.
|
|
205
|
-
- Harness args are declarative and may interpolate config/runtime variables.
|
|
206
|
-
- Per-phase `model` and `harness` blocks override global values when explicitly
|
|
207
|
-
declared.
|
|
208
|
-
- The initial selection phase is declared in `[[phases]]`, but the runtime treats
|
|
209
|
-
`workflow.entry_phase` as the selection step and expects the selection result
|
|
210
|
-
contract.
|
|
211
|
-
- `work_items` supports only `local` and `github` in v0.
|
|
212
|
-
- `work_items.max_candidates` defaults to `50` and caps the inventory sent to
|
|
213
|
-
the initial selection prompt.
|
|
214
|
-
- `work_items.excerpt_chars` defaults to `800` and bounds candidate excerpts.
|
|
215
|
-
- `workflow.final_phase` (optional) names the **entry phase of a finalization
|
|
216
|
-
flow** the engine runs after the iteration loop completes normally. It is
|
|
217
|
-
symmetric to `entry_phase`: the engine starts at `final_phase` and follows each
|
|
218
|
-
phase's `next`/`transitions` until it reaches a leaf phase (no `next`/no
|
|
219
|
-
`transitions`, which ends finalization successfully) or `stop_run` (which aborts
|
|
220
|
-
the run, keeping the worktree for debugging). This lets the finalization be more
|
|
221
|
-
than one step — e.g. `review` → (`changes_requested`) `revision` → back to
|
|
222
|
-
`review` → (`approved`) terminal `pull_request`/`closure`. Review/revision loops
|
|
223
|
-
are bounded by each phase's `max_visits_per_iteration`. A single leaf phase (the
|
|
224
|
-
default `pull_request`) simply runs once, unchanged. The flow receives run-level
|
|
225
|
-
state (the completed work items, the run branch); `runState.final_result` holds
|
|
226
|
-
the last phase's structured result. `next_iteration`/`stop_iteration` are
|
|
227
|
-
iteration-only targets and are rejected inside the finalization flow. If unset,
|
|
228
|
-
nothing runs after the loop.
|
|
229
|
-
- `[git]` (optional) drives the engine's generic git lifecycle. `mode` is `off`
|
|
230
|
-
(default, unchanged behavior), `branch` (a new branch checked out in place), or
|
|
231
|
-
`worktree` (an isolated worktree per run). `base` defaults to the current
|
|
232
|
-
branch. `branch_template` interpolates `{{run_id}}`. `worktree_dir` is the
|
|
233
|
-
gitignored parent of run worktrees. `cleanup` is `always`, `on_success`
|
|
234
|
-
(default, kept on failure for debugging), or `never`. The branch is always
|
|
235
|
-
kept; only the worktree directory is removed.
|
|
236
|
-
- At run start, the engine scans the configured provider, normalizes candidates
|
|
237
|
-
into `available_work_items`, and sends that inventory to the selection phase.
|
|
238
|
-
- The selection phase returns an ordered recommended `work_items` queue.
|
|
239
|
-
NyxAgent validates each recommended identity against `[work_items]`, rejects
|
|
240
|
-
duplicates, and requires every selected key to exist in
|
|
241
|
-
`available_work_items`.
|
|
242
|
-
- Before executing, NyxAgent shows the full `available_work_items` inventory in
|
|
243
|
-
an interactive checkbox prompt. The recommended queue is pre-checked, and the
|
|
244
|
-
user can add or remove available items. Only confirmed items are executed.
|
|
245
|
-
- The selection phase may return optional `work_item_annotations` for display.
|
|
246
|
-
Supported kinds are `task`, `plan`, `prd`, and `work`. Unknown or missing
|
|
247
|
-
kinds are shown as `work`; annotations never affect work item identity or
|
|
248
|
-
ledger completion.
|
|
249
|
-
- Local markdown work items do not have a required frontmatter schema. The
|
|
250
|
-
provider infers titles from the first heading or filename and includes a
|
|
251
|
-
bounded content excerpt.
|
|
252
|
-
- Local keys use `local:<relative-path-under-work-items-path>`.
|
|
253
|
-
- GitHub keys use `github:<owner>/<repo>#<issue-number>` and must match the
|
|
254
|
-
configured repository.
|
|
255
|
-
- NyxAgent does not decide whether an item is a plan, PRD, or task. The
|
|
256
|
-
selection agent makes that semantic choice from the deterministic inventory
|
|
257
|
-
and may include optional `selection_groups` for user review. Groups may cover
|
|
258
|
-
the full available inventory, not only the recommended queue.
|
|
259
|
-
|
|
260
|
-
### Phase Capabilities (network and permissions)
|
|
261
|
-
|
|
262
|
-
The engine stays agnostic: it only runs `command + args` per phase. The
|
|
263
|
-
capability of each phase — read-only, write, or write-with-network — is encoded
|
|
264
|
-
in the harness args that `nyxagent init` generates per preset:
|
|
265
|
-
|
|
266
|
-
| Capability | Phases | Codex args | Claude args |
|
|
267
|
-
| --- | --- | --- | --- |
|
|
268
|
-
| read-only | selection, review, global_review, finalize | `--sandbox read-only` | `-p --permission-mode plan` |
|
|
269
|
-
| write | execution, revision, global_revision | workspace-write (no extra flag) | `-p --dangerously-skip-permissions` |
|
|
270
|
-
| write + network | closure, pull_request | `-c sandbox_workspace_write.network_access=true` | `-p --dangerously-skip-permissions` |
|
|
271
|
-
|
|
272
|
-
Why the network capability matters: codex's default `workspace-write` sandbox
|
|
273
|
-
keeps outbound network **off**. A `git commit` is local and succeeds, but
|
|
274
|
-
`gh issue close` is a GitHub API call and fails silently. That is why issues
|
|
275
|
-
were committed but never closed. The `write_network` capability re-enables the
|
|
276
|
-
network only for the phases that need it (closure, pull request). Claude has no
|
|
277
|
-
network sandbox; its blocker was the missing `-p` (headless) and permission
|
|
278
|
-
flags, which `write`/`write_network` now provide.
|
|
279
|
-
|
|
280
|
-
Users can adjust any phase's posture by editing its `[phases.harness] args`.
|
|
281
|
-
|
|
282
|
-
### Git Lifecycle and the PRD Pull Request
|
|
283
|
-
|
|
284
|
-
When `[git].mode` is `worktree` (the default for GitHub init), the engine, once
|
|
285
|
-
per run:
|
|
286
|
-
|
|
287
|
-
1. creates one branch for the whole run (the PRD) from `base`, in an isolated
|
|
288
|
-
worktree under `worktree_dir`;
|
|
289
|
-
2. runs every iteration (execution → review → revision → closure) with the
|
|
290
|
-
harness `cwd` set to that worktree, while `.nyxagent` artifacts stay under the
|
|
291
|
-
project root;
|
|
292
|
-
3. after the loop, runs the `workflow.final_phase` finalization flow in the
|
|
293
|
-
worktree (a single `pull_request` phase by default, or a multi-step flow such
|
|
294
|
-
as the generated global review: `global_review` → (`changes_requested`)
|
|
295
|
-
`global_revision` → back to `global_review` → (`approved`) `pull_request`) to
|
|
296
|
-
push the branch and open a single pull request;
|
|
297
|
-
4. removes the worktree per `cleanup`, keeping the branch.
|
|
298
|
-
|
|
299
|
-
Per-work-item closure still closes each GitHub issue (`gh issue close`). The
|
|
300
|
-
pull request is the PRD-level deliverable; it is opened once, at the end, and is
|
|
301
|
-
GitHub-specific. The engine performs only generic git plumbing (branch, worktree,
|
|
302
|
-
cwd); all GitHub semantics live in the `closure.md` and `pull-request.md`
|
|
303
|
-
prompts, so the engine stays harness- and tracker-agnostic.
|
|
304
|
-
|
|
305
|
-
## Workflow Model
|
|
306
|
-
|
|
307
|
-
The workflow is phase based.
|
|
308
|
-
|
|
309
|
-
Each phase has either:
|
|
310
|
-
|
|
311
|
-
- `next`: a static next target
|
|
312
|
-
- `transitions`: a map from result `outcome` to next target
|
|
313
|
-
|
|
314
|
-
Reserved next targets:
|
|
315
|
-
|
|
316
|
-
- `stop_run`
|
|
317
|
-
- `stop_iteration`
|
|
318
|
-
- `next_iteration`
|
|
319
|
-
|
|
320
|
-
The engine does not know about development, review, approval, or closure. It
|
|
321
|
-
only knows phases, outcomes, transitions, and visit limits.
|
|
322
|
-
|
|
323
|
-
The default template expresses the standard run:
|
|
324
|
-
|
|
325
|
-
```text
|
|
326
|
-
selection -> user confirms inventory with recommended queue pre-checked
|
|
327
|
-
for each confirmed work item:
|
|
328
|
-
execution -> review
|
|
329
|
-
review.approved -> closure -> next_iteration
|
|
330
|
-
review.changes_requested -> execution
|
|
331
|
-
selection.no_work -> stop_run
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
## Structured Result Contract
|
|
335
|
-
|
|
336
|
-
Agents do not write result JSON files directly.
|
|
337
|
-
|
|
338
|
-
When a phase requires structured output, the harness must return a JSON object
|
|
339
|
-
inside the last `<nyxagent_result>` XML block in stdout:
|
|
340
|
-
|
|
341
|
-
```xml
|
|
342
|
-
<nyxagent_result>
|
|
343
|
-
{
|
|
344
|
-
"outcome": "approved",
|
|
345
|
-
"approved": true,
|
|
346
|
-
"summary": "Implementation matches the task and tests pass."
|
|
347
|
-
}
|
|
348
|
-
</nyxagent_result>
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
Engine behavior:
|
|
352
|
-
|
|
353
|
-
1. Capture stdout and stderr.
|
|
354
|
-
2. Extract the last `<nyxagent_result>...</nyxagent_result>` block.
|
|
355
|
-
3. Parse the block as JSON.
|
|
356
|
-
4. Validate it against `output_schema` when configured.
|
|
357
|
-
5. Write the validated object to `result.json`.
|
|
358
|
-
6. Merge relevant result data into iteration state.
|
|
359
|
-
|
|
360
|
-
If a phase declares `transitions`, its structured result must contain
|
|
361
|
-
`outcome`.
|
|
362
|
-
|
|
363
|
-
If multiple result blocks exist, the last block wins.
|
|
364
|
-
|
|
365
|
-
## Repair
|
|
366
|
-
|
|
367
|
-
Repair is only for malformed structured results.
|
|
368
|
-
|
|
369
|
-
If the harness exits with code `0` but the result block is missing, invalid
|
|
370
|
-
JSON, or schema-invalid, NyxAgent launches a repair phase.
|
|
371
|
-
|
|
372
|
-
The repair prompt receives:
|
|
373
|
-
|
|
374
|
-
- rendered original prompt
|
|
375
|
-
- stdout and stderr from the failed attempt
|
|
376
|
-
- expected schema
|
|
377
|
-
- validation or parsing error
|
|
378
|
-
|
|
379
|
-
The repair agent must return only a valid `<nyxagent_result>` block. It must not
|
|
380
|
-
redo the development or mutate the project.
|
|
381
|
-
|
|
382
|
-
If the harness exits non-zero, this is a phase failure, not a result repair.
|
|
383
|
-
Phase retry behavior can be added later.
|
|
384
|
-
|
|
385
|
-
## Runtime Prompt
|
|
386
|
-
|
|
387
|
-
NyxAgent renders a final prompt for each phase by prepending a runtime contract
|
|
388
|
-
to the user prompt.
|
|
389
|
-
|
|
390
|
-
The runtime contract includes:
|
|
391
|
-
|
|
392
|
-
- project root
|
|
393
|
-
- run directory
|
|
394
|
-
- iteration directory
|
|
395
|
-
- phase directory
|
|
396
|
-
- current state file
|
|
397
|
-
- phase id
|
|
398
|
-
- configured transitions
|
|
399
|
-
- required structured output contract
|
|
400
|
-
- work item context, when selected
|
|
401
|
-
- work item config from `[work_items]`
|
|
402
|
-
- `available_work_items`
|
|
403
|
-
- `recommended_work_item_queue`
|
|
404
|
-
- `selected_work_item_queue`
|
|
405
|
-
- `work_item_annotations`
|
|
406
|
-
- `seen_work_item_keys`
|
|
407
|
-
- `completed_work_item_keys`
|
|
408
|
-
- `last_completed_work_item`
|
|
409
|
-
|
|
410
|
-
The user prompt remains focused on domain behavior.
|
|
411
|
-
|
|
412
|
-
Prompts may use simple interpolation:
|
|
413
|
-
|
|
414
|
-
```text
|
|
415
|
-
{{project_root}}
|
|
416
|
-
{{run_dir}}
|
|
417
|
-
{{iteration_dir}}
|
|
418
|
-
{{phase_dir}}
|
|
419
|
-
{{state_file}}
|
|
420
|
-
{{recommended_work_item_queue}}
|
|
421
|
-
{{selected_work_item_queue}}
|
|
422
|
-
{{work_item_annotations}}
|
|
423
|
-
{{work_item.key}}
|
|
424
|
-
{{work_item.title}}
|
|
425
|
-
{{model.name}}
|
|
426
|
-
{{model.reasoning_level}}
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
The template language is intentionally small: dotted path lookup only.
|
|
430
|
-
|
|
431
|
-
## Artifacts
|
|
432
|
-
|
|
433
|
-
Each run creates a timestamped directory:
|
|
434
|
-
|
|
435
|
-
```text
|
|
436
|
-
.nyxagent/runs/2026-05-23T12-30-00/
|
|
437
|
-
run.json
|
|
438
|
-
state.json
|
|
439
|
-
selection/
|
|
440
|
-
state.json
|
|
441
|
-
phases/
|
|
442
|
-
selection/
|
|
443
|
-
attempt-001/
|
|
444
|
-
prompt.md
|
|
445
|
-
stdout.log
|
|
446
|
-
stderr.log
|
|
447
|
-
meta.json
|
|
448
|
-
result.json
|
|
449
|
-
iterations/
|
|
450
|
-
001/
|
|
451
|
-
state.json
|
|
452
|
-
phases/
|
|
453
|
-
execution/
|
|
454
|
-
attempt-001/
|
|
455
|
-
prompt.md
|
|
456
|
-
stdout.log
|
|
457
|
-
stderr.log
|
|
458
|
-
meta.json
|
|
459
|
-
result.json
|
|
460
|
-
review/
|
|
461
|
-
attempt-001/
|
|
462
|
-
prompt.md
|
|
463
|
-
stdout.log
|
|
464
|
-
stderr.log
|
|
465
|
-
meta.json
|
|
466
|
-
repair-001/
|
|
467
|
-
prompt.md
|
|
468
|
-
stdout.log
|
|
469
|
-
stderr.log
|
|
470
|
-
meta.json
|
|
471
|
-
result.json
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
`run.json` records immutable run metadata:
|
|
475
|
-
|
|
476
|
-
- run id
|
|
477
|
-
- project root
|
|
478
|
-
- started at
|
|
479
|
-
- config path
|
|
480
|
-
- harness preset and command
|
|
481
|
-
- initial Git snapshot when available
|
|
482
|
-
|
|
483
|
-
`run/state.json` records global current state:
|
|
484
|
-
|
|
485
|
-
- run status
|
|
486
|
-
- current iteration
|
|
487
|
-
- completed iterations
|
|
488
|
-
- available work items seen by the initial selection phase
|
|
489
|
-
- recommended work item queue returned by the selection agent
|
|
490
|
-
- selected work item queue confirmed for the run
|
|
491
|
-
- work item annotations returned by the selection agent
|
|
492
|
-
- skipped recommended work item keys
|
|
493
|
-
- selection groups returned for user review
|
|
494
|
-
- seen work item keys
|
|
495
|
-
- completed work item keys
|
|
496
|
-
- last completed work item
|
|
497
|
-
|
|
498
|
-
`.nyxagent/state.json` records persistent work item completion state:
|
|
499
|
-
|
|
500
|
-
- completed work item keys
|
|
501
|
-
- last completed work item
|
|
502
|
-
- minimal completion history
|
|
503
|
-
|
|
504
|
-
`iterations/NNN/state.json` records per-work-item state:
|
|
505
|
-
|
|
506
|
-
- iteration number
|
|
507
|
-
- work item
|
|
508
|
-
- selected work item queue for the run
|
|
509
|
-
- seen work item keys
|
|
510
|
-
- completed work item keys
|
|
511
|
-
- last completed work item
|
|
512
|
-
- phase results
|
|
513
|
-
- phase visit counts
|
|
514
|
-
- current phase status
|
|
515
|
-
|
|
516
|
-
`meta.json` for each attempt records:
|
|
517
|
-
|
|
518
|
-
- rendered command with secrets redacted
|
|
519
|
-
- start and end timestamps
|
|
520
|
-
- duration
|
|
521
|
-
- exit code
|
|
522
|
-
- parse/schema errors when present
|
|
523
|
-
- Git status before and after phase when available
|
|
524
|
-
|
|
525
|
-
## Git Behavior
|
|
526
|
-
|
|
527
|
-
NyxAgent does not require a clean worktree in v0.
|
|
528
|
-
|
|
529
|
-
At run start, if the project is a Git repository, the engine records:
|
|
530
|
-
|
|
531
|
-
- branch
|
|
532
|
-
- HEAD commit
|
|
533
|
-
- `git status --short`
|
|
534
|
-
|
|
535
|
-
The engine does not commit. The default workflow reserves commits for the
|
|
536
|
-
`closure` prompt after review approval.
|
|
537
|
-
|
|
538
|
-
When `[git].mode` is `branch` or `worktree`, the engine additionally manages a
|
|
539
|
-
run-scoped branch (and, for `worktree`, an isolated working directory) as
|
|
540
|
-
described under "Git Lifecycle and the PRD Pull Request". This is opt-in and off
|
|
541
|
-
by default; it performs only generic git plumbing, never GitHub actions.
|
|
542
|
-
|
|
543
|
-
Default phase policy:
|
|
544
|
-
|
|
545
|
-
- `selection`: read-only behavior by prompt/harness
|
|
546
|
-
- `execution`: may modify code and run tests, must not commit or close work
|
|
547
|
-
items
|
|
548
|
-
- `review`: read-only behavior by prompt/harness
|
|
549
|
-
- `closure`: may commit and close or mark done according to project prompt;
|
|
550
|
-
runs with the network capability so `gh issue close` works
|
|
551
|
-
- `pull_request` (final phase, GitHub PRD only): pushes the run branch and opens
|
|
552
|
-
one pull request; runs with the network capability
|
|
553
|
-
|
|
554
|
-
## Default Prompt Policy
|
|
555
|
-
|
|
556
|
-
Default prompts should be concise but operational.
|
|
557
|
-
|
|
558
|
-
Selection:
|
|
559
|
-
|
|
560
|
-
- recommend an ordered queue from `available_work_items`
|
|
561
|
-
- treat candidates agnostically: they may be plans, PRDs, or tasks
|
|
562
|
-
- prefer the most actionable items based on candidate titles and excerpts
|
|
563
|
-
- if a plan references concrete candidate tasks, choose the concrete task when
|
|
564
|
-
that is the best next work
|
|
565
|
-
- avoid keys already present in `seen_work_item_keys` or
|
|
566
|
-
`completed_work_item_keys`
|
|
567
|
-
- optionally include `selection_groups` to present related work by the most
|
|
568
|
-
useful grouping the agent can infer
|
|
569
|
-
- optionally include `work_item_annotations` with display kinds `task`, `plan`,
|
|
570
|
-
`prd`, or `work`
|
|
571
|
-
- return `selected` or `no_work`
|
|
572
|
-
|
|
573
|
-
Execution:
|
|
574
|
-
|
|
575
|
-
- work only on the selected item
|
|
576
|
-
- use a red-green-refactor style when practical
|
|
577
|
-
- run targeted validation
|
|
578
|
-
- do not commit
|
|
579
|
-
- do not close the work item
|
|
580
|
-
|
|
581
|
-
Review:
|
|
582
|
-
|
|
583
|
-
- stay read-only
|
|
584
|
-
- check alignment with selected work item
|
|
585
|
-
- check tests and validation evidence
|
|
586
|
-
- check architecture/design fit
|
|
587
|
-
- check obvious security or data safety concerns
|
|
588
|
-
- return `approved` or `changes_requested`
|
|
589
|
-
|
|
590
|
-
Closure:
|
|
591
|
-
|
|
592
|
-
- run only after approval
|
|
593
|
-
- inspect final diff/status
|
|
594
|
-
- commit when appropriate
|
|
595
|
-
- close or mark done according to work item source and project conventions
|
|
596
|
-
- for GitHub, close the issue explicitly with `gh issue close <number> --repo
|
|
597
|
-
<owner/repo>` (needs the network capability)
|
|
598
|
-
- return a structured `closed` / `failed` outcome so a failed close stops the run
|
|
599
|
-
instead of silently marking the item done
|
|
600
|
-
|
|
601
|
-
Pull request (final phase, GitHub PRD only):
|
|
602
|
-
|
|
603
|
-
- run once after the iteration loop, on the run branch in the worktree
|
|
604
|
-
- push the branch and open one pull request referencing the addressed issues
|
|
605
|
-
- return `pr_opened` with `pr_url`, or `failed` with what remains
|
|
606
|
-
|
|
607
|
-
Global review (finalization, optional):
|
|
608
|
-
|
|
609
|
-
- stay read-only; review the whole run/PRD, not a single item
|
|
610
|
-
- focus on cross-cutting concerns a per-task review cannot see (integration,
|
|
611
|
-
regressions between items, overall design, gaps vs intent)
|
|
612
|
-
- inspect the combined diff (`git diff {{git.base}}...HEAD` when a branch exists)
|
|
613
|
-
- return `approved` or `changes_requested` (with `required_changes`)
|
|
614
|
-
|
|
615
|
-
Global revision (finalization, optional):
|
|
616
|
-
|
|
617
|
-
- apply `phase_results.global_review.required_changes` across affected items
|
|
618
|
-
- **commit** the corrections (no closure phase follows it), so they land in the
|
|
619
|
-
run branch / pull request
|
|
620
|
-
|
|
621
|
-
Finalize (finalization terminal leaf, when there is no pull request):
|
|
622
|
-
|
|
623
|
-
- read-only; make no changes — all work is already implemented, committed, closed
|
|
624
|
-
- summarize the completed work items and confirm the run is complete
|
|
625
|
-
|
|
626
|
-
## Init Modes
|
|
627
|
-
|
|
628
|
-
`nyxagent init` asks for:
|
|
629
|
-
|
|
630
|
-
- harness preset: `codex`, `claude`, or custom
|
|
631
|
-
- model name
|
|
632
|
-
- reasoning level
|
|
633
|
-
- review strategy (see below)
|
|
634
|
-
- max iterations
|
|
635
|
-
- work item source template: `local` or `github`
|
|
636
|
-
|
|
637
|
-
The **review strategy** is a single choice (`--review-mode each|all|both|none`,
|
|
638
|
-
default `each`; the legacy `--review`/`--no-review` flags map to `each`/`none`):
|
|
639
|
-
|
|
640
|
-
- `each` — review + correction after **each** task, inside the iteration loop
|
|
641
|
-
(`execution → review → revision → closure`). This is the default and the
|
|
642
|
-
previous behavior.
|
|
643
|
-
- `all` — a single **global review + correction** of the whole run after the
|
|
644
|
-
loop, as a finalization sub-graph: `global_review` → (`changes_requested`)
|
|
645
|
-
`global_revision` → back to `global_review` → (`approved`) terminal. The
|
|
646
|
-
terminal is the `pull_request` phase for GitHub (with PR), otherwise a
|
|
647
|
-
read-only `finalize` leaf (local, or `--no-pull-request`). The loop is bounded
|
|
648
|
-
by `max_visits_per_iteration = 3`; exhausting it fails the run.
|
|
649
|
-
- `both` — per-task review **and** the final global review.
|
|
650
|
-
- `none` — no review at all (`execution → closure`).
|
|
651
|
-
|
|
652
|
-
For `local`, init asks for a work item path.
|
|
653
|
-
For `github`, init asks for a repository in `owner/repo` format and, by default,
|
|
654
|
-
wires the pull request finalization flow (`--no-pull-request` to skip). This adds
|
|
655
|
-
a `[git] mode = "worktree"` block, a `pull_request` phase, and
|
|
656
|
-
`workflow.final_phase = "pull_request"`. When a global review is enabled it
|
|
657
|
-
becomes the finalization entry (`workflow.final_phase = "global_review"`) and the
|
|
658
|
-
pull request becomes its approved terminal. Pull requests are GitHub-specific, so
|
|
659
|
-
`local` sources never get a `pull_request` phase; their global review approves
|
|
660
|
-
into the `finalize` leaf instead.
|
|
661
|
-
|
|
662
|
-
Default path selection:
|
|
663
|
-
|
|
664
|
-
- use `issues/` if it exists
|
|
665
|
-
- otherwise suggest `.nyxagent/tasks/`
|
|
666
|
-
|
|
667
|
-
If the chosen local work item path does not exist, init creates the directory but
|
|
668
|
-
does not create sample work items.
|
|
669
|
-
|
|
670
|
-
### Upgrading an existing config
|
|
671
|
-
|
|
672
|
-
`nyxagent init --missing` only adds missing template files; it does not rewrite an
|
|
673
|
-
existing `config.toml`. To fix issue closing on a config generated before the
|
|
674
|
-
network capability existed, add a network override to the `closure` phase:
|
|
675
|
-
|
|
676
|
-
```toml
|
|
677
|
-
[[phases]]
|
|
678
|
-
id = "closure"
|
|
679
|
-
# ... existing keys ...
|
|
680
|
-
|
|
681
|
-
[phases.harness]
|
|
682
|
-
# codex:
|
|
683
|
-
args = [
|
|
684
|
-
"exec",
|
|
685
|
-
"--model", "{{model.name}}",
|
|
686
|
-
"-c", "model_reasoning_effort=\"{{model.reasoning_level}}\"",
|
|
687
|
-
"-c", "sandbox_workspace_write.network_access=true",
|
|
688
|
-
"-"
|
|
689
|
-
]
|
|
690
|
-
# claude:
|
|
691
|
-
# args = ["-p", "--model", "{{model.name}}", "--output-format", "text", "--dangerously-skip-permissions"]
|
|
692
|
-
```
|
|
693
|
-
|
|
694
|
-
To adopt the pull request flow, add a `[git]` block, a `pull_request` phase, and
|
|
695
|
-
`workflow.final_phase = "pull_request"` (see the sections above), or regenerate
|
|
696
|
-
the config with `nyxagent init`.
|
|
697
|
-
|
|
698
|
-
## Implementation Stack
|
|
699
|
-
|
|
700
|
-
Recommended TypeScript stack:
|
|
701
|
-
|
|
702
|
-
- Node ESM
|
|
703
|
-
- `commander` for CLI commands
|
|
704
|
-
- `@inquirer/prompts` for interactive init
|
|
705
|
-
- `smol-toml` for TOML parsing/writing
|
|
706
|
-
- `zod` for internal config validation
|
|
707
|
-
- `ajv` for JSON Schema validation
|
|
708
|
-
- `execa` for process execution
|
|
709
|
-
- `tsx` for development
|
|
710
|
-
- `tsc` or `tsup` for build
|
|
711
|
-
|
|
712
|
-
Recommended source layout:
|
|
713
|
-
|
|
714
|
-
```text
|
|
715
|
-
src/
|
|
716
|
-
cli.ts
|
|
717
|
-
commands/
|
|
718
|
-
init.ts
|
|
719
|
-
run.ts
|
|
720
|
-
config/
|
|
721
|
-
loadConfig.ts
|
|
722
|
-
schema.ts
|
|
723
|
-
runtime/
|
|
724
|
-
renderPrompt.ts
|
|
725
|
-
runWorkflow.ts
|
|
726
|
-
runPhase.ts
|
|
727
|
-
parseResult.ts
|
|
728
|
-
templates/
|
|
729
|
-
default/
|
|
730
|
-
```
|
|
731
|
-
|
|
732
|
-
## Future Work
|
|
733
|
-
|
|
734
|
-
- `nyxagent resume`
|
|
735
|
-
- `nyxagent import-tasks`
|
|
736
|
-
- additional tracker adapters
|
|
737
|
-
- explicit Git commit adapter
|
|
738
|
-
- stricter artifact redaction
|
|
739
|
-
- richer phase retry policy
|
|
740
|
-
- local runner eject command
|
|
741
|
-
- JSON event stream output
|
|
742
|
-
- human approval gates between phases
|