@nathapp/nax 0.51.0 → 0.51.2
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 +177 -104
- package/dist/nax.js +35 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,15 +33,20 @@ nax run -f my-feature --plan --from spec.md
|
|
|
33
33
|
## How It Works
|
|
34
34
|
|
|
35
35
|
```
|
|
36
|
-
|
|
36
|
+
(plan →) acceptance setup → route → execute → verify → (escalate) → regression gate → acceptance
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
1. **
|
|
40
|
-
2. **
|
|
41
|
-
3. **
|
|
42
|
-
4. **
|
|
43
|
-
5. **
|
|
44
|
-
6. **
|
|
39
|
+
1. **Plan** *(optional)* — `nax run --plan` generates a `prd.json` from a spec file using an LLM
|
|
40
|
+
2. **Acceptance setup** *(pre-run)* — generate acceptance tests and assert RED (tests must fail before implementation)
|
|
41
|
+
3. **Route** — classify story complexity and select model tier (fast → balanced → powerful)
|
|
42
|
+
4. **Context** — gather relevant code, tests, and project standards
|
|
43
|
+
5. **Execute** — run an agent session (Claude Code, Codex, Gemini CLI, or ACP)
|
|
44
|
+
6. **Verify** — run scoped tests; if failing, **rectify** before escalating
|
|
45
|
+
7. **Review** — lint + typecheck; if failing, **autofix** before escalating
|
|
46
|
+
8. **Escalate** — on repeated failure, retry with a higher model tier
|
|
47
|
+
9. **Loop** — repeat steps 3–8 per story until all pass or a cost/iteration limit is hit
|
|
48
|
+
10. **Regression gate** — deferred full-suite run after all stories pass
|
|
49
|
+
11. **Acceptance** *(post-run)* — run the generated acceptance tests against the completed feature
|
|
45
50
|
|
|
46
51
|
---
|
|
47
52
|
|
|
@@ -49,7 +54,7 @@ analyze → route → execute → verify → (loop until all stories pass) → r
|
|
|
49
54
|
|
|
50
55
|
### `nax init`
|
|
51
56
|
|
|
52
|
-
Initialize nax in your project. Creates the
|
|
57
|
+
Initialize nax in your project. Creates the `.nax/` folder structure.
|
|
53
58
|
|
|
54
59
|
```bash
|
|
55
60
|
nax init
|
|
@@ -57,7 +62,7 @@ nax init
|
|
|
57
62
|
|
|
58
63
|
Creates:
|
|
59
64
|
```
|
|
60
|
-
nax/
|
|
65
|
+
.nax/
|
|
61
66
|
├── config.json # Project-level config
|
|
62
67
|
└── features/ # One folder per feature
|
|
63
68
|
```
|
|
@@ -68,7 +73,7 @@ nax/
|
|
|
68
73
|
nax init --package packages/api
|
|
69
74
|
```
|
|
70
75
|
|
|
71
|
-
Creates
|
|
76
|
+
Creates `.nax/mono/packages/api/context.md` for per-package agent context.
|
|
72
77
|
|
|
73
78
|
---
|
|
74
79
|
|
|
@@ -80,7 +85,7 @@ Scaffold a new feature.
|
|
|
80
85
|
nax features create user-auth
|
|
81
86
|
```
|
|
82
87
|
|
|
83
|
-
Creates
|
|
88
|
+
Creates `.nax/features/user-auth/spec.md` — fill in the overview, user stories, and acceptance criteria, then run `nax plan` to generate `prd.json`.
|
|
84
89
|
|
|
85
90
|
### `nax features list`
|
|
86
91
|
|
|
@@ -135,7 +140,7 @@ nax run -f my-feature
|
|
|
135
140
|
| Flag | Description |
|
|
136
141
|
|:-----|:------------|
|
|
137
142
|
| `-f, --feature <name>` | Feature name |
|
|
138
|
-
| `-a, --agent <name>` | Force a specific agent (`claude`, `opencode`, `codex`, etc.) |
|
|
143
|
+
| `-a, --agent <name>` | Force a specific agent (`claude`, `opencode`, `codex`, etc.). Only applies when `agent.protocol = "cli"` — ignored when using ACP protocol. |
|
|
139
144
|
| `--plan` | Run plan phase first (requires `--from`) |
|
|
140
145
|
| `--from <spec-path>` | Spec file for `--plan` |
|
|
141
146
|
| `--one-shot` | Skip interactive Q&A during planning (ACP only) |
|
|
@@ -201,21 +206,28 @@ nax status -f my-feature
|
|
|
201
206
|
|
|
202
207
|
---
|
|
203
208
|
|
|
204
|
-
### `nax logs
|
|
209
|
+
### `nax logs`
|
|
205
210
|
|
|
206
|
-
Stream logs from the current or last run.
|
|
211
|
+
Stream logs from the current or last run. Run from your project directory.
|
|
207
212
|
|
|
208
213
|
```bash
|
|
209
|
-
|
|
214
|
+
# List all recorded runs
|
|
215
|
+
nax logs --list
|
|
210
216
|
|
|
211
|
-
# Follow in real-time
|
|
212
|
-
nax logs
|
|
217
|
+
# Follow current run in real-time
|
|
218
|
+
nax logs --follow
|
|
213
219
|
|
|
214
220
|
# Filter by story
|
|
215
|
-
nax logs
|
|
221
|
+
nax logs --story US-003
|
|
216
222
|
|
|
217
|
-
# Filter by level
|
|
218
|
-
nax logs
|
|
223
|
+
# Filter by log level
|
|
224
|
+
nax logs --level error
|
|
225
|
+
|
|
226
|
+
# Select a specific run by ID
|
|
227
|
+
nax logs --run <runId>
|
|
228
|
+
|
|
229
|
+
# Raw JSONL output (for scripting)
|
|
230
|
+
nax logs --json
|
|
219
231
|
```
|
|
220
232
|
|
|
221
233
|
---
|
|
@@ -255,7 +267,7 @@ Output sections:
|
|
|
255
267
|
|
|
256
268
|
### `nax generate`
|
|
257
269
|
|
|
258
|
-
Generate agent config files from
|
|
270
|
+
Generate agent config files from `.nax/context.md`. Supports Claude Code, OpenCode, Codex, Cursor, Windsurf, Aider, and Gemini.
|
|
259
271
|
|
|
260
272
|
```bash
|
|
261
273
|
nax generate
|
|
@@ -265,7 +277,7 @@ nax generate
|
|
|
265
277
|
|
|
266
278
|
| Flag | Description |
|
|
267
279
|
|:-----|:------------|
|
|
268
|
-
| `-c, --context <path>` | Context file path (default:
|
|
280
|
+
| `-c, --context <path>` | Context file path (default: `.nax/context.md`) |
|
|
269
281
|
| `-o, --output <dir>` | Output directory (default: project root) |
|
|
270
282
|
| `-a, --agent <name>` | Generate for a specific agent only (`claude`, `opencode`, `cursor`, `windsurf`, `aider`, `codex`, `gemini`) |
|
|
271
283
|
| `--dry-run` | Preview without writing files |
|
|
@@ -287,7 +299,7 @@ nax generate
|
|
|
287
299
|
|
|
288
300
|
**Workflow:**
|
|
289
301
|
|
|
290
|
-
1. Create
|
|
302
|
+
1. Create `.nax/context.md` — describe your project's architecture, conventions, and coding standards
|
|
291
303
|
2. Run `nax generate` — writes agent config files to the project root (and per-package if configured)
|
|
292
304
|
3. Commit the generated files — your agents will automatically pick them up
|
|
293
305
|
|
|
@@ -301,7 +313,7 @@ nax generate --package packages/api
|
|
|
301
313
|
nax generate --all-packages
|
|
302
314
|
```
|
|
303
315
|
|
|
304
|
-
Each package can have its own
|
|
316
|
+
Each package can have its own context file at `.nax/mono/<package>/context.md` for package-specific agent instructions (created via `nax init --package <package>`).
|
|
305
317
|
|
|
306
318
|
---
|
|
307
319
|
|
|
@@ -317,7 +329,7 @@ nax prompts -f my-feature
|
|
|
317
329
|
|
|
318
330
|
| Flag | Description |
|
|
319
331
|
|:-----|:------------|
|
|
320
|
-
| `--init` | Export default role templates to
|
|
332
|
+
| `--init` | Export default role templates to `.nax/templates/` for customization |
|
|
321
333
|
| `--role <role>` | Show prompt for a specific role (`implementer`, `test-writer`, `verifier`, `tdd-simple`) |
|
|
322
334
|
|
|
323
335
|
After running `--init`, edit the templates and nax will use them automatically via `prompts.overrides` config.
|
|
@@ -354,12 +366,19 @@ nax agents
|
|
|
354
366
|
|
|
355
367
|
---
|
|
356
368
|
|
|
357
|
-
### `nax config
|
|
369
|
+
### `nax config`
|
|
358
370
|
|
|
359
|
-
Display the effective merged configuration
|
|
371
|
+
Display the effective merged configuration (global + project layers).
|
|
360
372
|
|
|
361
373
|
```bash
|
|
362
|
-
|
|
374
|
+
# Show merged config
|
|
375
|
+
nax config
|
|
376
|
+
|
|
377
|
+
# Show with field descriptions
|
|
378
|
+
nax config --explain
|
|
379
|
+
|
|
380
|
+
# Show only fields where project overrides global
|
|
381
|
+
nax config --diff
|
|
363
382
|
```
|
|
364
383
|
|
|
365
384
|
---
|
|
@@ -371,7 +390,7 @@ Config is layered — project overrides global:
|
|
|
371
390
|
| File | Scope |
|
|
372
391
|
|:-----|:------|
|
|
373
392
|
| `~/.nax/config.json` | Global (all projects) |
|
|
374
|
-
|
|
|
393
|
+
| `.nax/config.json` | Project-level override |
|
|
375
394
|
|
|
376
395
|
**Key options:**
|
|
377
396
|
|
|
@@ -414,7 +433,7 @@ Review commands (`lint`, `typecheck`) are executed directly via `Bun.spawn` —
|
|
|
414
433
|
}
|
|
415
434
|
```
|
|
416
435
|
```json
|
|
417
|
-
// nax/config.json
|
|
436
|
+
// .nax/config.json
|
|
418
437
|
"quality": {
|
|
419
438
|
"commands": {
|
|
420
439
|
"typecheck": "bun run build-and-check"
|
|
@@ -442,13 +461,15 @@ Use `testScoped` to define the exact scoped test command with a `{{files}}` plac
|
|
|
442
461
|
|
|
443
462
|
If `testScoped` is not configured, nax falls back to a heuristic that replaces the last path-like token in the `test` command. **Recommended:** always configure `testScoped` explicitly to avoid surprises.
|
|
444
463
|
|
|
445
|
-
**TDD strategy options:**
|
|
464
|
+
**TDD strategy options:** <a name="tdd-strategy-options"></a>
|
|
446
465
|
|
|
447
466
|
| Value | Behaviour |
|
|
448
467
|
|:------|:----------|
|
|
449
|
-
| `auto` | nax decides based on complexity and tags |
|
|
450
|
-
| `
|
|
451
|
-
| `
|
|
468
|
+
| `auto` | nax decides based on complexity and tags — simple→`tdd-simple`, security/public-api→`three-session-tdd`, else→`three-session-tdd-lite` |
|
|
469
|
+
| `strict` | Always use `three-session-tdd` (strictest — all stories) |
|
|
470
|
+
| `lite` | Always use `three-session-tdd-lite` |
|
|
471
|
+
| `simple` | Always use `tdd-simple` (1 session) |
|
|
472
|
+
| `off` | No TDD — tests written after implementation (`test-after`) |
|
|
452
473
|
|
|
453
474
|
---
|
|
454
475
|
|
|
@@ -462,12 +483,12 @@ Customize the instructions sent to each agent role for your project's specific n
|
|
|
462
483
|
|
|
463
484
|
```bash
|
|
464
485
|
nax prompts --init # Create default templates
|
|
465
|
-
# Edit nax/templates/*.md
|
|
486
|
+
# Edit .nax/templates/*.md
|
|
466
487
|
nax prompts --export test-writer # Preview a role's prompt
|
|
467
488
|
nax run -f my-feature # Uses your custom prompts
|
|
468
489
|
```
|
|
469
490
|
|
|
470
|
-
**Full guide:** See [Prompt Customization Guide](docs/prompt-customization.md) for detailed instructions, role reference, and best practices.
|
|
491
|
+
**Full guide:** See [Prompt Customization Guide](docs/guides/prompt-customization.md) for detailed instructions, role reference, and best practices.
|
|
471
492
|
|
|
472
493
|
---
|
|
473
494
|
|
|
@@ -477,12 +498,13 @@ nax selects a test strategy per story based on complexity and tags:
|
|
|
477
498
|
|
|
478
499
|
| Strategy | Sessions | When | Description |
|
|
479
500
|
|:---------|:---------|:-----|:------------|
|
|
480
|
-
| `test
|
|
501
|
+
| `no-test` | 1 | Config, docs, CI, pure refactors with no behavior change | No tests written or run — requires `noTestJustification` in prd.json |
|
|
502
|
+
| `test-after` | 1 | Refactors, deletions | Single session, tests written after implementation |
|
|
481
503
|
| `tdd-simple` | 1 | Simple stories | Single session with TDD prompt (red-green-refactor) |
|
|
482
504
|
| `three-session-tdd-lite` | 3 | Medium stories | Three sessions, relaxed isolation rules |
|
|
483
505
|
| `three-session-tdd` | 3 | Complex/security stories | Three sessions, strict file isolation |
|
|
484
506
|
|
|
485
|
-
Configure the default TDD behavior in
|
|
507
|
+
Configure the default TDD behavior in `.nax/config.json`:
|
|
486
508
|
|
|
487
509
|
```json
|
|
488
510
|
{
|
|
@@ -492,11 +514,7 @@ Configure the default TDD behavior in `nax/config.json`:
|
|
|
492
514
|
}
|
|
493
515
|
```
|
|
494
516
|
|
|
495
|
-
|
|
496
|
-
|:------|:----------|
|
|
497
|
-
| `auto` | nax decides based on complexity and tags (default) |
|
|
498
|
-
| `lite` | Prefer `three-session-tdd-lite` for complex stories |
|
|
499
|
-
| `strict` | Always use full `three-session-tdd` for complex stories |
|
|
517
|
+
See [TDD strategy options](#tdd-strategy-options) for all values.
|
|
500
518
|
|
|
501
519
|
---
|
|
502
520
|
|
|
@@ -544,7 +562,7 @@ Configured under `quality.testing` — supports **per-package override** in mono
|
|
|
544
562
|
|
|
545
563
|
> **Tip:** `externalBoundaries` and `mockGuidance` complement `context.md`. nax provides the rule ("mock all I/O"), while `context.md` provides project-specific knowledge ("use `ioredis-mock` for Redis"). Use both for best results.
|
|
546
564
|
|
|
547
|
-
> **Monorepo:** Each package can override `quality.testing` in its own
|
|
565
|
+
> **Monorepo:** Each package can override `quality.testing` in its own `.nax/mono/<package>/config.json`. For example, `packages/api` can specify Redis boundaries while `apps/web` specifies HTTP-only.
|
|
548
566
|
|
|
549
567
|
> **Opt-out:** Set `quality.testing.hermetic: false` if your project requires real integration calls (e.g. live database tests against a local dev container).
|
|
550
568
|
|
|
@@ -552,34 +570,41 @@ Configured under `quality.testing` — supports **per-package override** in mono
|
|
|
552
570
|
|
|
553
571
|
## Story Decomposition
|
|
554
572
|
|
|
555
|
-
|
|
573
|
+
Story decomposition is **opt-in** — disabled by default. Enable it by adding a `decompose` block to `.nax/config.json`.
|
|
556
574
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
**How it works:**
|
|
560
|
-
|
|
561
|
-
1. The `DecomposeBuilder` constructs a prompt with the target story, sibling stories (to prevent overlap), and codebase context
|
|
562
|
-
2. An LLM generates sub-stories with IDs, titles, descriptions, acceptance criteria, and dependency ordering
|
|
563
|
-
3. Post-decompose validators check:
|
|
564
|
-
- **Overlap** — sub-stories must not duplicate scope of existing stories
|
|
565
|
-
- **Coverage** — sub-stories must cover all parent acceptance criteria
|
|
566
|
-
- **Complexity** — each sub-story must be simpler than the parent
|
|
567
|
-
- **Dependencies** — dependency graph must be acyclic with valid references
|
|
568
|
-
4. The parent story is replaced in the PRD with the validated sub-stories
|
|
575
|
+
When enabled, nax checks during the routing stage whether a story is oversized (complex/expert complexity with more ACs than `maxAcceptanceCriteria`). If so, an LLM breaks it into smaller sub-stories and replaces the original in the PRD.
|
|
569
576
|
|
|
570
577
|
**Configuration:**
|
|
571
578
|
|
|
572
579
|
```json
|
|
573
580
|
{
|
|
574
581
|
"decompose": {
|
|
575
|
-
"
|
|
576
|
-
"
|
|
577
|
-
"
|
|
578
|
-
"
|
|
582
|
+
"trigger": "auto",
|
|
583
|
+
"maxAcceptanceCriteria": 6,
|
|
584
|
+
"maxSubstories": 5,
|
|
585
|
+
"maxSubstoryComplexity": "medium",
|
|
586
|
+
"maxRetries": 2,
|
|
587
|
+
"model": "balanced"
|
|
579
588
|
}
|
|
580
589
|
}
|
|
581
590
|
```
|
|
582
591
|
|
|
592
|
+
**Trigger modes:**
|
|
593
|
+
|
|
594
|
+
| Value | Behaviour |
|
|
595
|
+
|:------|:----------|
|
|
596
|
+
| `auto` | Decompose automatically — no confirmation prompt |
|
|
597
|
+
| `confirm` | Show interaction prompt — you approve, skip, or continue as-is |
|
|
598
|
+
| `disabled` | Never decompose — log a warning if story is oversized |
|
|
599
|
+
|
|
600
|
+
> **Note:** `storySizeGate` (under `precheck`) is a separate pre-run guard that warns if stories exceed size limits before execution starts. Decomposition happens during routing, mid-run.
|
|
601
|
+
|
|
602
|
+
**How it works:**
|
|
603
|
+
|
|
604
|
+
1. An LLM generates sub-stories with IDs, titles, descriptions, acceptance criteria, and dependency ordering
|
|
605
|
+
2. Post-decompose validators check overlap, coverage, complexity, and dependency ordering
|
|
606
|
+
3. The parent story is replaced in the PRD with the validated sub-stories
|
|
607
|
+
|
|
583
608
|
---
|
|
584
609
|
|
|
585
610
|
## Regression Gate
|
|
@@ -601,8 +626,8 @@ After all stories pass their individual verification, nax can run a deferred ful
|
|
|
601
626
|
| Mode | Behaviour |
|
|
602
627
|
|:-----|:----------|
|
|
603
628
|
| `disabled` | No regression gate |
|
|
604
|
-
| `per-story` | Full suite after each story
|
|
605
|
-
| `deferred` | Full suite once after all stories pass (recommended) |
|
|
629
|
+
| `per-story` | Full suite after each story — higher cost and slower if stories fail regression |
|
|
630
|
+
| `deferred` | Full suite once after all stories pass (recommended) — **default** |
|
|
606
631
|
|
|
607
632
|
If the regression gate detects failures, nax maps them to the responsible story via git blame and attempts automated rectification. If rectification fails, affected stories are marked as `regression-failed`.
|
|
608
633
|
|
|
@@ -646,7 +671,9 @@ nax run -f my-feature --parallel 3
|
|
|
646
671
|
|
|
647
672
|
## Agents
|
|
648
673
|
|
|
649
|
-
nax supports multiple coding agents.
|
|
674
|
+
nax supports multiple coding agents via the [Agent Client Protocol (ACP)](https://github.com/openclaw/acpx). **ACP protocol is recommended** — it provides persistent sessions, structured cost/token reporting, and works with all supported agents.
|
|
675
|
+
|
|
676
|
+
> **CLI protocol** (`agent.protocol: "cli"`) is supported for Claude Code only and is being gradually deprecated in favour of ACP. New projects should use ACP.
|
|
650
677
|
|
|
651
678
|
```bash
|
|
652
679
|
# List installed agents and their capabilities
|
|
@@ -655,21 +682,16 @@ nax agents
|
|
|
655
682
|
|
|
656
683
|
**Supported agents:**
|
|
657
684
|
|
|
658
|
-
| Agent |
|
|
659
|
-
|
|
660
|
-
| `claude` |
|
|
661
|
-
| `opencode`
|
|
662
|
-
| `codex` | ACP | Codex via acpx |
|
|
663
|
-
| `cursor` | ACP | Cursor via acpx |
|
|
664
|
-
| `windsurf` | ACP | Windsurf via acpx |
|
|
665
|
-
| `aider` | ACP | Aider via acpx |
|
|
666
|
-
| `gemini` | ACP | Gemini CLI via acpx |
|
|
685
|
+
| Agent | CLI mode |
|
|
686
|
+
|:------|:---------|
|
|
687
|
+
| `claude` | ✅ Stable |
|
|
688
|
+
| All others (`codex`, `gemini`, `opencode`, `cursor`, `copilot`, `kilo`, `qwen`, `kimi`, `iflow`, `droid`, `kiro`, and more) | 🧪 Experimental |
|
|
667
689
|
|
|
668
|
-
|
|
690
|
+
nax connects to agents via [acpx](https://github.com/openclaw/acpx). All agents run as persistent ACP sessions — nax sends prompts and receives structured JSON-RPC responses including token counts and exact USD cost per session. For the full list of supported agents and their ACP startup commands, see the [acpx agent docs](https://github.com/openclaw/acpx#agents).
|
|
669
691
|
|
|
670
|
-
|
|
692
|
+
> **Note:** When `agent.protocol` is set to `"acp"`, the `--agent` CLI flag has no effect — all execution routes through the ACP adapter regardless of agent name.
|
|
671
693
|
|
|
672
|
-
> **Known issue — `acpx` ≤ 0.3.1:** The `--model` flag is not supported. Model selection via `execution.model` or per-package `model` overrides has no effect
|
|
694
|
+
> **Known issue — `acpx` ≤ 0.3.1:** The `--model` flag is not supported. Model selection via `execution.model` or per-package `model` overrides has no effect. As a temporary workaround, use the [nathapp-io/acpx](https://github.com/nathapp-io/acpx) fork which adds `--model` support. Upstream fix is tracked in [openclaw/acpx#49](https://github.com/openclaw/acpx/issues/49).
|
|
673
695
|
|
|
674
696
|
**Configuring agents:**
|
|
675
697
|
|
|
@@ -683,10 +705,11 @@ nax uses [acpx](https://github.com/nathapp/acpx) as the ACP transport. All agent
|
|
|
683
705
|
}
|
|
684
706
|
```
|
|
685
707
|
|
|
686
|
-
**Force a specific agent at runtime:**
|
|
708
|
+
**Force a specific agent at runtime (CLI protocol only):**
|
|
687
709
|
|
|
688
710
|
```bash
|
|
689
|
-
|
|
711
|
+
# Only applies when agent.protocol = "cli" (Claude Code only — other agents experimental)
|
|
712
|
+
nax run -f my-feature --agent claude
|
|
690
713
|
```
|
|
691
714
|
|
|
692
715
|
---
|
|
@@ -708,27 +731,27 @@ nax init --package packages/web
|
|
|
708
731
|
|
|
709
732
|
### Per-Package Config
|
|
710
733
|
|
|
711
|
-
Each package
|
|
734
|
+
Each package's config and context are stored centrally under the root `.nax/mono/` directory:
|
|
712
735
|
|
|
713
736
|
```
|
|
714
737
|
repo-root/
|
|
715
|
-
├── nax/
|
|
716
|
-
│
|
|
717
|
-
|
|
718
|
-
│
|
|
719
|
-
│
|
|
720
|
-
│
|
|
721
|
-
│
|
|
722
|
-
│
|
|
723
|
-
│
|
|
724
|
-
│
|
|
725
|
-
│
|
|
738
|
+
├── .nax/
|
|
739
|
+
│ ├── config.json # root config
|
|
740
|
+
│ └── mono/
|
|
741
|
+
│ ├── packages/
|
|
742
|
+
│ │ └── api/
|
|
743
|
+
│ │ ├── config.json # overrides for packages/api
|
|
744
|
+
│ │ └── context.md # agent context for packages/api
|
|
745
|
+
│ └── apps/
|
|
746
|
+
│ └── api/
|
|
747
|
+
│ ├── config.json # overrides for apps/api
|
|
748
|
+
│ └── context.md # agent context for apps/api
|
|
726
749
|
```
|
|
727
750
|
|
|
728
751
|
**Overridable fields per package:** `execution`, `review`, `acceptance`, `quality`, `context`
|
|
729
752
|
|
|
730
753
|
```json
|
|
731
|
-
// packages/api/
|
|
754
|
+
// .nax/mono/packages/api/config.json
|
|
732
755
|
{
|
|
733
756
|
"quality": {
|
|
734
757
|
"commands": {
|
|
@@ -764,7 +787,7 @@ When `nax plan` generates stories for a monorepo, it auto-discovers packages fro
|
|
|
764
787
|
- `turbo.json` → `packages` field
|
|
765
788
|
- `package.json` → `workspaces`
|
|
766
789
|
- `pnpm-workspace.yaml` → `packages`
|
|
767
|
-
- Existing
|
|
790
|
+
- Existing `.nax/mono/*/context.md` files
|
|
768
791
|
|
|
769
792
|
### Generate Agent Files for All Packages
|
|
770
793
|
|
|
@@ -772,7 +795,7 @@ When `nax plan` generates stories for a monorepo, it auto-discovers packages fro
|
|
|
772
795
|
nax generate --all-packages
|
|
773
796
|
```
|
|
774
797
|
|
|
775
|
-
Generates a `CLAUDE.md` (or agent-specific file) in each discovered package directory, using the package's own
|
|
798
|
+
Generates a `CLAUDE.md` (or agent-specific file) in each discovered package directory, using the package's own `.nax/mono/<package>/context.md` if present.
|
|
776
799
|
|
|
777
800
|
---
|
|
778
801
|
|
|
@@ -780,7 +803,7 @@ Generates a `CLAUDE.md` (or agent-specific file) in each discovered package dire
|
|
|
780
803
|
|
|
781
804
|
Integrate notifications, CI triggers, or custom scripts via lifecycle hooks.
|
|
782
805
|
|
|
783
|
-
**Project hooks** (
|
|
806
|
+
**Project hooks** (`.nax/hooks.json`):
|
|
784
807
|
|
|
785
808
|
```json
|
|
786
809
|
{
|
|
@@ -883,7 +906,7 @@ nax can pause execution and prompt you for decisions at critical points. Configu
|
|
|
883
906
|
| `max-retries` | 🟡 Yellow | `skip` | Story exhausted all retry attempts — skip and continue? |
|
|
884
907
|
| `pre-merge` | 🟡 Yellow | `escalate` | Checkpoint before merging to main branch |
|
|
885
908
|
| `human-review` | 🟡 Yellow | `skip` | Human review required on critical failure |
|
|
886
|
-
| `story-oversized` | 🟡 Yellow | `continue` | Story too complex — decompose into sub-stories? |
|
|
909
|
+
| `story-oversized` | 🟡 Yellow | `continue` | Story too complex — decompose into sub-stories? (only fires when `decompose.trigger = "confirm"`) |
|
|
887
910
|
| `story-ambiguity` | 🟢 Green | `continue` | Story requirements unclear — continue with best effort? |
|
|
888
911
|
| `review-gate` | 🟢 Green | `continue` | Code review checkpoint before proceeding |
|
|
889
912
|
|
|
@@ -913,7 +936,7 @@ nax can pause execution and prompt you for decisions at critical points. Configu
|
|
|
913
936
|
|
|
914
937
|
Extend nax with custom reviewers, reporters, or integrations.
|
|
915
938
|
|
|
916
|
-
**Project plugins** (
|
|
939
|
+
**Project plugins** (`.nax/config.json`):
|
|
917
940
|
|
|
918
941
|
```json
|
|
919
942
|
{
|
|
@@ -976,35 +999,85 @@ nax precheck -f my-feature
|
|
|
976
999
|
|
|
977
1000
|
**Run stopped mid-way**
|
|
978
1001
|
|
|
979
|
-
nax saves progress in
|
|
1002
|
+
nax saves progress in `.nax/features/<name>/prd.json`. Re-run with the same command — completed stories are skipped automatically.
|
|
980
1003
|
|
|
981
1004
|
---
|
|
982
1005
|
|
|
983
1006
|
## PRD Format
|
|
984
1007
|
|
|
985
|
-
User stories are defined in
|
|
1008
|
+
User stories are defined in `.nax/features/<name>/prd.json`. Typically generated by `nax plan` — but you can write it by hand.
|
|
986
1009
|
|
|
987
1010
|
```json
|
|
988
1011
|
{
|
|
1012
|
+
"project": "my-app",
|
|
989
1013
|
"feature": "user-auth",
|
|
1014
|
+
"branchName": "feat/user-auth",
|
|
1015
|
+
"createdAt": "2026-01-01T00:00:00.000Z",
|
|
1016
|
+
"updatedAt": "2026-01-01T00:00:00.000Z",
|
|
990
1017
|
"userStories": [
|
|
991
1018
|
{
|
|
992
1019
|
"id": "US-001",
|
|
993
1020
|
"title": "Add login endpoint",
|
|
994
|
-
"description": "POST /auth/login
|
|
1021
|
+
"description": "POST /auth/login accepts email + password, returns signed JWT on success",
|
|
995
1022
|
"acceptanceCriteria": [
|
|
996
|
-
"Returns JWT on
|
|
997
|
-
"Returns 401 on invalid credentials"
|
|
1023
|
+
"Returns 200 + JWT on valid credentials",
|
|
1024
|
+
"Returns 401 on invalid credentials",
|
|
1025
|
+
"Rate-limits to 5 attempts per minute"
|
|
998
1026
|
],
|
|
999
|
-
"complexity": "medium",
|
|
1000
1027
|
"tags": ["auth", "security"],
|
|
1001
|
-
"
|
|
1028
|
+
"dependencies": [],
|
|
1029
|
+
"status": "pending",
|
|
1030
|
+
"passes": false,
|
|
1031
|
+
"attempts": 0,
|
|
1032
|
+
"escalations": [],
|
|
1033
|
+
"contextFiles": ["src/auth/types.ts"],
|
|
1034
|
+
"expectedFiles": ["src/auth/login.ts", "test/auth/login.test.ts"]
|
|
1035
|
+
},
|
|
1036
|
+
{
|
|
1037
|
+
"id": "US-002",
|
|
1038
|
+
"title": "Update changelog",
|
|
1039
|
+
"description": "Add v1.0 entry to CHANGELOG.md",
|
|
1040
|
+
"acceptanceCriteria": ["CHANGELOG.md has v1.0 section"],
|
|
1041
|
+
"tags": ["docs"],
|
|
1042
|
+
"dependencies": [],
|
|
1043
|
+
"status": "pending",
|
|
1044
|
+
"passes": false,
|
|
1045
|
+
"attempts": 0,
|
|
1046
|
+
"escalations": [],
|
|
1047
|
+
"routing": {
|
|
1048
|
+
"complexity": "simple",
|
|
1049
|
+
"testStrategy": "no-test",
|
|
1050
|
+
"noTestJustification": "Docs-only change — no executable code",
|
|
1051
|
+
"reasoning": "Pure documentation update"
|
|
1052
|
+
}
|
|
1002
1053
|
}
|
|
1003
1054
|
]
|
|
1004
1055
|
}
|
|
1005
1056
|
```
|
|
1006
1057
|
|
|
1007
|
-
|
|
1058
|
+
**Key fields:**
|
|
1059
|
+
|
|
1060
|
+
| Field | Required | Description |
|
|
1061
|
+
|:------|:---------|:------------|
|
|
1062
|
+
| `id` | ✅ | Story ID — must be unique (e.g. `US-001`) |
|
|
1063
|
+
| `title` | ✅ | Short story title |
|
|
1064
|
+
| `description` | ✅ | What needs to be built |
|
|
1065
|
+
| `acceptanceCriteria` | ✅ | Testable outcomes — used for acceptance tests |
|
|
1066
|
+
| `tags` | ✅ | Routing hints that influence complexity classification and test strategy selection. Security tags (`auth`, `security`, `jwt`, `oauth`, `rbac`, etc.) and public-API tags (`public-api`, `endpoint`, `sdk`, etc.) force `three-session-tdd`. UI/integration tags (`ui`, `layout`, `cli`, `integration`) prefer `three-session-tdd-lite`. |
|
|
1067
|
+
| `dependencies` | ✅ | Story IDs that must pass before this one runs |
|
|
1068
|
+
| `status` | ✅ | `pending` \| `in-progress` \| `passed` \| `failed` \| `skipped` \| `blocked` \| `paused` |
|
|
1069
|
+
| `passes` | ✅ | `true` once all ACs pass — set by nax, not manually |
|
|
1070
|
+
| `attempts` | ✅ | Retry counter — set by nax |
|
|
1071
|
+
| `escalations` | ✅ | Escalation history — set by nax |
|
|
1072
|
+
| `contextFiles` | optional | Files pre-loaded into agent prompt |
|
|
1073
|
+
| `expectedFiles` | optional | Files that must exist after execution (pre-flight gate) |
|
|
1074
|
+
| `workdir` | optional | Package subdirectory for monorepo stories (e.g. `packages/api`) |
|
|
1075
|
+
| `routing` | optional | Pre-set routing — skip LLM classification if provided |
|
|
1076
|
+
| `routing.testStrategy` | optional | Override test strategy (e.g. `no-test`, `tdd-simple`). Only honored when `routing.contentHash` is absent — omit `contentHash` to prevent the LLM classifier from overriding your manual value. |
|
|
1077
|
+
| `routing.noTestJustification` | required if `no-test` | Explain why no tests are needed |
|
|
1078
|
+
| `storyPoints` | optional | Estimate (default: 1) |
|
|
1079
|
+
|
|
1080
|
+
> **Tip:** Use `"status": "passed"` to manually skip a story that's already done.
|
|
1008
1081
|
|
|
1009
1082
|
---
|
|
1010
1083
|
|
package/dist/nax.js
CHANGED
|
@@ -3321,7 +3321,8 @@ Decompose this spec into user stories. For each story, provide:
|
|
|
3321
3321
|
9. reasoning: Why this complexity level
|
|
3322
3322
|
10. estimatedLOC: Estimated lines of code to change
|
|
3323
3323
|
11. risks: Array of implementation risks
|
|
3324
|
-
12. testStrategy: "test-after" | "tdd-simple" | "three-session-tdd" | "three-session-tdd-lite"
|
|
3324
|
+
12. testStrategy: "no-test" | "test-after" | "tdd-simple" | "three-session-tdd" | "three-session-tdd-lite"
|
|
3325
|
+
13. noTestJustification: string (REQUIRED when testStrategy is "no-test" \u2014 explain why tests are unnecessary)
|
|
3325
3326
|
|
|
3326
3327
|
${COMPLEXITY_GUIDE}
|
|
3327
3328
|
|
|
@@ -21122,7 +21123,7 @@ async function loadConfigForWorkdir(rootConfigPath, packageDir) {
|
|
|
21122
21123
|
return rootConfig;
|
|
21123
21124
|
}
|
|
21124
21125
|
const repoRoot = dirname2(rootNaxDir);
|
|
21125
|
-
const packageConfigPath = join7(repoRoot, PROJECT_NAX_DIR, "
|
|
21126
|
+
const packageConfigPath = join7(repoRoot, PROJECT_NAX_DIR, "mono", packageDir, "config.json");
|
|
21126
21127
|
const packageOverride = await loadJsonFile(packageConfigPath, "config");
|
|
21127
21128
|
if (!packageOverride) {
|
|
21128
21129
|
return rootConfig;
|
|
@@ -22398,7 +22399,7 @@ var package_default;
|
|
|
22398
22399
|
var init_package = __esm(() => {
|
|
22399
22400
|
package_default = {
|
|
22400
22401
|
name: "@nathapp/nax",
|
|
22401
|
-
version: "0.51.
|
|
22402
|
+
version: "0.51.2",
|
|
22402
22403
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
22403
22404
|
type: "module",
|
|
22404
22405
|
bin: {
|
|
@@ -22470,8 +22471,8 @@ var init_version = __esm(() => {
|
|
|
22470
22471
|
NAX_VERSION = package_default.version;
|
|
22471
22472
|
NAX_COMMIT = (() => {
|
|
22472
22473
|
try {
|
|
22473
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
22474
|
-
return "
|
|
22474
|
+
if (/^[0-9a-f]{6,10}$/.test("7f71f43"))
|
|
22475
|
+
return "7f71f43";
|
|
22475
22476
|
} catch {}
|
|
22476
22477
|
try {
|
|
22477
22478
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -30553,7 +30554,7 @@ function generatePackageContextTemplate(packagePath) {
|
|
|
30553
30554
|
}
|
|
30554
30555
|
async function initPackage(repoRoot, packagePath, force = false) {
|
|
30555
30556
|
const logger = getLogger();
|
|
30556
|
-
const naxDir = join31(repoRoot, ".nax", "
|
|
30557
|
+
const naxDir = join31(repoRoot, ".nax", "mono", packagePath);
|
|
30557
30558
|
const contextPath = join31(naxDir, "context.md");
|
|
30558
30559
|
if (existsSync20(contextPath) && !force) {
|
|
30559
30560
|
logger.info("init", "Package context.md already exists (use --force to overwrite)", { path: contextPath });
|
|
@@ -67582,10 +67583,10 @@ async function generateAll(options, config2, agentFilter) {
|
|
|
67582
67583
|
async function discoverPackages(repoRoot) {
|
|
67583
67584
|
const packages = [];
|
|
67584
67585
|
const seen = new Set;
|
|
67585
|
-
for (const pattern of [".nax/
|
|
67586
|
+
for (const pattern of [".nax/mono/*/context.md", ".nax/mono/*/*/context.md"]) {
|
|
67586
67587
|
const glob = new Bun.Glob(pattern);
|
|
67587
67588
|
for await (const match of glob.scan({ cwd: repoRoot, dot: true })) {
|
|
67588
|
-
const pkgRelative = match.replace(/^\.nax\/
|
|
67589
|
+
const pkgRelative = match.replace(/^\.nax\/mono\//, "").replace(/\/context\.md$/, "");
|
|
67589
67590
|
const pkgAbsolute = join11(repoRoot, pkgRelative);
|
|
67590
67591
|
if (!seen.has(pkgAbsolute)) {
|
|
67591
67592
|
seen.add(pkgAbsolute);
|
|
@@ -68192,7 +68193,8 @@ Generate a JSON object with this exact structure (no markdown, no explanation \u
|
|
|
68192
68193
|
"passes": false,
|
|
68193
68194
|
"routing": {
|
|
68194
68195
|
"complexity": "simple | medium | complex | expert",
|
|
68195
|
-
"testStrategy": "tdd-simple | three-session-tdd-lite | three-session-tdd | test-after",
|
|
68196
|
+
"testStrategy": "no-test | tdd-simple | three-session-tdd-lite | three-session-tdd | test-after",
|
|
68197
|
+
"noTestJustification": "string \u2014 REQUIRED when testStrategy is no-test, explains why tests are unnecessary",
|
|
68196
68198
|
"reasoning": "string \u2014 brief classification rationale"
|
|
68197
68199
|
},
|
|
68198
68200
|
"escalations": [],
|
|
@@ -69569,10 +69571,10 @@ async function generateCommand(options) {
|
|
|
69569
69571
|
if (dryRun) {
|
|
69570
69572
|
console.log(source_default.yellow("\u26A0 Dry run \u2014 no files will be written"));
|
|
69571
69573
|
}
|
|
69572
|
-
console.log(source_default.blue("\u2192 Discovering packages with .nax/
|
|
69574
|
+
console.log(source_default.blue("\u2192 Discovering packages with .nax/mono/*/context.md..."));
|
|
69573
69575
|
const packages = await discoverPackages(workdir);
|
|
69574
69576
|
if (packages.length === 0) {
|
|
69575
|
-
console.log(source_default.yellow(" No packages found (no .nax/
|
|
69577
|
+
console.log(source_default.yellow(" No packages found (no .nax/mono/*/context.md or .nax/mono/*/*/context.md)"));
|
|
69576
69578
|
return;
|
|
69577
69579
|
}
|
|
69578
69580
|
console.log(source_default.blue(`\u2192 Generating agent files for ${packages.length} package(s)...`));
|
|
@@ -78850,26 +78852,34 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
78850
78852
|
|
|
78851
78853
|
## Overview
|
|
78852
78854
|
|
|
78853
|
-
|
|
78855
|
+
<!-- One paragraph describing what this feature does and why it's needed. -->
|
|
78854
78856
|
|
|
78855
|
-
##
|
|
78856
|
-
`);
|
|
78857
|
-
await Bun.write(join53(featureDir, "plan.md"), `# Plan: ${name}
|
|
78857
|
+
## Background / Context
|
|
78858
78858
|
|
|
78859
|
-
|
|
78859
|
+
<!-- Optional: relevant background, existing behaviour, or constraints. -->
|
|
78860
78860
|
|
|
78861
|
-
##
|
|
78861
|
+
## User Stories
|
|
78862
78862
|
|
|
78863
|
-
|
|
78864
|
-
|
|
78865
|
-
await Bun.write(join53(featureDir, "tasks.md"), `# Tasks: ${name}
|
|
78863
|
+
<!-- Describe what users need. Each story becomes a unit of work for nax.
|
|
78864
|
+
Be specific \u2014 the more detail here, the better the generated plan. -->
|
|
78866
78865
|
|
|
78867
|
-
|
|
78866
|
+
- As a [user], I want to [goal] so that [benefit].
|
|
78868
78867
|
|
|
78869
|
-
|
|
78868
|
+
## Technical Requirements
|
|
78870
78869
|
|
|
78871
|
-
|
|
78872
|
-
|
|
78870
|
+
<!-- Optional: specific technical constraints, patterns to follow, APIs to use, etc. -->
|
|
78871
|
+
|
|
78872
|
+
## Acceptance Criteria
|
|
78873
|
+
|
|
78874
|
+
<!-- These are parsed by nax to generate acceptance tests.
|
|
78875
|
+
Use clear, testable statements. Each criterion = one AC test. -->
|
|
78876
|
+
|
|
78877
|
+
- [ ] [Describe observable outcome 1]
|
|
78878
|
+
- [ ] [Describe observable outcome 2]
|
|
78879
|
+
|
|
78880
|
+
## Out of Scope
|
|
78881
|
+
|
|
78882
|
+
<!-- What this feature explicitly does NOT cover. -->
|
|
78873
78883
|
`);
|
|
78874
78884
|
await Bun.write(join53(featureDir, "progress.txt"), `# Progress: ${name}
|
|
78875
78885
|
|
|
@@ -78880,11 +78890,9 @@ Created: ${new Date().toISOString()}
|
|
|
78880
78890
|
console.log(source_default.green(`\u2705 Created feature: ${name}`));
|
|
78881
78891
|
console.log(source_default.dim(` ${featureDir}/`));
|
|
78882
78892
|
console.log(source_default.dim(" \u251C\u2500\u2500 spec.md"));
|
|
78883
|
-
console.log(source_default.dim(" \u251C\u2500\u2500 plan.md"));
|
|
78884
|
-
console.log(source_default.dim(" \u251C\u2500\u2500 tasks.md"));
|
|
78885
78893
|
console.log(source_default.dim(" \u2514\u2500\u2500 progress.txt"));
|
|
78886
78894
|
console.log(source_default.dim(`
|
|
78887
|
-
Next: Edit spec.md
|
|
78895
|
+
Next: Edit spec.md, then: nax plan -f ${name} --from spec.md --auto`));
|
|
78888
78896
|
});
|
|
78889
78897
|
features.command("list").description("List all features").option("-d, --dir <path>", "Project directory", process.cwd()).action(async (options) => {
|
|
78890
78898
|
let workdir;
|