@navels/neal 0.1.0 → 0.3.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 (120) hide show
  1. package/README.md +206 -209
  2. package/SECURITY.md +16 -19
  3. package/dist/neal/adjudicator/{blocked-adjudicator.js → consultant.js} +21 -21
  4. package/dist/neal/adjudicator/execute.js +33 -33
  5. package/dist/neal/adjudicator/final-completion.js +2 -31
  6. package/dist/neal/adjudicator/planning.js +264 -24
  7. package/dist/neal/agents/prompts.js +7 -15
  8. package/dist/neal/agents/rounds.js +51 -73
  9. package/dist/neal/agents/schemas.js +615 -502
  10. package/dist/neal/agents/structured-json.js +36 -0
  11. package/dist/neal/blocked-guidance.js +16 -9
  12. package/dist/neal/cli.js +2 -2
  13. package/dist/neal/commands/check.js +2 -2
  14. package/dist/neal/commands/compat.js +100 -36
  15. package/dist/neal/commands/interactive-activity.js +2 -2
  16. package/dist/neal/commands/recovery-guidance.js +20 -8
  17. package/dist/neal/commands/runtime.js +4 -2
  18. package/dist/neal/config.js +40 -7
  19. package/dist/neal/context/inline-review-context.js +13 -28
  20. package/dist/neal/context/reviewer-context.js +19 -14
  21. package/dist/neal/eval/reviewer-eval-manifest.js +86 -0
  22. package/dist/neal/eval/reviewer-eval.js +155 -0
  23. package/dist/neal/git.js +9 -3
  24. package/dist/neal/interactive-controls.js +5 -0
  25. package/dist/neal/orchestrator/completion.js +215 -113
  26. package/dist/neal/orchestrator/failures.js +7 -0
  27. package/dist/neal/orchestrator/notifications.js +9 -9
  28. package/dist/neal/orchestrator/phases/planning.js +124 -112
  29. package/dist/neal/orchestrator/phases/recovery.js +151 -115
  30. package/dist/neal/orchestrator/phases/review.js +28 -1
  31. package/dist/neal/orchestrator/split-plan.js +12 -11
  32. package/dist/neal/orchestrator/transitions.js +36 -71
  33. package/dist/neal/orchestrator.js +3 -0
  34. package/dist/neal/plan-doc.js +24 -1
  35. package/dist/neal/plan-queue.js +29 -1
  36. package/dist/neal/prompts/assert-builder.js +8 -1
  37. package/dist/neal/prompts/execute.js +11 -19
  38. package/dist/neal/prompts/planning.js +64 -55
  39. package/dist/neal/prompts/review-doctrine.js +13 -50
  40. package/dist/neal/prompts/specialized.js +28 -22
  41. package/dist/neal/prompts/specs.js +223 -17
  42. package/dist/neal/providers/agent-settings-isolation.js +35 -0
  43. package/dist/neal/providers/anthropic-claude.js +309 -248
  44. package/dist/neal/providers/detection.js +3 -7
  45. package/dist/neal/providers/git-config-isolation.js +83 -0
  46. package/dist/neal/providers/openai-codex.js +102 -204
  47. package/dist/neal/providers/{generic-agentic-tools.js → openai-compatible-tools.js} +11 -5
  48. package/dist/neal/providers/openai-compatible.js +1079 -403
  49. package/dist/neal/providers/openrouter-routing.js +68 -0
  50. package/dist/neal/providers/pricing.js +124 -0
  51. package/dist/neal/providers/rate-card.js +2275 -0
  52. package/dist/neal/providers/registry.js +6 -17
  53. package/dist/neal/providers/telemetry.js +4 -0
  54. package/dist/neal/providers/types.js +12 -0
  55. package/dist/neal/resume-decision.js +7 -6
  56. package/dist/neal/resume-planner.js +9 -0
  57. package/dist/neal/retrospective.js +36 -7
  58. package/dist/neal/review-debt.js +30 -0
  59. package/dist/neal/review-findings/provider.js +17 -29
  60. package/dist/neal/review.js +17 -1
  61. package/dist/neal/run-metrics.js +74 -9
  62. package/dist/neal/state-invariants.js +11 -3
  63. package/dist/neal/state-views.js +27 -5
  64. package/dist/neal/state.js +59 -15
  65. package/dist/neal/status.js +28 -1
  66. package/dist/neal/support.js +3 -3
  67. package/docs/README.md +22 -18
  68. package/docs/{ADJUDICATOR_INVENTORY.md → adjudicator-inventory.md} +58 -57
  69. package/docs/architecture.md +79 -83
  70. package/docs/automation.md +11 -11
  71. package/docs/compat.md +91 -61
  72. package/docs/compatible-models.md +145 -110
  73. package/docs/demo.md +15 -5
  74. package/docs/maintenance.md +74 -32
  75. package/docs/plan-format.md +61 -33
  76. package/docs/prompt-evals.md +96 -0
  77. package/docs/{PROMPT_SPECS.md → prompt-specs.md} +52 -48
  78. package/docs/providers.md +330 -283
  79. package/docs/release.md +43 -40
  80. package/docs/review-convergence.md +246 -0
  81. package/docs/state-machine.md +61 -59
  82. package/docs/storage.md +40 -31
  83. package/docs/troubleshooting.md +32 -29
  84. package/examples/compat/add-edit-verify/PLAN.md +2 -0
  85. package/examples/compat/add-edit-verify/broken.diff +2 -2
  86. package/examples/compat/add-edit-verify/good.diff +2 -2
  87. package/examples/compat/add-edit-verify/src/add.js +1 -1
  88. package/examples/compat/manifest.json +25 -29
  89. package/examples/compat/sum-grep-edit/PLAN.md +33 -0
  90. package/examples/compat/sum-grep-edit/broken.diff +12 -0
  91. package/examples/compat/sum-grep-edit/good.diff +12 -0
  92. package/examples/compat/sum-grep-edit/package.json +5 -0
  93. package/examples/compat/sum-grep-edit/src/numbers.js +9 -0
  94. package/examples/compat/sum-grep-edit/test/numbers.test.js +15 -0
  95. package/examples/issue-triage-js/README.md +0 -15
  96. package/examples/reviewer-eval/clean-doc/base/src/clamp.ts +3 -0
  97. package/examples/reviewer-eval/clean-doc/change.diff +9 -0
  98. package/examples/reviewer-eval/clean-extract/base/src/greet.ts +3 -0
  99. package/examples/reviewer-eval/clean-extract/change.diff +13 -0
  100. package/examples/reviewer-eval/dropped-error/base/src/load.ts +4 -0
  101. package/examples/reviewer-eval/dropped-error/change.diff +15 -0
  102. package/examples/reviewer-eval/manifest.json +45 -0
  103. package/examples/reviewer-eval/off-by-one/base/src/paginate.ts +5 -0
  104. package/examples/reviewer-eval/off-by-one/change.diff +11 -0
  105. package/{config.yml → neal.yml} +1 -1
  106. package/package.json +20 -15
  107. package/dist/neal/providers/generic-agentic.js +0 -1238
  108. package/docs/comparison.md +0 -105
  109. package/examples/compat/is-even-add-test/PLAN.md +0 -30
  110. package/examples/compat/is-even-add-test/broken.diff +0 -11
  111. package/examples/compat/is-even-add-test/good.diff +0 -11
  112. package/examples/compat/is-even-add-test/package.json +0 -5
  113. package/examples/compat/is-even-add-test/src/is-even.js +0 -3
  114. package/examples/compat/is-even-add-test/test/is-even.test.js +0 -9
  115. package/examples/compat/reverse-grep-edit/PLAN.md +0 -32
  116. package/examples/compat/reverse-grep-edit/broken.diff +0 -12
  117. package/examples/compat/reverse-grep-edit/good.diff +0 -12
  118. package/examples/compat/reverse-grep-edit/package.json +0 -5
  119. package/examples/compat/reverse-grep-edit/src/strings.js +0 -10
  120. package/examples/compat/reverse-grep-edit/test/strings.test.js +0 -15
