@navels/neal 0.1.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 (170) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +527 -0
  3. package/SECURITY.md +91 -0
  4. package/config.yml +104 -0
  5. package/dist/neal/activity-footer.js +177 -0
  6. package/dist/neal/activity-reporting.js +1 -0
  7. package/dist/neal/adjudicator/artifacts.js +58 -0
  8. package/dist/neal/adjudicator/blocked-adjudicator.js +223 -0
  9. package/dist/neal/adjudicator/contracts.js +139 -0
  10. package/dist/neal/adjudicator/execute.js +611 -0
  11. package/dist/neal/adjudicator/final-completion.js +104 -0
  12. package/dist/neal/adjudicator/planning.js +145 -0
  13. package/dist/neal/adjudicator/specs.js +453 -0
  14. package/dist/neal/agents/prompts.js +120 -0
  15. package/dist/neal/agents/rounds.js +706 -0
  16. package/dist/neal/agents/schemas.js +832 -0
  17. package/dist/neal/agents/structured-coder.js +82 -0
  18. package/dist/neal/agents/structured-json.js +528 -0
  19. package/dist/neal/agents.js +4 -0
  20. package/dist/neal/atomic-write.js +18 -0
  21. package/dist/neal/blocked-guidance.js +406 -0
  22. package/dist/neal/cli.js +471 -0
  23. package/dist/neal/commands/check.js +401 -0
  24. package/dist/neal/commands/compat.js +807 -0
  25. package/dist/neal/commands/interactive-activity.js +57 -0
  26. package/dist/neal/commands/new-run.js +79 -0
  27. package/dist/neal/commands/plan-and-execute.js +44 -0
  28. package/dist/neal/commands/recovery-guidance.js +217 -0
  29. package/dist/neal/commands/resume-run.js +395 -0
  30. package/dist/neal/commands/review.js +21 -0
  31. package/dist/neal/commands/runtime.js +557 -0
  32. package/dist/neal/commands/setup.js +596 -0
  33. package/dist/neal/commands/squash.js +113 -0
  34. package/dist/neal/commands/status.js +33 -0
  35. package/dist/neal/commands/writer-exit-codes.js +42 -0
  36. package/dist/neal/commit-message.js +17 -0
  37. package/dist/neal/config.js +432 -0
  38. package/dist/neal/context/artifacts.js +140 -0
  39. package/dist/neal/context/context.js +324 -0
  40. package/dist/neal/context/inline-review-context.js +131 -0
  41. package/dist/neal/context/reviewer-context.js +166 -0
  42. package/dist/neal/context/shared.js +117 -0
  43. package/dist/neal/context/types.js +1 -0
  44. package/dist/neal/diagnostic.js +208 -0
  45. package/dist/neal/execute-finalization.js +5 -0
  46. package/dist/neal/final-completion-review.js +188 -0
  47. package/dist/neal/final-completion.js +229 -0
  48. package/dist/neal/git.js +339 -0
  49. package/dist/neal/index.js +135 -0
  50. package/dist/neal/interactive-controls.js +85 -0
  51. package/dist/neal/logger.js +102 -0
  52. package/dist/neal/manual-gates.js +121 -0
  53. package/dist/neal/orchestrator/artifacts.js +70 -0
  54. package/dist/neal/orchestrator/completion.js +531 -0
  55. package/dist/neal/orchestrator/failures.js +31 -0
  56. package/dist/neal/orchestrator/notifications.js +175 -0
  57. package/dist/neal/orchestrator/phases/coder.js +516 -0
  58. package/dist/neal/orchestrator/phases/planning.js +540 -0
  59. package/dist/neal/orchestrator/phases/recovery.js +798 -0
  60. package/dist/neal/orchestrator/phases/review.js +136 -0
  61. package/dist/neal/orchestrator/phases/shared.js +279 -0
  62. package/dist/neal/orchestrator/run-loop.js +113 -0
  63. package/dist/neal/orchestrator/split-plan.js +235 -0
  64. package/dist/neal/orchestrator/transitions.js +309 -0
  65. package/dist/neal/orchestrator.js +215 -0
  66. package/dist/neal/phase-display.js +27 -0
  67. package/dist/neal/plan-doc.js +154 -0
  68. package/dist/neal/plan-queue.js +1092 -0
  69. package/dist/neal/plan-refinement.js +39 -0
  70. package/dist/neal/plan-validation.js +525 -0
  71. package/dist/neal/progress.js +237 -0
  72. package/dist/neal/prompts/assert-builder.js +13 -0
  73. package/dist/neal/prompts/execute.js +290 -0
  74. package/dist/neal/prompts/guidance.js +70 -0
  75. package/dist/neal/prompts/planning.js +313 -0
  76. package/dist/neal/prompts/review-doctrine.js +142 -0
  77. package/dist/neal/prompts/shared.js +101 -0
  78. package/dist/neal/prompts/specialized.js +212 -0
  79. package/dist/neal/prompts/specs.js +572 -0
  80. package/dist/neal/providers/anthropic-claude.js +1599 -0
  81. package/dist/neal/providers/detection.js +139 -0
  82. package/dist/neal/providers/generic-agentic-tools.js +586 -0
  83. package/dist/neal/providers/generic-agentic.js +1238 -0
  84. package/dist/neal/providers/liveness.js +151 -0
  85. package/dist/neal/providers/openai-codex.js +1014 -0
  86. package/dist/neal/providers/openai-compatible.js +654 -0
  87. package/dist/neal/providers/registry.js +389 -0
  88. package/dist/neal/providers/telemetry.js +208 -0
  89. package/dist/neal/providers/types.js +21 -0
  90. package/dist/neal/recovery-artifacts.js +50 -0
  91. package/dist/neal/resume-decision.js +220 -0
  92. package/dist/neal/resume-planner.js +265 -0
  93. package/dist/neal/retrospective.js +391 -0
  94. package/dist/neal/review-debt.js +18 -0
  95. package/dist/neal/review-findings/artifacts.js +173 -0
  96. package/dist/neal/review-findings/prompts.js +172 -0
  97. package/dist/neal/review-findings/provider.js +330 -0
  98. package/dist/neal/review-findings/run.js +373 -0
  99. package/dist/neal/review-findings/types.js +1 -0
  100. package/dist/neal/review-mode.js +67 -0
  101. package/dist/neal/review.js +137 -0
  102. package/dist/neal/run-lock.js +334 -0
  103. package/dist/neal/run-metrics.js +355 -0
  104. package/dist/neal/run-narrative-types.js +1 -0
  105. package/dist/neal/run-narrative.js +1374 -0
  106. package/dist/neal/run-registry.js +218 -0
  107. package/dist/neal/run-status.js +25 -0
  108. package/dist/neal/scopes.js +451 -0
  109. package/dist/neal/sensitive-text.js +8 -0
  110. package/dist/neal/squash-message.js +379 -0
  111. package/dist/neal/squash.js +591 -0
  112. package/dist/neal/state-invariants.js +496 -0
  113. package/dist/neal/state-views.js +344 -0
  114. package/dist/neal/state.js +887 -0
  115. package/dist/neal/status-footer.js +258 -0
  116. package/dist/neal/status.js +1260 -0
  117. package/dist/neal/storage-paths.js +57 -0
  118. package/dist/neal/support.js +58 -0
  119. package/dist/neal/terminal-narrator.js +435 -0
  120. package/dist/neal/types.js +1 -0
  121. package/dist/neal/verification-events.js +81 -0
  122. package/dist/neal/version.js +37 -0
  123. package/dist/neal/worktree-status.js +137 -0
  124. package/dist/notifier.js +44 -0
  125. package/docs/ADJUDICATOR_INVENTORY.md +310 -0
  126. package/docs/PROMPT_SPECS.md +266 -0
  127. package/docs/README.md +22 -0
  128. package/docs/architecture.md +113 -0
  129. package/docs/assets/neal-execution-flow.png +0 -0
  130. package/docs/automation.md +65 -0
  131. package/docs/comparison.md +105 -0
  132. package/docs/compat.md +269 -0
  133. package/docs/compatible-models.md +135 -0
  134. package/docs/demo.md +55 -0
  135. package/docs/maintenance.md +64 -0
  136. package/docs/plan-format.md +213 -0
  137. package/docs/providers.md +751 -0
  138. package/docs/release.md +147 -0
  139. package/docs/state-machine.md +266 -0
  140. package/docs/storage.md +207 -0
  141. package/docs/troubleshooting.md +152 -0
  142. package/examples/compat/add-edit-verify/PLAN.md +29 -0
  143. package/examples/compat/add-edit-verify/broken.diff +8 -0
  144. package/examples/compat/add-edit-verify/good.diff +8 -0
  145. package/examples/compat/add-edit-verify/package.json +5 -0
  146. package/examples/compat/add-edit-verify/src/add.js +2 -0
  147. package/examples/compat/add-edit-verify/test/add.test.js +9 -0
  148. package/examples/compat/is-even-add-test/PLAN.md +30 -0
  149. package/examples/compat/is-even-add-test/broken.diff +11 -0
  150. package/examples/compat/is-even-add-test/good.diff +11 -0
  151. package/examples/compat/is-even-add-test/package.json +5 -0
  152. package/examples/compat/is-even-add-test/src/is-even.js +3 -0
  153. package/examples/compat/is-even-add-test/test/is-even.test.js +9 -0
  154. package/examples/compat/manifest.json +60 -0
  155. package/examples/compat/plan-greeting/ISSUE.md +25 -0
  156. package/examples/compat/plan-greeting/package.json +5 -0
  157. package/examples/compat/plan-greeting/src/greet.js +2 -0
  158. package/examples/compat/plan-greeting/test/greet.test.js +8 -0
  159. package/examples/compat/reverse-grep-edit/PLAN.md +32 -0
  160. package/examples/compat/reverse-grep-edit/broken.diff +12 -0
  161. package/examples/compat/reverse-grep-edit/good.diff +12 -0
  162. package/examples/compat/reverse-grep-edit/package.json +5 -0
  163. package/examples/compat/reverse-grep-edit/src/strings.js +10 -0
  164. package/examples/compat/reverse-grep-edit/test/strings.test.js +15 -0
  165. package/examples/issue-triage-js/PLAN.md +83 -0
  166. package/examples/issue-triage-js/README.md +76 -0
  167. package/examples/issue-triage-js/package.json +9 -0
  168. package/examples/issue-triage-js/src/issue-triage.js +87 -0
  169. package/examples/issue-triage-js/test/issue-triage.test.js +107 -0
  170. package/package.json +70 -0
