@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.
Files changed (44) hide show
  1. package/README.md +58 -9
  2. package/dist/cli.js +13 -16
  3. package/dist/commands/init.js +112 -462
  4. package/dist/commands/run.js +17 -3
  5. package/dist/commands/update.js +1 -0
  6. package/dist/config/loadConfig.js +17 -3
  7. package/dist/config/schema.js +29 -146
  8. package/dist/runtime/files.js +1 -0
  9. package/dist/runtime/git.js +1 -0
  10. package/dist/runtime/gitLifecycle.js +19 -57
  11. package/dist/runtime/harness.js +26 -0
  12. package/dist/runtime/ledger.js +1 -0
  13. package/dist/runtime/paths.js +1 -12
  14. package/dist/runtime/prompts.js +103 -0
  15. package/dist/runtime/runPhase.js +85 -254
  16. package/dist/runtime/runPipeline.js +479 -0
  17. package/dist/runtime/schemas.js +52 -0
  18. package/dist/runtime/scm.js +80 -0
  19. package/dist/runtime/time.js +1 -0
  20. package/dist/runtime/validateResult.js +2 -3
  21. package/dist/runtime/workItems.js +43 -118
  22. package/package.json +2 -5
  23. package/dist/runtime/buildPrompt.js +0 -54
  24. package/dist/runtime/effectiveConfig.js +0 -14
  25. package/dist/runtime/renderTemplate.js +0 -28
  26. package/dist/runtime/runWorkflow.js +0 -680
  27. package/dist/runtime/validateWorkItem.js +0 -212
  28. package/dist/runtime/workItemAnnotations.js +0 -39
  29. package/docs/nyxagent-v0-spec.md +0 -742
  30. package/templates/default/prompts/closure.md +0 -30
  31. package/templates/default/prompts/execution.md +0 -11
  32. package/templates/default/prompts/finalize.md +0 -7
  33. package/templates/default/prompts/global-review.md +0 -24
  34. package/templates/default/prompts/global-revision.md +0 -9
  35. package/templates/default/prompts/pull-request.md +0 -23
  36. package/templates/default/prompts/repair-result.md +0 -29
  37. package/templates/default/prompts/review.md +0 -18
  38. package/templates/default/prompts/revision.md +0 -7
  39. package/templates/default/prompts/selection.md +0 -46
  40. package/templates/default/schemas/closure.schema.json +0 -35
  41. package/templates/default/schemas/global-review.schema.json +0 -60
  42. package/templates/default/schemas/pull-request.schema.json +0 -44
  43. package/templates/default/schemas/review.schema.json +0 -60
  44. package/templates/default/schemas/selection.schema.json +0 -135
@@ -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