@@ -1,105 +0,0 @@
1
- # Why neal instead of X?
2
-
3
- neal is a harness, not an agent. It runs three independent roles — planner,
4
- coder, reviewer — each bound to whatever provider and model you choose
5
- ([providers.md](providers.md)), and drives them with a deterministic state
6
- machine ([architecture.md](architecture.md)) rather than letting a model decide
7
- the control flow. Verdicts are schema-validated structured output, not prose an
8
- orchestrator model interprets. Every run is persisted under `.neal/` and
9
- resumable after a crash ([storage.md](storage.md)). The reviewer is read-only by
10
- construction: the provider registry rejects any reviewer capability that
11
- declares write or shell access, so a reviewer structurally cannot mutate the
12
- repo regardless of prompt. Most alternatives are agents; neal is the loop that
13
- holds agents accountable to a plan.
14
-
15
- ## Claude Code
16
-
17
- What it's great at: interactive, conversational coding with a single very
18
- capable agent. Its subagents delegate work, plan mode gates execution behind an
19
- approved plan, and hooks let you inject your own checks into the tool loop.
20
-
21
- The structural difference: Claude Code is a single-vendor agent product.
22
- Its subagents are prompt-scoped delegates inside one product, sharing a vendor
23
- and orchestrated by a model — the top-level agent decides when to delegate and
24
- how to weigh what comes back. There is no cross-vendor adversarial review: the
25
- judge and the judged are the same vendor, often the same model family. neal is
26
- not a competitor to Claude Code; it is a consumer of it. The `anthropic-claude`
27
- adapter drives Claude Code's SDK as a coder or reviewer, and the common
28
- configuration is exactly the adversarial split Claude Code cannot express:
29
- Codex codes, Claude reviews, and a deterministic orchestrator — not a model —
30
- decides what happens with the verdict.
31
-
32
- Pick Claude Code when the work is exploratory or conversational, when you want
33
- a human in the loop turn by turn, or when you have no plan yet. neal wants a
34
- plan document; Claude Code is a good place to figure one out.
35
-
36
- ## Aider (architect/editor mode)
37
-
38
- What it's great at: fast, terminal-native pair programming. Its
39
- architect/editor mode was an early demonstration that splitting reasoning from
40
- editing across two models improves results.
41
-
42
- The structural difference: Aider's two models cooperate on one change — the
43
- architect proposes, the editor applies — and the control flow between them is
44
- mediated by the models within a chat session. There is no independent reviewer
45
- producing a structured verdict that a state machine acts on, no scoped plan
46
- queue where each scope starts the coder from a fresh context, and continuity is
47
- conversation-shaped rather than a persisted run ledger. neal's roles are
48
- adversarial rather than cooperative: the reviewer judges committed diffs it had
49
- no hand in producing, findings route back to the coder until a schema-validated
50
- accept, and `neal resume` reconstructs an interrupted run from the `.neal/`
51
- ledgers rather than replaying a chat.
52
-
53
- Pick Aider for tight interactive edits where you are the reviewer and the loop
54
- is you. neal earns its overhead on multi-scope work where drift over a long
55
- session is the failure mode.
56
-
57
- ## OpenHands and autonomous agents
58
-
59
- What they're great at: sandboxed, hands-off execution — hand an issue to an
60
- agent in an isolated runtime and come back to a pull request. The sandbox makes
61
- broad autonomy defensible.
62
-
63
- The structural difference: these systems bet on maximizing agent autonomy and
64
- containing it with a sandbox. neal bets the opposite way: local-first execution
65
- in your checkout, a human-authored plan as the contract for what may happen,
66
- and bounded autonomy with structural escalation — blocked states that wait for
67
- `neal resume --message`, manual gates for work only a human can do, and a
68
- bounded adjudicator that resolves a narrow recoverable class and escalates
69
- genuine walls. Even `--unattended` mode only bounds how long neal persists
70
- before failing cleanly; it never widens authorization.
71
-
72
- Pick an autonomous agent when you want isolation and don't need to constrain
73
- the path taken. Pick neal when the plan is the point — when you want to
74
- specify the decomposition, the verification per scope, and the stop conditions,
75
- and have the machine enforce them.
76
-
77
- ## If you just want CI review
78
-
79
- PR-review bots comment on diffs after they reach the forge. neal's review is
80
- inside the loop: every scope's committed diff is judged before the run moves
81
- on, and a final-completion review checks the whole plan before the squash — so
82
- findings are fixed by the same coder in the same run, not triaged later.
83
- `neal review` also works standalone against any committed range, role-symmetric
84
- (the coder provider drafts findings, the read-only reviewer adjudicates them),
85
- local, and provider-agnostic — no forge integration or CI required. The two are
86
- complementary: neal reviews before you push, bots review after.
87
-
88
- ## What neal does not do
89
-
90
- - **No GUI.** neal is a CLI with narrative terminal output; state lives in
91
- files under `.neal/`.
92
- - **No sandbox of its own for the coder.** Writer providers run with broad
93
- local permissions (Codex under `danger-full-access`, Claude under
94
- `bypassPermissions`, the generic writer's `run` tool is unsandboxed shell).
95
- Bring your own isolation — disposable checkout, container, or VM. See
96
- [SECURITY.md](../SECURITY.md).
97
- - **Serial scopes only, today.** Scopes execute one at a time, and `neal run`
98
- queues run plans serially. There is no parallel scope execution.
99
- - **It requires a plan document.** There is no "just fix it" mode — the
100
- authored plan, with its mandatory `## Execution Shape` section
101
- ([plan-format.md](plan-format.md)), is the product's opinion. If writing a
102
- plan feels like overhead, neal is the wrong tool for that task.
103
- - **No provider plugins yet.** Adapters are built-in (`openai-codex`,
104
- `anthropic-claude`, `openai-compatible`, `generic-agentic`); external
105
- provider plugins are future work.
@@ -1,30 +0,0 @@
1
- # Compat fixture: replace the placeholder test
2
-
3
- ## Execution Shape
4
-
5
- executionShape: one_shot
6
-
7
- ## Objective
8
-
9
- `src/is-even.js` exports a correct `isEven(n)` helper. Its test in
10
- `test/is-even.test.js` is only a placeholder that always fails
11
- (`assert.ok(false, ...)`).
12
-
13
- Replace the placeholder assertion with a real test that exercises `isEven` —
14
- asserting `isEven(4)` is `true` is enough — so the test suite passes. Keep the
15
- existing `test(...)` block; only the placeholder assertion needs to change.
16
-
17
- ## Boundaries
18
-
19
- Allowed paths:
20
-
21
- - `test/is-even.test.js`
22
-
23
- Forbidden:
24
-
25
- - Do not edit `src/is-even.js` (it is already correct).
26
- - Do not add dependencies or new files.
27
-
28
- ## Verification
29
-
30
- Run `node --test test/is-even.test.js`; it must exit `0`.
@@ -1,11 +0,0 @@
1
- diff --git a/test/is-even.test.js b/test/is-even.test.js
2
- index 52c2a94..0e9eec5 100644
3
- --- a/test/is-even.test.js
4
- +++ b/test/is-even.test.js
5
- @@ -5,5 +5,5 @@ import { isEven } from '../src/is-even.js';
6
-
7
- test('isEven identifies even numbers', () => {
8
- // TODO: replace this placeholder with a real assertion on isEven.
9
- - assert.ok(false, 'TODO: replace this placeholder with a real test for isEven');
10
- + assert.equal(isEven(4), false);
11
- });
@@ -1,11 +0,0 @@
1
- diff --git a/test/is-even.test.js b/test/is-even.test.js
2
- index 52c2a94..28d1d73 100644
3
- --- a/test/is-even.test.js
4
- +++ b/test/is-even.test.js
5
- @@ -5,5 +5,5 @@ import { isEven } from '../src/is-even.js';
6
-
7
- test('isEven identifies even numbers', () => {
8
- // TODO: replace this placeholder with a real assertion on isEven.
9
- - assert.ok(false, 'TODO: replace this placeholder with a real test for isEven');
10
- + assert.equal(isEven(4), true);
11
- });
@@ -1,5 +0,0 @@
1
- {
2
- "name": "@navels/neal-compat-is-even-add-test",
3
- "private": true,
4
- "type": "module"
5
- }
@@ -1,3 +0,0 @@
1
- // Trivial compat fixture: this helper is already correct. The work is to add a
2
- // real test in place of the placeholder.
3
- export const isEven = (n) => n % 2 === 0;
@@ -1,9 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import test from 'node:test';
3
-
4
- import { isEven } from '../src/is-even.js';
5
-
6
- test('isEven identifies even numbers', () => {
7
- // TODO: replace this placeholder with a real assertion on isEven.
8
- assert.ok(false, 'TODO: replace this placeholder with a real test for isEven');
9
- });
@@ -1,32 +0,0 @@
1
- # Compat fixture: fix the broken string helper
2
-
3
- ## Execution Shape
4
-
5
- executionShape: one_shot
6
-
7
- ## Objective
8
-
9
- `src/strings.js` exports several small string helpers. Exactly one of them is
10
- buggy: `reverse(s)` is supposed to return the string with its characters
11
- reversed, but it returns the string unchanged. The `reverse` test in
12
- `test/strings.test.js` fails because of this.
13
-
14
- Read `src/strings.js`, locate the faulty `reverse` helper, and make the smallest
15
- complete change so it returns the reversed string. Do not touch the other
16
- helpers, which already pass their tests.
17
-
18
- ## Boundaries
19
-
20
- Allowed paths:
21
-
22
- - `src/strings.js`
23
-
24
- Forbidden:
25
-
26
- - Do not edit the test file.
27
- - Do not change the other (already-correct) helpers.
28
- - Do not add dependencies or new files.
29
-
30
- ## Verification
31
-
32
- Run `node --test test/strings.test.js`; it must exit `0`.
@@ -1,12 +0,0 @@
1
- diff --git a/src/strings.js b/src/strings.js
2
- index c338691..fbfe71b 100644
3
- --- a/src/strings.js
4
- +++ b/src/strings.js
5
- @@ -5,6 +5,6 @@ export const upper = (s) => s.toUpperCase();
6
- export const lower = (s) => s.toLowerCase();
7
-
8
- // BUG: this does not actually reverse the string.
9
- -export const reverse = (s) => s.split('').join('');
10
- +export const reverse = (s) => s.split('').join('-');
11
-
12
- export const repeat = (s, n) => s.repeat(n);
@@ -1,12 +0,0 @@
1
- diff --git a/src/strings.js b/src/strings.js
2
- index c338691..d17fc16 100644
3
- --- a/src/strings.js
4
- +++ b/src/strings.js
5
- @@ -5,6 +5,6 @@ export const upper = (s) => s.toUpperCase();
6
- export const lower = (s) => s.toLowerCase();
7
-
8
- // BUG: this does not actually reverse the string.
9
- -export const reverse = (s) => s.split('').join('');
10
- +export const reverse = (s) => s.split('').reverse().join('');
11
-
12
- export const repeat = (s, n) => s.repeat(n);
@@ -1,5 +0,0 @@
1
- {
2
- "name": "@navels/neal-compat-reverse-grep-edit",
3
- "private": true,
4
- "type": "module"
5
- }
@@ -1,10 +0,0 @@
1
- // Trivial compat fixture: several string helpers live here. Exactly one of them
2
- // is buggy, so an agent must read/grep to locate the faulty function.
3
- export const upper = (s) => s.toUpperCase();
4
-
5
- export const lower = (s) => s.toLowerCase();
6
-
7
- // BUG: this does not actually reverse the string.
8
- export const reverse = (s) => s.split('').join('');
9
-
10
- export const repeat = (s, n) => s.repeat(n);
@@ -1,15 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import test from 'node:test';
3
-
4
- import { lower, repeat, reverse, upper } from '../src/strings.js';
5
-
6
- test('upper/lower/repeat helpers are correct', () => {
7
- assert.equal(upper('abc'), 'ABC');
8
- assert.equal(lower('ABC'), 'abc');
9
- assert.equal(repeat('ab', 3), 'ababab');
10
- });
11
-
12
- test('reverse returns the string reversed', () => {
13
- assert.equal(reverse('abc'), 'cba');
14
- assert.equal(reverse('neal'), 'laen');
15
- });