@@ -0,0 +1,147 @@
1
+ # Release Process
2
+
3
+ This is the canonical tracked release guide for Neal. Releases are manual,
4
+ versioned npm operations. Normal CI remains verification-only for pushes and
5
+ pull requests; publishing is isolated to the GitHub Actions `Publish` workflow,
6
+ which is triggered manually with `workflow_dispatch`.
7
+
8
+ ## Versioning Policy
9
+
10
+ Neal uses Semantic Versioning. `package.json.version` changes only in an
11
+ intentional release-preparation pull request, not in ordinary implementation
12
+ commits. Release versions are exact SemVer strings without a leading `v`, and
13
+ an npm version must never be reused.
14
+
15
+ Before `1.0.0`, minor releases may include meaningful behavior changes while
16
+ the CLI, configuration, exit-code, and artifact contracts settle. After
17
+ `1.0.0`, breaking changes to documented CLI commands, flags, configuration,
18
+ exit codes, or durable run artifacts require a major version.
19
+
20
+ Examples:
21
+
22
+ - Patch: `0.1.1` fixes a defect or compatibility issue without intentionally
23
+ changing documented behavior.
24
+ - Minor before `1.0.0`: `0.2.0` adds a feature or meaningful behavior change
25
+ while the public contract is still settling.
26
+ - Major: `1.0.0` establishes the stable public contract; later breaking
27
+ contract changes require `2.0.0`, `3.0.0`, and so on.
28
+
29
+ ## SDK Dependency Policy
30
+
31
+ Direct coding-agent and AI SDK runtime dependencies must use exact SemVer specs
32
+ in `package.json`. Do not use `latest`, caret ranges, tilde ranges, wildcards,
33
+ workspace specs, file specs, or link specs for these direct dependencies in a
34
+ published CLI package:
35
+
36
+ - `@anthropic-ai/claude-agent-sdk`
37
+ - `@openai/codex-sdk`
38
+ - `ai`
39
+ - `@ai-sdk/openai-compatible`
40
+ - `zod`
41
+
42
+ An SDK update should land as a normal dependency pull request that updates both
43
+ `package.json` and `pnpm-lock.yaml`, runs normal CI, and records any provider
44
+ compatibility findings. The resulting Neal release should match the user-facing
45
+ impact: use a patch release for a compatibility fix that preserves documented
46
+ behavior, a minor release for behavior changes before `1.0.0`, and a major
47
+ release after `1.0.0` if a documented public contract breaks.
48
+
49
+ ## Local Release Readiness
50
+
51
+ Prepare a release with a normal pull request that changes `package.json.version`
52
+ to the intended exact SemVer version:
53
+
54
+ ```sh
55
+ pnpm version <version> --no-git-tag-version
56
+ ```
57
+
58
+ Run the local release-readiness gates from the repository root:
59
+
60
+ ```sh
61
+ RELEASE_VERSION=<version> RELEASE_DRY_RUN=true pnpm run validate:release
62
+ pnpm typecheck
63
+ pnpm test
64
+ pnpm build
65
+ node scripts/verify-package.mjs
66
+ ```
67
+
68
+ `validate:release` checks that the workflow input version matches
69
+ `package.json.version`, validates required package metadata, checks npm version
70
+ availability, and checks remote `v<version>` tag availability when an `origin`
71
+ remote is configured. Package verification confirms the built CLI and packed
72
+ tarball.
73
+
74
+ ## Manual Publish Workflow
75
+
76
+ After the release-preparation pull request is merged and normal CI passes, run
77
+ the `Publish` workflow manually from `main` with:
78
+
79
+ - `version`: the exact `package.json.version`, without a leading `v`
80
+ - `dry_run`: `true`
81
+
82
+ The workflow is guarded to `refs/heads/main`, uses the `npm-publish`
83
+ environment, grants `contents: read` and `id-token: write`, installs with
84
+ `pnpm install --frozen-lockfile`, and runs these gates before any publish step:
85
+
86
+ ```sh
87
+ RELEASE_VERSION=<version> RELEASE_DRY_RUN=<dry_run> pnpm run validate:release
88
+ pnpm typecheck
89
+ pnpm test
90
+ pnpm build
91
+ node scripts/verify-package.mjs
92
+ ```
93
+
94
+ Review the dry-run result before any real publish. Run `Publish` again with
95
+ `dry_run: false` only when a first-publish or later release-preparation plan has
96
+ explicitly authorized the real publish.
97
+
98
+ ## First-Publish Boundary
99
+
100
+ `@navels/neal` is not yet published to the npm registry. Local validation and
101
+ the workflow run dry-run release checks, including `npm publish --dry-run
102
+ --access public`. A real public publish (`npm publish --access public`) happens
103
+ only on the `dry_run: false` path, under the configured npm trusted publishing
104
+ and an explicit authorization from a first-publish or later release-preparation
105
+ plan.
106
+
107
+ ## Trusted Publishing Setup
108
+
109
+ The publish workflow relies on trusted publishing/OIDC and intentionally has no
110
+ npm-token fallback. It grants `id-token: write` for OIDC, keeps repository
111
+ contents read-only, uses the `npm-publish` GitHub environment, and publishes
112
+ with `npm publish --access public` only on the real-publish path.
113
+
114
+ Use this npm CLI setup command as the trusted publisher reference:
115
+
116
+ ```sh
117
+ npm install -g npm@^11.10.0
118
+ npm trust github @navels/neal --repo navels/neal --file publish.yml --env npm-publish --allow-publish
119
+ ```
120
+
121
+ Current first-publish limitation: `@navels/neal` is not currently published, and
122
+ the `npm trust github` command may be blocked until the package already exists
123
+ on the npm registry. The npm trusted publisher configuration must match the
124
+ repository workflow: package `@navels/neal`, owner/repo `navels/neal`, workflow
125
+ filename `publish.yml`, environment `npm-publish`, and allowed action
126
+ `npm publish`.
127
+
128
+ ## Release Boundaries
129
+
130
+ The current workflow checks that the remote `v<version>` tag is available, but
131
+ it does not create tags or GitHub releases. Do not promise or perform release
132
+ marker creation as part of the current publish workflow. If tags or GitHub
133
+ releases are needed after a successful publish, add them in a separate plan with
134
+ the required permissions and explicit operator approval.
135
+
136
+ Recovery rule for later real publishes: if `npm publish` succeeds but a later
137
+ release-marker step fails in a separate plan, do not rerun the publish blindly.
138
+ First confirm the npm version exists, then create only the missing marker.
139
+
140
+ Official references:
141
+
142
+ - GitHub `workflow_dispatch` inputs:
143
+ <https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/trigger-a-workflow>
144
+ - npm trusted publishing:
145
+ <https://docs.npmjs.com/trusted-publishers/>
146
+ - npm trust command:
147
+ <https://docs.npmjs.com/cli/v11/commands/npm-trust/>
@@ -0,0 +1,266 @@
1
+ # Neal State Machine
2
+
3
+ The product-level storage layout, artifact classifications, run pointers,
4
+ retention guidance, and no-global-index decision are documented in
5
+ [storage.md](storage.md). This document focuses on the persisted ledgers and the
6
+ state invariants Neal enforces when reading and writing them.
7
+
8
+ Neal keeps two persisted ledgers:
9
+
10
+ - `OrchestrationState` is the child-run ledger. It lives in each run directory as `RUN_STATE.json` and records one plan or execute writer run.
11
+ - `PlanAndExecuteQueueState` is the parent queue ledger. It lives under `.neal/queues/<queue-id>/QUEUE_STATE.json` and tracks serial `neal run` children, their active stage, child run ids, and queue-level stop status.
12
+
13
+ These ledgers are related but separate. A queue item points at child run state paths; child runs do not own the queue's status, item ordering, or current queue pointer.
14
+
15
+ ## Hydration And Validation
16
+
17
+ `src/neal/state.ts` owns v1 child-run hydration. It reads JSON, checks the basic shape, requires the current v1 fields Neal writes, and rejects unknown enum-like strings while hydrating phase references. Missing or malformed required child-run fields fail load instead of receiving invented defaults.
18
+
19
+ `src/neal/state-invariants.ts` owns semantic validation after hydration and before save. `assertValidOrchestrationState` is pure: it has no filesystem, git, provider, logger, or clock dependency. The same invariant layer runs when `loadState` returns hydrated state and when `saveState` builds the timestamped next state.
20
+
21
+ Queue state has its own parser and invariants in `src/neal/plan-queue.ts`, centered on `parsePlanAndExecuteQueueState` and related queue item parsing helpers.
22
+
23
+ ## Schema Versions
24
+
25
+ Persisted JSON that Neal reads as durable schema is versioned at v1.
26
+ `RUN_STATE.json` hydrates through `normalizeStateV1`; `.neal/current.json`,
27
+ queue state, `.neal/current-queue.json`, queue child links, run narratives,
28
+ squash audit results, and the active writer lock all have v1 write shapes or
29
+ parsers.
30
+
31
+ Run `meta.json` is support data, not child-run state. Optional context artifacts
32
+ such as `plan-progress.json` are written as v1 and read defensively so malformed
33
+ or unsupported support data does not replace the canonical run ledger.
34
+
35
+ ## State Views And Public Lifecycle
36
+
37
+ Persisted v1 child-run state remains record-shaped, but most callers should not
38
+ treat `OrchestrationState` as one large nullable programming model.
39
+ `src/neal/state-views.ts` exposes typed views over the current v1 fields without
40
+ changing the stored JSON shape:
41
+
42
+ - shared metadata and public lifecycle views
43
+ - plan and execute run views
44
+ - interactive blocked-recovery views
45
+ - derived-plan and final-completion views
46
+
47
+ The public lifecycle view treats `status` as the product-facing lifecycle owner
48
+ and treats `phase` as an internal runnable cursor or diagnostic detail.
49
+ `src/neal/run-status.ts` and status rendering build on that lifecycle view so
50
+ human output can say `waiting_for_guidance`, `paused`, `blocked`, `failed`, or
51
+ `done` without requiring users to interpret raw phase names.
52
+
53
+ `neal status --json` remains the stable automation surface. It still exposes raw
54
+ `phase` and `status` fields for diagnostics, and it preserves derived public
55
+ fields such as `effectiveStatus`, `waitingForOperatorGuidance`, and
56
+ `pendingOperatorGuidance`.
57
+
58
+ ## Phase And Status
59
+
60
+ Known child-run phases and statuses are centralized in `state-invariants.ts` through `ORCHESTRATION_PHASES`, `ORCHESTRATION_STATUSES`, and their runtime guard helpers. Runnable dispatch is authored in `src/neal/orchestrator/run-loop.ts` as purpose-specific registries for plan, execute, interactive recovery, and execute finalization phases. Those registries are composed into `RUNNABLE_PHASE_REGISTRY` for dispatch and exposed through top-level-mode helpers so tests can assert which phases are runnable for plan and execute runs.
61
+
62
+ The enforced phase/status relationship is intentionally small:
63
+
64
+ - `phase === 'done'` if and only if `status === 'done'`.
65
+ - `phase === 'blocked'` may use `status === 'blocked'` or `status === 'failed'`.
66
+ - `status === 'running'` is invalid with terminal `done` or `blocked` phases.
67
+ - Failed states may preserve the phase that failed, because provider, reviewer, coder, or artifact errors are useful to resume and diagnostic tooling only when the failing phase remains visible.
68
+
69
+ Read-only `neal review` is not a writer-run mode. It writes isolated findings artifacts under `.neal/reviews/<review-id>/` and does not create `OrchestrationState`.
70
+
71
+ ## Recovery State
72
+
73
+ Interactive blocked recovery is owned by `interactiveBlockedRecovery` while the active phase is `interactive_blocked_recovery`. The invariant layer validates execute-mode ownership, supported source phases, bounded turn counters, contiguous turn numbers, and disposition result phases.
74
+
75
+ Every block class — coder-blocked signals, reviewer `review_stuck` deadlocks, and
76
+ the split-plan invalid-payload block — funnels through the single
77
+ `enterInteractiveBlockedRecovery` chokepoint, where the generalized blocked
78
+ adjudicator triages it (see Site A below). The adjudicator is read-only: it never
79
+ grants authorization, expands scope, or waives verification gates. Its verdict
80
+ auto-acts only under unattended runs; attended runs surface it as advice and yield.
81
+
82
+ Public resume eligibility is classified by `src/neal/resume-decision.ts` before
83
+ any recovery mutation. That read-only decision layer combines loaded child-run
84
+ state with lock, queue, and retrospective evidence, then returns the shared
85
+ vocabulary used by `neal resume`, `neal status`, and run narratives: continue,
86
+ needs message, pending message, already running, done, or cannot resume.
87
+
88
+ Blocked resume eligibility still depends on the planner actions from
89
+ `src/neal/resume-planner.ts`, with the orchestrator recovery code applying the
90
+ selected actions only after the selected run has been classified as executable.
91
+ `state-invariants.ts` mirrors the allowed phase sets so changes to recovery
92
+ behavior are visible in focused tests.
93
+
94
+ ## Unattended Mode
95
+
96
+ `--unattended` / `agent.unattended` resolves to a persisted
97
+ `OrchestrationState.unattended` boolean (default `false`) for both plan and
98
+ execute top-level modes, so a separate `neal resume` process and the `neal run`
99
+ plan→execute hand-off see it without re-passing a flag. The flag overrides the
100
+ config key. The resolved value is also threaded into the planner, reviewer,
101
+ coder, final-completion, and plan-reviewer prompts, where it adds one autonomy
102
+ line only when true; with `unattended` false the rendered prompts are
103
+ byte-identical to attended output.
104
+
105
+ Unattended changes only the three structural operator-block sites; it never
106
+ weakens verification, authorization, or squash/grading, and never removes
107
+ `block_for_operator` from any decision surface. Every unattended branch gates on
108
+ structural state (`state.unattended`, `actionResolution.effectiveAction`,
109
+ `phase`, `blockedFromPhase`, the bounded auto-resume counter), never on
110
+ substring-matching assistant or guidance text.
111
+
112
+ - **Site A — execute-mode interactive recovery.** All fresh blocks funnel
113
+ through `enterInteractiveBlockedRecovery` (`src/neal/orchestrator/phases/recovery.ts`).
114
+ Under unattended, while `unattendedAutoResumeCount < UNATTENDED_MAX_AUTO_RESUMES`
115
+ (a module constant, reconciled so it never pushes past
116
+ `interactiveBlockedRecovery.maxTurns`), it appends a synthesized conservative
117
+ guidance turn (`UNATTENDED_AUTO_RESUME_GUIDANCE` from
118
+ `src/neal/blocked-guidance.ts`) via the same turn-recording helper a human
119
+ message uses, increments the persisted counter, and lets the run proceed into
120
+ the recovery phase. Past the cap (or the `maxTurns` boundary) it runs the
121
+ shared terminal-fail action instead of waiting.
122
+ - **Generalized blocked adjudicator (bounded, both modes).** Inside
123
+ `enterInteractiveBlockedRecovery`, *before* the generic auto-resume / yield
124
+ decision, eligible blocks are triaged by a read-only adjudicator
125
+ (`runBlockedAdjudicator`, in `src/neal/adjudicator/blocked-adjudicator.ts`,
126
+ running through the same no-write reviewer plumbing the review/final-completion
127
+ reviewers use, making zero commits and zero file edits). Eligible source phases
128
+ (`ADJUDICATOR_ELIGIBLE_SOURCE_PHASES`) are the coder-block phases (`coder_scope`
129
+ / `coder_response` / `coder_optional_response`, which also carry the split-plan
130
+ invalid-payload block) and the reviewer `review_stuck` phases (`reviewer_scope` /
131
+ `reviewer_plan`). The adjudicator first applies an anti-thrash guard
132
+ (`recentBlocks`, keyed on scope identity + source phase + normalized blocker key +
133
+ evidence fingerprint): a same-scope repeat with no new evidence short-circuits to
134
+ `recoverable:false` without an LLM round. Otherwise it returns a verdict
135
+ `{ recoverable, triageCategory, resolutionDirective, rationale }`. Under
136
+ unattended, a `recoverable` `misunderstanding` verdict with a concrete in-scope
137
+ directive enters recovery with that directive injected as the pending turn
138
+ (consumed exactly like a human `neal resume --message`); a `recoverable:false`
139
+ genuine wall (`authorization` / `external_precondition` / `impossible_task`) runs
140
+ the shared terminal-fail action. Under attended, the same gated adjudicator runs
141
+ read-only, persists its verdict as `interactiveBlockedRecovery.adjudicatorAdvice`,
142
+ and the run yields for the operator (no auto-apply). It is bounded by the counter
143
+ `reviewStuckArbiterCount` against the `review_stuck_arbiter_max_attempts` knob
144
+ (default `1`, `0` disables) -- a SEPARATE budget that never touches
145
+ `unattendedAutoResumeCount` or `interactiveBlockedRecovery.maxTurns`. Every other
146
+ case (ineligible source phase, disabled/exhausted cap, turn cap, or any
147
+ adjudicator error) falls through to the generic auto-resume / yield path
148
+ unchanged, writing neither `recentBlocks` nor `adjudicatorAdvice`.
149
+ The decisions are auditable from the structured event log via the
150
+ `review_stuck_arbiter.{start,verdict,resolved,declined,exhausted}` events, which
151
+ carry `scopeNumber`, `sourcePhase`, `blockedReason`, and (on `verdict`/`resolved`)
152
+ `recoverable`, `triageCategory`, `targetCanonicalIds`, and the post-increment
153
+ `reviewStuckArbiterCount`.
154
+ - **Sites B and C — final-completion review and the top-level plan-review gate.**
155
+ These gates block directly (bypassing the recovery chokepoint), and their own
156
+ budgets — the final-completion continue-execution cap and the
157
+ review-round/convergence cap — already bounded the autonomous effort. Under
158
+ unattended they run the shared terminal-fail action immediately rather than
159
+ saving `status:'blocked'`; there is no auto-resume and no synthesized
160
+ `pendingPlanReviewGuidance`. Site C edits only the `topLevelMode !== 'execute'`
161
+ branch of `finalizeBlockedPlanReviewResponse`; execute-mode derived-plan-review
162
+ blocks (`topLevelMode === 'execute'`) re-enter site A and are handled there.
163
+
164
+ The shared terminal-fail action is `persistUnattendedBlockUnresolvedFailure`
165
+ (`src/neal/orchestrator/phases/shared.ts`), which mirrors the
166
+ `persistCoderFailureState` failed-run shape: save `status:'failed'` (preserving
167
+ `phase`/`blockedFromPhase` for diagnostics), re-render execution artifacts, write
168
+ a `failed` checkpoint retrospective, and emit the classified
169
+ `unattended.block_unresolved` log event (`reason:'unattended_block_unresolved'`
170
+ plus the `UnattendedBlockSite` origin) — deliberately without `notifyBlocked`,
171
+ which is the attended wait notification. The run exits with writer code `3`, and
172
+ any produced diff/plan is left unsubmitted as an artifact. There is no top-level
173
+ reason field on `OrchestrationState`; the classification rides the log event and
174
+ retrospective. Attended runs are unchanged and still wait for
175
+ `neal resume --message` at all three sites.
176
+
177
+ ## Resume Planning
178
+
179
+ New-run initialization and existing-run resume reconciliation are separate.
180
+ `loadOrInitialize` still provides the command-facing entrypoint, but resume
181
+ reconciliation is modeled as explicit `ResumeAction` values from
182
+ `planResumeActions` and applied by `applyResumeActions`.
183
+
184
+ Current resume actions cover stopped-status normalization, restoring a resumable
185
+ blocked source phase, keeping non-resumable blocked runs blocked, promoting
186
+ accepted or pending unexecuted derived plans, blocking rejected abandoned derived
187
+ plans, flushing derived-plan notifications, recovering clean committed
188
+ scope work that is waiting for review, waiting for operator guidance, processing
189
+ pending operator guidance, and no-op completion for done runs.
190
+
191
+ `neal resume` is the safe first recovery command for mechanical interruptions.
192
+ The command gathers read-only context, asks the shared decision layer what should
193
+ happen, and calls `loadRunForResume()` only for decisions that should execute
194
+ the selected run. `loadRunForResume()` remains the mutation boundary for resume
195
+ normalization, event logging, pointer writes, and execution artifacts.
196
+
197
+ `neal resume --run <run-id> --message "..."` is the operator-input path only
198
+ when the shared decision says interactive recovery is waiting for guidance.
199
+ Pending guidance resumes with plain `neal resume --run <run-id>`. Queue
200
+ continuation still belongs to `continuePlanAndExecuteQueueFromChildRun` after
201
+ the resumed child run finishes; selecting a child run for resume does not
202
+ advance or repair the parent queue by itself.
203
+
204
+ ## Derived Plans
205
+
206
+ Derived-plan fields are child-run state because they describe replacement execution for the active child run, not the parent queue. The invariant layer enforces these ownership rules:
207
+
208
+ - A non-null `derivedPlanStatus` requires a non-null `derivedPlanPath`.
209
+ - A `derivedScopeIndex` requires execute mode, an accepted derived plan, a parent scope number, and a plan path.
210
+ - `awaiting_derived_plan_execution` requires an accepted derived plan that has not started executing yet and no active created commits.
211
+ - Pending or rejected derived plans cannot have a `derivedScopeIndex`.
212
+
213
+ Derived-plan execution should continue to flow through the existing orchestrator transition helpers before any future shape refactor changes the persisted fields.
214
+
215
+ ## Final Completion
216
+
217
+ Final-completion review is execute-mode only. The `final_completion_review` phase requires a `finalCompletionSummary`. When a reviewer verdict exists, `finalCompletionResolvedAction` must match the effective action, including the continue-execution cap case where Neal resolves to operator blocking instead of starting another scope.
218
+
219
+ When final completion review asks to continue execution, the orchestrator may clear summary and verdict fields and reopen `coder_scope`. That reopened running state is valid.
220
+
221
+ Accepted execute scopes also pass through execute finalization before Neal either opens the next scope or starts final-completion review. The persisted internal runnable cursor for that step is `execute_finalization`, which is separate from the public `neal squash` command. Public `neal squash` is a post-run command with selection, preview, and interactive TTY confirmation before it rewrites history.
222
+
223
+ ## Atomic Writes And Locks
224
+
225
+ `src/neal/atomic-write.ts` provides per-file atomic replacement helpers. State, current run pointers, queue state, queue pointers, queue links, queue summaries, run metadata, progress artifacts, review/final-completion/recovery/split-plan/retrospective artifacts, run narratives, and default squash audit writes use temp-file-plus-rename writes where in scope.
226
+
227
+ This is not a multi-file transaction. If a process stops between writes, each individual JSON or text file should be either the previous complete file or the next complete file, but related files can briefly disagree. Resume and status commands must continue to tolerate that by resolving run paths and validating loaded state.
228
+
229
+ The active-run lock is separate. `src/neal/run-lock.ts` uses exclusive creation for `.neal/active-run.lock`; that acquisition path should not be converted to atomic rename because the exclusive-create behavior is the mutual exclusion mechanism.
230
+
231
+ ## Change Checklist
232
+
233
+ When adding a child-run phase:
234
+
235
+ - Add the phase to `OrchestrationPhase` in `src/neal/types.ts`.
236
+ - Add it to `ORCHESTRATION_PHASES` in `src/neal/state-invariants.ts`.
237
+ - If it is runnable, add it to `RUNNABLE_PHASE_REGISTRY` in `src/neal/orchestrator/run-loop.ts`.
238
+ - Update any recovery or blocked-resume phase sets that should include or exclude it.
239
+ - Add tests in `test/state-invariants.test.ts` or `test/run-loop.test.ts` for the new membership and dispatch contract.
240
+
241
+ When adding a child-run persisted field:
242
+
243
+ - Add the type in `OrchestrationState`.
244
+ - Initialize it in `createInitialState`.
245
+ - Parse it in `normalizeStateV1`.
246
+ - Validate semantic combinations in `assertValidOrchestrationState` when the field can make state invalid.
247
+ - Extend state round-trip or invariant tests.
248
+
249
+ When adding a queue-state field:
250
+
251
+ - Add the type in `PlanAndExecuteQueueState` or `PlanAndExecuteQueueItem`.
252
+ - Initialize it in queue creation or child transition helpers.
253
+ - Parse and validate it in `parsePlanAndExecuteQueueState` or `parsePlanAndExecuteQueueItem`.
254
+ - Include it in queue summary or current queue pointer output only when it is operator-facing or needed for resume.
255
+
256
+ ## Future Refactor Path
257
+
258
+ Do not jump directly from the current record-shaped `OrchestrationState` to a
259
+ persisted discriminated union. The lower-risk path now in place is to keep v1
260
+ hydration isolated, keep semantic checks centralized in `state-invariants.ts`,
261
+ and route new logic through typed state views and the resume planner.
262
+
263
+ After those views have stabilized in real runs and tests, a v2 envelope or
264
+ discriminated internal TypeScript model can be considered separately. Any future
265
+ shape should preserve `neal status --json` as the automation contract and keep
266
+ v1 run-local ledgers readable unless an explicit migration command exists.
@@ -0,0 +1,207 @@
1
+ # Neal Storage Contract
2
+
3
+ Neal uses project-local `.neal/` storage as the source of truth for runs, queues,
4
+ review artifacts, recovery artifacts, progress, and audit history. User-level
5
+ storage is reserved for configuration, guidance, caches, logs, and future
6
+ optional discovery helpers.
7
+
8
+ This document describes the product-level storage contract. The state transition
9
+ and validation details for run and queue ledgers are documented separately in
10
+ [state-machine.md](state-machine.md).
11
+
12
+ ## Public Automation Surface
13
+
14
+ `neal status --json` and `neal status --json --all` are the stable automation
15
+ contracts. Scripts should prefer them over parsing raw files under `.neal/`.
16
+ The status JSON includes public status and phase strings, next action, commit
17
+ and patch summaries, provider-error metadata, build metadata, and active writer
18
+ lock evidence through `lock.kind`.
19
+
20
+ The single-run JSON is the authoritative read model for wrappers that already
21
+ know a run id. Important stable fields include:
22
+
23
+ - `runId`, `status`, `effectiveStatus`, `publicStatus`, `phase`,
24
+ `publicPhase`, and `nextAction` for classification and follow-up.
25
+ - `waitingForOperatorGuidance`, `pendingOperatorGuidance`, `blocker`,
26
+ `manualGate`, `resumeDecision`, `health`, and `lock` for blocked, waiting,
27
+ paused, timed-out, live-lock, stale-lock, and manually gated states.
28
+ - `commits` with `initialBaseCommit`, `baseCommit`, `finalCommit`,
29
+ `createdCommitCount`, and accepted-scope final commits.
30
+ - `squash` with the run-local audit artifact path, summary status
31
+ (`missing`, `pending`, `complete`, or `malformed`), replacement/final-head
32
+ commits, original base/final commits, and an unavailable reason when the
33
+ summary cannot provide complete metadata.
34
+ - `patch` with the conservative default-submission decision, reason, patch
35
+ source, base/head/range, commit count, changed-file count, changed files, and
36
+ unavailable reason.
37
+ - `providerError` with the latest provider failure or unclassified phase error,
38
+ including timestamp, provider id, role, label, session handle, normalized
39
+ error kind, bounded message, and retryability where available.
40
+ - `build` with Neal package version, Neal source Git SHA when available, Node
41
+ version, source marker (`meta` or `live_fallback`), and the persisted
42
+ coder/reviewer agent config.
43
+ - `artifacts` with run-local paths for the human narrative, review, progress,
44
+ support, and related diagnostic artifacts.
45
+
46
+ `neal status --json --all` is the discovery surface. Each listed run is built
47
+ from the same status snapshot path, so list entries retain the public status,
48
+ phase, next action, commit, squash, provider-error, build, patch, lock, and
49
+ artifact summaries. Scripts that need a final decision for one run should still
50
+ read that run with `--run <run-id>`.
51
+
52
+ Status reads are best-effort for optional artifacts. Missing or malformed
53
+ `SQUASH_RESULT.json`, unreadable patch ranges, missing run metadata, and old
54
+ runs without build metadata are represented in the JSON summary instead of
55
+ making status fail. The canonical run ledger still must be readable.
56
+
57
+ Raw `.neal` files are inspectable support artifacts. Internal JSON files are not
58
+ public JSON APIs unless this repository documents that guarantee for a specific
59
+ command output.
60
+
61
+ Storage classifications used below are: stable CLI surface, user-facing human
62
+ artifact, support/debug artifact, internal state, and lock/concurrency artifact.
63
+ The stable CLI surfaces in this storage contract are `neal status --json` and
64
+ `neal status --json --all`; the project-local files are artifacts that support
65
+ Neal operations and diagnostics.
66
+
67
+ ## Project-Local Layout
68
+
69
+ | Path | Classification | Contract |
70
+ | --- | --- | --- |
71
+ | `.neal/runs/<run-id>/RUN_STATE.json` | Internal state | Child-run ledger. Neal validates current v1 state on read, but scripts should use `neal status --json` rather than depend on this file as a public API. |
72
+ | `.neal/runs/<run-id>/events.ndjson` | Support/debug artifact | Append-only event log for audit, diagnostics, command output references, and provider/runtime events. Readers should tolerate malformed or partial final lines where implemented. |
73
+ | `.neal/runs/<run-id>/stderr.log` | Support/debug artifact | Append-only stderr transcript for writer runs. It includes visible narrative lines plus low-level detail such as provider/tool telemetry, command output, reviewer context, and heartbeat diagnostics that may be hidden from the normal terminal stream. |
74
+ | `.neal/runs/<run-id>/meta.json` | Support/debug artifact | Run metadata used for diagnostics. New writes include `version: 1`; metadata alone cannot make a run selectable for squash or status. It is not the stable automation surface. |
75
+ | `.neal/runs/<run-id>/PLAN_ORIGINAL.md` | Support/debug artifact | Original plan document backup for `neal plan` runs, written before in-place plan refinement so the pre-refinement input remains inspectable. |
76
+ | `.neal/runs/<run-id>/scratch/` | Support/debug artifact | Run-local scratch root for execute-scope and final-completion reviewer verification artifacts such as copied tests, scratch builds, logs, and modified throwaway files. It is not durable state, but it remains project-local `.neal/` data for retention and privacy purposes. |
77
+ | `.neal/runs/<run-id>/plan-progress.json` | Internal state | Machine-readable v1 progress artifact used by Neal context and summaries. |
78
+ | `.neal/runs/<run-id>/PLAN_PROGRESS.md` | User-facing human artifact | Human-readable progress summary for the active plan or scope. |
79
+ | `.neal/runs/<run-id>/RETROSPECTIVE.md` | User-facing human artifact | Human-readable retrospective or checkpoint summary. Archived variants such as `RETROSPECTIVE-scope-*.md` may also exist. |
80
+ | `.neal/runs/<run-id>/RUN_NARRATIVE.md` | User-facing human artifact | Human-readable run narrative. It includes a benchmark trace section with status, patch-policy, provider-error, and reproducibility summaries suitable for public result bundles. |
81
+ | `.neal/runs/<run-id>/RUN_NARRATIVE.json` | Internal state | Narrative source data that Neal may read to update the human narrative. It is not a public trace artifact. |
82
+ | `.neal/runs/<run-id>/REVIEW.md` | User-facing human artifact | Scope or plan review history and findings. |
83
+ | `.neal/runs/<run-id>/RECOVERY.md` | User-facing human artifact | Interactive blocked-recovery transcript/history for a run. |
84
+ | `.neal/runs/<run-id>/FINAL_COMPLETION_REVIEW.md` | User-facing human artifact | Whole-plan final completion review. |
85
+ | `.neal/runs/<run-id>/SQUASH_RESULT.json` | Support/debug artifact | Versioned audit artifact from `neal squash`. It records the squash decision/result but is not the stable automation surface. |
86
+ | `.neal/runs/<run-id>/QUEUE_LINK.json` | Internal state | Link from a child run back to its parent plan-and-execute queue item. |
87
+ | `.neal/queues/<queue-id>/QUEUE_STATE.json` | Internal state | Parent queue ledger. Neal validates it on read, but it is not a public JSON API. |
88
+ | `.neal/queues/<queue-id>/QUEUE_SUMMARY.md` | User-facing human artifact | Human-readable summary for a plan-and-execute queue. |
89
+ | `.neal/reviews/<review-id>/meta.json` | Support/debug artifact | Review metadata for a read-only `neal review` request. |
90
+ | `.neal/reviews/<review-id>/events.ndjson` | Support/debug artifact | Append-only review event log. |
91
+ | `.neal/reviews/<review-id>/REVIEW_REQUEST.md` | User-facing human artifact | Original review request, selected range, and loop prompts. |
92
+ | `.neal/reviews/<review-id>/REVIEW_CONTEXT.json` | Support/debug artifact | Resolved local commit range, changed files, diff stat, and diff used for findings. |
93
+ | `.neal/reviews/<review-id>/REVIEW_DRAFT.md` | User-facing human artifact | Human-readable draft findings history for each review loop round. |
94
+ | `.neal/reviews/<review-id>/REVIEW_REVIEW.json` | Support/debug artifact | Versioned review loop summary, including outcome, cap, and round reviews. |
95
+ | `.neal/reviews/<review-id>/REVIEW_ROUNDS.json` | Support/debug artifact | Versioned round-by-round review draft/review prompt and response history. |
96
+ | `.neal/reviews/<review-id>/REVIEW_FINAL.md` | User-facing human artifact | Accepted final reviewed findings artifact, written only after reviewer acceptance. |
97
+ | `.neal/current.json` | Internal state | Default writer-run pointer for commands that need the current run. |
98
+ | `.neal/current-queue.json` | Internal state | Preferred current plan-and-execute queue pointer. |
99
+ | `.neal/active-run.lock` | Lock/concurrency artifact | Active writer-run lock. It prevents unrelated writer commands from mutating the same checkout concurrently. |
100
+
101
+ Writer processes remove their own active lock during normal shutdown and on
102
+ `SIGINT`/`SIGTERM`. Timeout wrappers should still launch Neal in a process group
103
+ and terminate the group, because provider-owned child processes are outside the
104
+ lock file contract. After a timeout, call `neal status --json --run <run-id>`
105
+ when the run id is known; treat the wrapper timeout as the primary result while
106
+ using `status`, `health`, and `lock.kind` to record whether Neal's run state is
107
+ still running, cleaned up, live, stale, cross-host, or unreadable.
108
+
109
+ ## Patch Automation Policy
110
+
111
+ Default public prediction submission should use only
112
+ `patch.defaultSubmissionEligible: true`. Neal sets that value only for clean
113
+ completed execute runs with a non-empty readable patch range.
114
+
115
+ When a completed run has a successful squash artifact, the status read model
116
+ prefers `squash.originalBaseCommit..squash.replacementCommit` and reports
117
+ `patch.source: "squash_replacement"`. Unsquashed completed execute runs fall
118
+ back to `commits.initialBaseCommit ?? commits.baseCommit` through
119
+ `commits.finalCommit` and report `patch.source: "final_commit"`.
120
+
121
+ Failed, blocked, paused, running, waiting, provider-error, timed-out,
122
+ manual-gate, malformed-squash, pending-squash, unreadable-range, and empty-patch
123
+ runs may still report patch-bearing metadata for diagnostics or private
124
+ analysis. They are not default-submission eligible, and `patch.reason` explains
125
+ why.
126
+
127
+ ## Source Of Truth
128
+
129
+ Project-local `.neal/` remains the source of truth for run, queue, review,
130
+ recovery, progress, and audit artifacts.
131
+
132
+ Run-local `.neal/runs/<run-id>/RUN_STATE.json` is the only writer-run ledger
133
+ path Neal writes. `.neal/current.json` points at the default writer run; it is a
134
+ pointer, not a copy of the ledger.
135
+
136
+ There is no required global run index in v1. Future global discovery, if added,
137
+ must be optional and rebuildable from project-local data. It must not become the
138
+ only place where run or queue history can be recovered.
139
+
140
+ ## Ledgers And Pointers
141
+
142
+ `.neal/runs/<run-id>/RUN_STATE.json` and
143
+ `.neal/queues/<queue-id>/QUEUE_STATE.json` are persisted ledgers. Neal validates
144
+ them on read. Child-run state uses strict current v1 hydration: missing or
145
+ malformed required child-run fields fail instead of receiving defaults. These
146
+ ledgers are not public JSON APIs.
147
+
148
+ Neal does not write, read, migrate, or repair a session mirror. Use
149
+ `.neal/current.json` as the default writer-run pointer, `neal status --all` to
150
+ discover run IDs, and `--run <run-id>` when selecting a specific run for
151
+ `resume` or `status`.
152
+
153
+ Squash discovery requires readable run-local state. Run metadata and progress
154
+ artifacts can help humans inspect a run, but they cannot make a run selectable
155
+ for `neal squash` without `.neal/runs/<run-id>/RUN_STATE.json`.
156
+
157
+ ## Schema Versions And Writes
158
+
159
+ Neal-owned JSON schemas use `version: 1` where they are read back as durable
160
+ state or audit data. That includes child-run state, current run pointers, queue
161
+ state, current queue pointers, queue child links, progress summaries, run
162
+ narratives, squash audit results, review artifacts, and the active writer lock.
163
+
164
+ Run `meta.json` is diagnostic support data. New writes include `version: 1`, but
165
+ status, resume, and squash selection derive canonical run facts from run-local
166
+ state.
167
+
168
+ Important replacement artifacts under `.neal/` are written through per-file
169
+ atomic replacement helpers so a reader should see either the old complete file
170
+ or the new complete file. This is still not a multi-file transaction: related
171
+ files such as state, progress, reviews, and pointers can briefly disagree if a
172
+ process stops between writes. Append-only event logs remain append-only, and the
173
+ active writer lock keeps exclusive file creation for acquisition.
174
+
175
+ ## Retention And Privacy
176
+
177
+ `.neal/` may contain prompts, local paths, command output, diffs, review text,
178
+ provider responses, user guidance diagnostics, reviewer scratch files, copied
179
+ tests, build logs, and project-specific context. Review `.neal/` before sharing
180
+ archives, bug reports, or support bundles.
181
+
182
+ Public automation bundles should copy `neal status --json` output and
183
+ `RUN_NARRATIVE.md` when a safe per-run trace is needed. Do not publish raw run
184
+ directories, `RUN_NARRATIVE.json`, `events.ndjson`, `stderr.log`, or internal
185
+ state ledgers as benchmark traces.
186
+
187
+ Run and review artifacts are intentionally inspectable, but they should be
188
+ treated as project data. Apply the same retention and access controls you use
189
+ for source, logs, and local debugging output.
190
+
191
+ ## Manual Cleanup
192
+
193
+ Manual cleanup is safe only when you no longer need resume, history, diagnostics,
194
+ or audit data for the item being removed.
195
+
196
+ Reasonable manual cleanup options:
197
+
198
+ - remove old `.neal/runs/<run-id>/` directories when resume and run history for
199
+ those runs are no longer needed
200
+ - remove old `.neal/queues/<queue-id>/` directories when queue resume and queue
201
+ history are no longer needed
202
+ - remove stale `.neal/current.json` or `.neal/current-queue.json` pointers only
203
+ after confirming they do not point to work you still intend to resume
204
+
205
+ Deleting run or queue state removes Neal's resume and history for that run or
206
+ queue. Prefer keeping the full directory until the related work has been merged,
207
+ archived, or otherwise recorded somewhere durable.