@bastani/atomic 0.9.7 → 0.9.8

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 (51) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/builtin/cursor/CHANGELOG.md +12 -0
  3. package/dist/builtin/cursor/package.json +2 -2
  4. package/dist/builtin/intercom/CHANGELOG.md +12 -0
  5. package/dist/builtin/intercom/package.json +1 -1
  6. package/dist/builtin/mcp/CHANGELOG.md +12 -0
  7. package/dist/builtin/mcp/package.json +1 -1
  8. package/dist/builtin/subagents/CHANGELOG.md +14 -0
  9. package/dist/builtin/subagents/package.json +1 -1
  10. package/dist/builtin/subagents/skills/{effective-liteparse → liteparse}/SKILL.md +4 -4
  11. package/dist/builtin/subagents/skills/playwright-cli/SKILL.md +21 -5
  12. package/dist/builtin/subagents/skills/playwright-cli/references/test-generation.md +311 -12
  13. package/dist/builtin/web-access/CHANGELOG.md +12 -0
  14. package/dist/builtin/web-access/package.json +1 -1
  15. package/dist/builtin/workflows/CHANGELOG.md +24 -0
  16. package/dist/builtin/workflows/README.md +2 -2
  17. package/dist/builtin/workflows/builtin/goal-prompts.ts +9 -7
  18. package/dist/builtin/workflows/builtin/goal-reducer.ts +9 -24
  19. package/dist/builtin/workflows/builtin/goal-review.ts +17 -36
  20. package/dist/builtin/workflows/builtin/ralph-core.ts +1 -3
  21. package/dist/builtin/workflows/builtin/ralph-review-gate.ts +31 -53
  22. package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +10 -4
  23. package/dist/builtin/workflows/builtin/shared-prompts.ts +5 -4
  24. package/dist/builtin/workflows/package.json +1 -1
  25. package/dist/builtin/workflows/skills/impeccable/reference/hooks.md +2 -2
  26. package/dist/builtin/workflows/skills/impeccable/reference/init.md +37 -10
  27. package/dist/builtin/workflows/skills/impeccable/scripts/context-signals.mjs +1 -1
  28. package/dist/builtin/workflows/skills/impeccable/scripts/context.mjs +2 -1
  29. package/dist/builtin/workflows/skills/impeccable/scripts/critique-storage.mjs +2 -2
  30. package/dist/builtin/workflows/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +20 -4
  31. package/dist/builtin/workflows/skills/impeccable/scripts/detector/engines/regex/detect-text.mjs +3 -6
  32. package/dist/builtin/workflows/skills/impeccable/scripts/detector/rules/checks.mjs +2 -4
  33. package/dist/builtin/workflows/skills/impeccable/scripts/detector/shared/page.mjs +31 -8
  34. package/dist/builtin/workflows/skills/impeccable/scripts/hook-admin.mjs +7 -6
  35. package/dist/builtin/workflows/skills/impeccable/scripts/hook-lib.mjs +11 -10
  36. package/dist/builtin/workflows/skills/impeccable/scripts/lib/impeccable-paths.mjs +1 -0
  37. package/dist/builtin/workflows/skills/impeccable/scripts/lib/is-generated.mjs +1 -1
  38. package/dist/builtin/workflows/skills/impeccable/scripts/lib/provider.mjs +4 -0
  39. package/dist/builtin/workflows/skills/impeccable/scripts/live/browser-script-parts.mjs +2 -1
  40. package/dist/builtin/workflows/skills/impeccable/scripts/live/svelte-component.mjs +38 -16
  41. package/dist/builtin/workflows/skills/impeccable/scripts/live-accept.mjs +33 -19
  42. package/dist/builtin/workflows/skills/impeccable/scripts/live-browser.js +9 -9
  43. package/dist/builtin/workflows/skills/impeccable/scripts/live-server.mjs +2 -0
  44. package/dist/builtin/workflows/skills/impeccable/scripts/pin.mjs +16 -9
  45. package/dist/builtin/workflows/src/tui/overlay-adapter.ts +59 -14
  46. package/docs/quickstart.md +1 -1
  47. package/docs/workflows.md +4 -4
  48. package/npm-shrinkwrap.json +23 -23
  49. package/package.json +2 -2
  50. package/dist/builtin/subagents/skills/playwright-cli/references/spec-driven-testing.md +0 -305
  51. /package/dist/builtin/subagents/skills/{effective-liteparse → liteparse}/scripts/search.py +0 -0
@@ -6,7 +6,7 @@
6
6
  * node <scripts_path>/pin.mjs pin <command>
7
7
  * node <scripts_path>/pin.mjs unpin <command>
8
8
  *
9
- * `pin audit` creates a lightweight /audit skill that redirects to /impeccable audit.
9
+ * `pin audit` creates a lightweight audit skill that redirects to Impeccable's audit workflow.
10
10
  * `unpin audit` removes that shortcut.
11
11
  *
12
12
  * The script discovers harness directories (.claude/skills, .cursor/skills, etc.)
@@ -14,7 +14,7 @@
14
14
  */
15
15
 
16
16
  import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync, readdirSync } from 'node:fs';
17
- import { join, resolve, dirname } from 'node:path';
17
+ import { basename, join, resolve, dirname } from 'node:path';
18
18
  import { fileURLToPath } from 'node:url';
19
19
 
20
20
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -25,6 +25,8 @@ const HARNESS_DIRS = [
25
25
  '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev',
26
26
  ];
27
27
 
28
+ const CODEX_HARNESSES = new Set(['.codex', '.agents']);
29
+
28
30
  // Valid sub-command names
29
31
  const VALID_COMMANDS = [
30
32
  'craft', 'init', 'extract', 'document', 'shape',
@@ -87,8 +89,12 @@ function loadCommandMetadata() {
87
89
  /**
88
90
  * Generate a pinned skill's SKILL.md content.
89
91
  */
90
- function generatePinnedSkill(command, metadata) {
91
- const desc = metadata[command]?.description || `Shortcut for /impeccable ${command}.`;
92
+ function commandPrefixForSkillsDir(skillsDir) {
93
+ return CODEX_HARNESSES.has(basename(dirname(skillsDir))) ? '$' : '/';
94
+ }
95
+
96
+ function generatePinnedSkill(command, metadata, commandPrefix) {
97
+ const desc = metadata[command]?.description || `Shortcut for ${commandPrefix}impeccable ${command}.`;
92
98
  const hint = metadata[command]?.argumentHint || '[target]';
93
99
 
94
100
  return `---
@@ -100,9 +106,9 @@ user-invocable: true
100
106
 
101
107
  ${PIN_MARKER}
102
108
 
103
- This is a pinned shortcut for \`{{command_prefix}}impeccable ${command}\`.
109
+ This is a pinned shortcut for \`${commandPrefix}impeccable ${command}\`.
104
110
 
105
- Invoke {{command_prefix}}impeccable ${command}, passing along any arguments provided here, and follow its instructions.
111
+ Invoke ${commandPrefix}impeccable ${command}, passing along any arguments provided here, and follow its instructions.
106
112
  `;
107
113
  }
108
114
 
@@ -118,10 +124,11 @@ function pin(command, projectRoot) {
118
124
  return false;
119
125
  }
120
126
 
121
- const content = generatePinnedSkill(command, metadata);
122
127
  let created = 0;
123
128
 
124
129
  for (const skillsDir of harnessDirs) {
130
+ const commandPrefix = commandPrefixForSkillsDir(skillsDir);
131
+ const content = generatePinnedSkill(command, metadata, commandPrefix);
125
132
  // Check if skill already exists (and isn't a pin)
126
133
  const skillDir = join(skillsDir, command);
127
134
  if (existsSync(skillDir)) {
@@ -143,7 +150,7 @@ function pin(command, projectRoot) {
143
150
 
144
151
  if (created > 0) {
145
152
  console.log(`\nPinned '${command}' as a standalone shortcut in ${created} location(s).`);
146
- console.log(`You can now use /${command} directly.`);
153
+ console.log('Use the pinned command directly in each harness.');
147
154
  }
148
155
 
149
156
  return created > 0;
@@ -177,7 +184,7 @@ function unpin(command, projectRoot) {
177
184
 
178
185
  if (removed > 0) {
179
186
  console.log(`\nUnpinned '${command}' from ${removed} location(s).`);
180
- console.log(`Use /impeccable ${command} to access it.`);
187
+ console.log(`Use Impeccable's '${command}' workflow directly to access it.`);
181
188
  } else {
182
189
  console.log(`No pinned '${command}' shortcut found.`);
183
190
  }
@@ -103,12 +103,25 @@ const FULLSCREEN_OVERLAY_OPTIONS: PiOverlayOptions = {
103
103
 
104
104
  const MOUSE_SCROLL_TRACKING_ON = "\x1b[?1000h\x1b[?1002h\x1b[?1006h";
105
105
  const MOUSE_SCROLL_TRACKING_OFF = "\x1b[?1006l\x1b[?1002l\x1b[?1000l";
106
+ const TERMINAL_AUTOWRAP_ON = "\x1b[?7h";
107
+ const TERMINAL_AUTOWRAP_OFF = "\x1b[?7l";
106
108
  const MAIN_CHAT_INPUT_STATUS_KEY = `${WORKFLOW_STATUS_KEY}:main-chat-input`;
107
109
  const MAIN_CHAT_INPUT_STATUS = "Main chat needs input — exit graph to answer.";
108
110
 
109
- function setMouseScrollTracking(enabled: boolean): void {
110
- if (!process.stdout.isTTY) return;
111
- process.stdout.write(enabled ? MOUSE_SCROLL_TRACKING_ON : MOUSE_SCROLL_TRACKING_OFF);
111
+ export interface OverlayTerminalOutput {
112
+ platform: NodeJS.Platform;
113
+ isTTY: boolean | undefined;
114
+ write(data: string): void;
115
+ }
116
+
117
+ function setMouseScrollTracking(enabled: boolean, output: OverlayTerminalOutput): void {
118
+ if (!output.isTTY) return;
119
+ output.write(enabled ? MOUSE_SCROLL_TRACKING_ON : MOUSE_SCROLL_TRACKING_OFF);
120
+ }
121
+
122
+ function setTerminalAutowrap(enabled: boolean, output: OverlayTerminalOutput): void {
123
+ if (output.platform !== "win32" || !output.isTTY) return;
124
+ output.write(enabled ? TERMINAL_AUTOWRAP_ON : TERMINAL_AUTOWRAP_OFF);
112
125
  }
113
126
 
114
127
  export interface BuildGraphOverlayAdapterOpts {
@@ -126,6 +139,8 @@ export interface BuildGraphOverlayAdapterOpts {
126
139
  onQuitRun?: (runId: string) => void;
127
140
  /** Optional clock injection for deterministic attach-pane transition tests. */
128
141
  now?: () => number;
142
+ /** Terminal output seam used to test raw overlay control sequences. */
143
+ terminalOutput?: OverlayTerminalOutput;
129
144
  }
130
145
 
131
146
  export function buildGraphOverlayAdapter(
@@ -135,6 +150,16 @@ export function buildGraphOverlayAdapter(
135
150
  ): GraphOverlayPort {
136
151
  const registry = buildOpts.stageControlRegistry ?? defaultStageControlRegistry;
137
152
  const stageUiBroker = buildOpts.stageUiBroker;
153
+ const terminalOutput = buildOpts.terminalOutput ?? {
154
+ platform: process.platform,
155
+ isTTY: process.stdout.isTTY,
156
+ write: (data: string): void => {
157
+ process.stdout.write(data);
158
+ },
159
+ };
160
+ const updateMouseScrollTracking = (enabled: boolean): void => {
161
+ setMouseScrollTracking(enabled, terminalOutput);
162
+ };
138
163
  const quitRun = buildOpts.onQuitRun ?? ((id: string): void => {
139
164
  defaultQuitRun(id, { store, stageControlRegistry: registry });
140
165
  });
@@ -149,6 +174,13 @@ export function buildGraphOverlayAdapter(
149
174
  let observedUi: OverlayUISurface | undefined;
150
175
  let unsubscribeHostCustomUi: (() => void) | null = null;
151
176
  let hostInlineCustomUiActive = false;
177
+ let overlayVisible = false;
178
+
179
+ function updateTerminalAutowrap(visible: boolean): void {
180
+ if (overlayVisible === visible) return;
181
+ overlayVisible = visible;
182
+ setTerminalAutowrap(!visible, terminalOutput);
183
+ }
152
184
 
153
185
  function readHostCustomUiActive(ui: OverlayUISurface | undefined = observedUi): boolean {
154
186
  const state = ui?.getHostCustomUiState?.();
@@ -188,8 +220,9 @@ export function buildGraphOverlayAdapter(
188
220
  }
189
221
 
190
222
  function close(): void {
191
- setMouseScrollTracking(false);
223
+ updateMouseScrollTracking(false);
192
224
  currentHandle?.hide();
225
+ updateTerminalAutowrap(false);
193
226
  finishMounted?.();
194
227
  observedUi?.setStatus?.(WORKFLOW_STATUS_KEY, undefined);
195
228
  observedUi?.setStatus?.(MAIN_CHAT_INPUT_STATUS_KEY, undefined);
@@ -218,11 +251,12 @@ export function buildGraphOverlayAdapter(
218
251
  * running and can be re-attached.
219
252
  */
220
253
  function hideMounted(): void {
221
- setMouseScrollTracking(false);
254
+ updateMouseScrollTracking(false);
222
255
  observedUi?.setStatus?.(MAIN_CHAT_INPUT_STATUS_KEY, undefined);
223
256
  if (currentHandle) {
224
257
  currentView?.setVisible(false);
225
258
  currentHandle.setHidden(true);
259
+ updateTerminalAutowrap(false);
226
260
  currentHandle.unfocus();
227
261
  return;
228
262
  }
@@ -230,6 +264,7 @@ export function buildGraphOverlayAdapter(
230
264
  finishMounted();
231
265
  return;
232
266
  }
267
+ updateTerminalAutowrap(false);
233
268
  }
234
269
 
235
270
  function refocusVisibleOverlayForAwaitingInput(snapshot: StoreSnapshot): void {
@@ -258,7 +293,8 @@ export function buildGraphOverlayAdapter(
258
293
  },
259
294
  invalidate: () => tui.requestRender?.(),
260
295
  dispose: () => {
261
- setMouseScrollTracking(false);
296
+ updateTerminalAutowrap(false);
297
+ updateMouseScrollTracking(false);
262
298
  unsubscribe();
263
299
  view.dispose();
264
300
  },
@@ -277,14 +313,16 @@ export function buildGraphOverlayAdapter(
277
313
  if (mounted && currentHandle?.isHidden()) {
278
314
  currentView?.retarget(runId, stageId);
279
315
  currentView?.setVisible(true);
280
- setMouseScrollTracking(currentView?.wantsMouseScrollTracking() ?? true);
316
+ updateTerminalAutowrap(true);
317
+ updateMouseScrollTracking(currentView?.wantsMouseScrollTracking() ?? true);
281
318
  currentHandle.setHidden(false);
282
319
  currentHandle.focus();
283
320
  return;
284
321
  }
285
322
  if (mounted) {
286
323
  currentView?.retarget(runId, stageId);
287
- setMouseScrollTracking(currentView?.wantsMouseScrollTracking() ?? true);
324
+ updateTerminalAutowrap(true);
325
+ updateMouseScrollTracking(currentView?.wantsMouseScrollTracking() ?? true);
288
326
  // Restore keyboard focus to the visible overlay after retargeting.
289
327
  // pi-tui dispatches key events only to the focused component, so a
290
328
  // mounted-but-visible overlay that is retargeted (e.g. to a stage-scoped
@@ -309,7 +347,7 @@ export function buildGraphOverlayAdapter(
309
347
  const finish = (): void => {
310
348
  if (settled) return;
311
349
  settled = true;
312
- setMouseScrollTracking(false);
350
+ updateMouseScrollTracking(false);
313
351
  observedUi?.setStatus?.(WORKFLOW_STATUS_KEY, undefined);
314
352
  observedUi?.setStatus?.(MAIN_CHAT_INPUT_STATUS_KEY, undefined);
315
353
  currentView?.dispose();
@@ -318,7 +356,11 @@ export function buildGraphOverlayAdapter(
318
356
  finishMounted = null;
319
357
  mounted = false;
320
358
  clearHostCustomUiObservation();
321
- done(undefined);
359
+ try {
360
+ done(undefined);
361
+ } finally {
362
+ updateTerminalAutowrap(false);
363
+ }
322
364
  };
323
365
  const view = new WorkflowAttachPane({
324
366
  store,
@@ -369,7 +411,7 @@ export function buildGraphOverlayAdapter(
369
411
  if (currentHandle?.isFocused() === true) return;
370
412
  currentHandle?.focus();
371
413
  },
372
- setMouseScrollTracking,
414
+ setMouseScrollTracking: updateMouseScrollTracking,
373
415
  now: buildOpts.now,
374
416
  } as ConstructorParameters<typeof WorkflowAttachPane>[0] & {
375
417
  piTui?: PiCustomOverlayFactoryTui;
@@ -379,7 +421,8 @@ export function buildGraphOverlayAdapter(
379
421
  currentView = view;
380
422
  finishMounted = finish;
381
423
  mounted = true;
382
- setMouseScrollTracking(view.wantsMouseScrollTracking());
424
+ updateTerminalAutowrap(true);
425
+ updateMouseScrollTracking(view.wantsMouseScrollTracking());
383
426
  updateMainChatInputHint(readHostCustomUiActive(ui));
384
427
  return makeComponent(view, tui);
385
428
  };
@@ -403,11 +446,13 @@ export function buildGraphOverlayAdapter(
403
446
  if (mounted && currentHandle) {
404
447
  const nowHidden = !currentHandle.isHidden();
405
448
  currentView?.setVisible(!nowHidden);
406
- setMouseScrollTracking(
449
+ if (!nowHidden) updateTerminalAutowrap(true);
450
+ updateMouseScrollTracking(
407
451
  nowHidden ? false : currentView?.wantsMouseScrollTracking() ?? true,
408
452
  );
409
453
  currentHandle.setHidden(nowHidden);
410
- if (!nowHidden) currentHandle.focus();
454
+ if (nowHidden) updateTerminalAutowrap(false);
455
+ else currentHandle.focus();
411
456
  return;
412
457
  }
413
458
  if (mounted) {
@@ -151,7 +151,7 @@ Skills are reusable expert instructions. Trigger one with `/skill:<name>` follow
151
151
  | `tdd` | Test-first feature or bug work. | `/skill:tdd` |
152
152
  | `impeccable` | Critique or refine web/native frontend and product UI; includes detector hooks. | `/skill:impeccable` |
153
153
  | `playwright-cli` | Drive a real browser for end-to-end UI checks, screenshots, and reviewable proof videos. | `/skill:playwright-cli` |
154
- | `effective-liteparse` | Pull text, tables, or values out of PDF, DOCX, PPTX, XLSX, and image files locally. | `/skill:effective-liteparse` |
154
+ | `liteparse` | Pull text, tables, or values out of PDF, DOCX, PPTX, XLSX, and image files locally. | `/skill:liteparse` |
155
155
 
156
156
  Use `/skill:research-codebase` for a focused area and `/workflow deep-research-codebase` when a clearly delegated repo-wide research job benefits from durable stages and artifacts. Keep conversation-led planning and implementation inline, or use bounded subagents while the parent remains in control. When an autonomous implementation job needs durable execution, use `/workflow goal` for a goal ledger, bounded worker turns, and reviewer-gated completion, or `/workflow ralph` for a research-first pipeline with delegated implementation and iterative review. Task size alone does not select either workflow. Add `create_pr=true` only when you want the workflow's final pull-request stage after approval.
157
157
 
package/docs/workflows.md CHANGED
@@ -227,7 +227,7 @@ Inputs:
227
227
  | `git_worktree_dir` | string | no | `""` | Optional reusable Git worktree root. Empty runs in the invoking checkout; non-empty values run Goal stages in the created/reused worktree. |
228
228
  | `create_pr` | boolean | no | `false` | Safe-by-default PR creation flag. Omitted or `false` skips the final `pull-request` stage and omits `pr_report`; prompt text alone does not opt in, and only strict `true` authorizes the final `pull-request` stage to attempt provider-appropriate PR/MR/review creation after Goal reaches `complete`. |
229
229
 
230
- `goal` defaults to 10 worker/review turns. Reviewer quorum is fixed internally at 2 reviewer `complete` votes, but approval is evidence closure rather than reviewer agreement alone: quorum can only complete the run when no objective-relevant blocking finding from any reviewer in the current round remains unresolved. The repeated-blocker threshold defaults to 3 consecutive same-blocker turns and is clamped to `max_turns` when you run fewer than 3 turns.
230
+ `goal` defaults to 10 worker/review turns. Reviewer quorum is fixed internally at 2 reviewer `complete` votes, and approval is deterministic on each reviewer's self-reported `stop_review_loop` boolean: a reviewer approves exactly when it returns `stop_review_loop=true` with no `reviewer_error` (schema-parse failures count as non-approval), and the reducer completes the run when quorum of those booleans is met without recomputing approval from findings arrays or traceability statuses. The repeated-blocker threshold defaults to 3 consecutive same-blocker turns and is clamped to `max_turns` when you run fewer than 3 turns.
231
231
 
232
232
  Run examples:
233
233
 
@@ -245,9 +245,9 @@ Set `git_worktree_dir` when you want Goal's worker and reviewer stages isolated
245
245
 
246
246
  Write the `objective` like a compact acceptance spec. Say what should exist when the run is done, how you want testing handled, which command(s) or manual checks matter, and what outcome proves completion. The workflow is intentionally lean: it does not first generate an RFC or migration plan, so the developer-supplied objective is where scope, validation, and completion criteria belong.
247
247
 
248
- Goal worker/reviewer prompts treat the objective and acceptance criteria as the sole literal source of truth: if follow-up deltas, language specs, upstream issues, in-repo comments, or best practices conflict with explicit wording, reviewers surface the conflict instead of silently implementing external knowledge. Reviewer findings carry `objective_alignment` (`required_by_objective`, `consistent_with_objective`, `beyond_objective`, or `contradicts_objective`); `beyond_objective` and `contradicts_objective` findings are reported but do not block completion and must not be promoted into follow-up objectives without reconciling them against the acceptance criteria. Severity labels alone never dismiss objective-relevant findings: `required_by_objective` findings block at any priority (P3 included), while `consistent_with_objective` P3 nice-to-haves stay non-blocking. Review decisions also include `requirements_traceability`, a clause-by-clause evidence map over every explicit objective/acceptance-criteria requirement. Goal approval requires that map to be non-empty and fully `proven` except for a missing PR/MR/review row when `create_pr=true` and that final handoff is the only remaining action; passing worker-authored tests or snapshots alone is circular evidence unless tied to independent current-state proof.
248
+ Goal worker/reviewer prompts treat the objective and acceptance criteria as the sole literal source of truth: if follow-up deltas, language specs, upstream issues, in-repo comments, or best practices conflict with explicit wording, reviewers surface the conflict instead of silently implementing external knowledge. Reviewer findings carry `objective_alignment` (`required_by_objective`, `consistent_with_objective`, `beyond_objective`, or `contradicts_objective`); `beyond_objective` and `contradicts_objective` findings are reported but do not block completion and must not be promoted into follow-up objectives without reconciling them against the acceptance criteria. Severity labels alone never dismiss objective-relevant findings: `required_by_objective` findings block at any priority (P3 included), while `consistent_with_objective` P3 nice-to-haves stay non-blocking. Review decisions also include `requirements_traceability`, a clause-by-clause evidence map over every explicit objective/acceptance-criteria requirement. Findings and traceability are audit evidence that drive how each reviewer derives its authoritative `stop_review_loop` boolean; the harness gates approval on that boolean alone, and reviewers are explicitly told that process-only clauses (reviewer quorum/approval counts, and the authorized post-approval PR/MR/review final action when `create_pr=true`) must never hold the flag at `false`. Passing worker-authored tests or snapshots alone is circular evidence unless tied to independent current-state proof.
249
249
 
250
- The worker may claim readiness, but it cannot finalize completion. Workers start from an observable acceptance/contract matrix derived from the literal objective/acceptance criteria (one row per clause, each mapped to the concrete check that proves it), and are prompted to model states, transitions, and invariants explicitly when the work is stateful. Reviewer findings from the latest round are consolidated into a deduplicated cross-reviewer batch persisted in the round artifact (`consolidated_findings` in `review-round-latest.json`), and the next worker turn is instructed to plan and repair the whole batch — with durable regression evidence for reproduced findings — rather than fixing one finding per turn. Workers and reviewers are prompted to verify user-visible behavior end-to-end when practical, using `playwright-cli`-skilled subagents for web/frontend flows that may depend on backend/API behavior and tmux-skilled subagents for TUI or terminal-app scenarios. They must assume credentials/auth/environment access exists until concrete checks plus an actual app/flow launch attempt prove otherwise; skipped E2E is valid only when exact attempted commands and observed failure output are recorded. Goal reviewers also look for any QA E2E video referenced by the ledger or receipt and must inspect the actual video before treating it as proof. Three reviewers independently inspect the ledger, worker receipt, repository state, and diff against `base_branch`; each starts in a clean, non-forked context, matching Ralph's reviewer context behavior, and every Goal reviewer uses Ralph's `reviewer-a` model chain with Claude Fable 5 as the primary model. Each reviewer is instructed to first derive its own adversarial check list from the literal contract — boundary/edge/negative probes plus state/transition/invariant probes — before relying on the worker receipt or worker-authored tests, and each returns structured JSON with findings, evidence, verification still remaining, and an optional blocker. A TypeScript reducer marks the goal complete only when reviewer quorum approves and evidence closure holds (no unresolved objective-relevant blocking finding from any reviewer in the round), marks blocked only when the same dependency/tool blocker repeats for the blocker threshold, continues when evidence is missing or closure fails (recording the unresolved findings in the decision reason), and returns `needs_human` when `max_turns` is exhausted or worker execution fails, so the bounded loop always stops with an inspectable reason.
250
+ The worker may claim readiness, but it cannot finalize completion. Workers start from an observable acceptance/contract matrix derived from the literal objective/acceptance criteria (one row per clause, each mapped to the concrete check that proves it), and are prompted to model states, transitions, and invariants explicitly when the work is stateful. Reviewer findings from the latest round are consolidated into a deduplicated cross-reviewer batch persisted in the round artifact (`consolidated_findings` in `review-round-latest.json`), and the next worker turn is instructed to plan and repair the whole batch — with durable regression evidence for reproduced findings — rather than fixing one finding per turn. Workers and reviewers are prompted to verify user-visible behavior end-to-end when practical, using `playwright-cli`-skilled subagents for web/frontend flows that may depend on backend/API behavior and tmux-skilled subagents for TUI or terminal-app scenarios. They must assume credentials/auth/environment access exists until concrete checks plus an actual app/flow launch attempt prove otherwise; skipped E2E is valid only when exact attempted commands and observed failure output are recorded. Goal reviewers also look for any QA E2E video referenced by the ledger or receipt and must inspect the actual video before treating it as proof. Three reviewers independently inspect the ledger, worker receipt, repository state, and diff against `base_branch`; each starts in a clean, non-forked context, matching Ralph's reviewer context behavior, and every Goal reviewer uses Ralph's `reviewer-a` model chain with Claude Fable 5 as the primary model. Each reviewer is instructed to first derive its own adversarial check list from the literal contract — boundary/edge/negative probes plus state/transition/invariant probes — before relying on the worker receipt or worker-authored tests, and each returns structured JSON with findings, evidence, verification still remaining, and an optional blocker. A TypeScript reducer marks the goal complete when reviewer quorum approves via the `stop_review_loop` booleans, marks blocked only when the same dependency/tool blocker repeats for the blocker threshold, continues while quorum is missing (recording the reviewers' remaining work in the decision reason), and returns `needs_human` when `max_turns` is exhausted or worker execution fails, so the bounded loop always stops with an inspectable reason.
251
251
 
252
252
  When Goal's reducer returns `needs_human`, `blocked`, or another incomplete status, the top-level workflow run is not reported as a successful completion. `/workflow status` and lifecycle notices surface it as blocked/failed according to the run's terminal condition. Atomic also preserves structured recoverable failure metadata from the run's blocking stage (`failedStageId`) or run-level failure metadata, so auth, rate-limit, and provider fallback exhaustion remains blocked/resumable even if the workflow later returns ordinary outputs instead of a reserved `status` value. Tolerated branch failures from non-fail-fast parallel work do not reclassify an otherwise completed run.
253
253
 
@@ -293,7 +293,7 @@ Run examples:
293
293
  /workflow ralph prompt="Safely implement the API refactor" git_worktree_dir=../atomic-ralph-api-wt base_branch=main
294
294
  ```
295
295
 
296
- Each `ralph` run uses the raw `prompt` exactly as supplied as the operative objective for research, orchestration, and review, and stores `acceptance_criteria` as the immutable literal contract (defaulting to the prompt when omitted). Shared literal-contract prompt language forbids adding behaviors, restrictions, or error conditions beyond the prompt/acceptance criteria and requires surfacing conflicts with external knowledge; Ralph does not run an initial prompt-refinement stage. Each iteration transforms that raw prompt with `/skill:prompt-engineer Transform the following user request into a codebase and online research question which can be thoroughly explored: ...` (`research-prompt-refinement`), researches that transformed question with `/skill:research-codebase ...`, and writes the findings under `research/`. The research, orchestrator, and reviewer prompts carry `acceptance_criteria` next to the literal contract, so orchestrators should pass the ORIGINAL task text when launching follow-up Ralph runs from reviewer findings. The orchestrator starts from an observable acceptance/contract matrix derived from the literal prompt/acceptance criteria (one row per clause mapped to the concrete observable check that proves it) and is prompted to model states, transitions, and invariants explicitly when the work is stateful; it treats the research artifact as its primary implementation context, initializes/updates an OS-temp implementation notes file while generating verifiable evidence for any claims it records in the notes and reviewer artifacts, delegates implementation through sub-agents, repairs unresolved reviewer findings as one consolidated batch (with durable regression evidence for reproduced findings) rather than one finding per iteration, and asks two independent reviewers (`reviewer-a` and `reviewer-b`) to inspect the patch directly against `base_branch`. The reviewer fan-out runs reviewers on different primary model families (Claude Fable 5 and GPT-5.5 Codex, with shared fallbacks) so the adversarial review gets cross-model coverage instead of repeated passes from one model, and each reviewer is instructed to first derive its own adversarial check list from the literal contract — boundary/edge/negative probes plus state/transition/invariant probes — before relying on the implementation notes, orchestrator report, or worker-authored tests. Ralph's orchestrator and reviewers are prompted to verify user-visible behavior end-to-end when practical, using `playwright-cli`-skilled subagents for web/frontend flows that may depend on backend/API behavior and tmux-skilled subagents for TUI or terminal-app scenarios. They must assume credentials/auth/environment access exists until concrete checks plus an actual app/flow launch attempt prove otherwise; skipped E2E is valid only when exact attempted commands and observed failure output are recorded. For UI-applicable or full-stack changes, the orchestrator runs a `playwright-cli` end-to-end QA pass and records a reviewable proof video (referenced in the implementation notes and surfaced as `qa_video_path`); reviewers receive that path and must inspect the actual video before treating it as proof. When `create_pr=true`, the final `pull-request` stage attaches or links that video to the created PR/MR/review after reviewer approval. If reviewers find issues, the next `research-prompt-refinement` and research stages receive the review artifact path (whose `review-round-latest.json` now also carries a deduplicated cross-reviewer `consolidated_findings` batch) so follow-up research can address unresolved findings, and research stages fork from prior research session data when available. The loop stops only when both reviewers independently approve or `max_loops` is reached, so the bounded loop always stops with an inspectable review round. Ralph findings include the same `objective_alignment` classification used by Goal: `required_by_objective` findings block at any priority (P3 included, because severity labels alone never dismiss objective-relevant findings), `consistent_with_objective` P0/P1/P2 findings block while P3 remains a non-blocking nice-to-have, and `beyond_objective`/`contradicts_objective` findings are surfaced but non-blocking so they are not silently converted into new requirements. Ralph review decisions also include `requirements_traceability`, a clause-by-clause evidence map over every explicit prompt/acceptance-criteria requirement; approval requires that map to be non-empty and fully `proven` except for a missing PR/MR/review row when `create_pr=true` and that final handoff is the only remaining action. Worker-authored tests or snapshots passing are circular evidence unless tied to independent current-state proof. By default Ralph does not start the final `pull-request` stage, and `pr_report` is omitted. Prompt text alone does not opt in. Pass `create_pr=true` only when you explicitly want the final `pull-request` stage to inspect provider credentials and attempt provider-appropriate PR/MR/review creation, such as GitHub `gh`, Azure Repos `az repos pr create`, or Sapling/Phabricator tooling; Ralph's own PR-creation instructions live in that final stage and run only after approval.
296
+ Each `ralph` run uses the raw `prompt` exactly as supplied as the operative objective for research, orchestration, and review, and stores `acceptance_criteria` as the immutable literal contract (defaulting to the prompt when omitted). Shared literal-contract prompt language forbids adding behaviors, restrictions, or error conditions beyond the prompt/acceptance criteria and requires surfacing conflicts with external knowledge; Ralph does not run an initial prompt-refinement stage. Each iteration transforms that raw prompt with `/skill:prompt-engineer Transform the following user request into a codebase and online research question which can be thoroughly explored: ...` (`research-prompt-refinement`), researches that transformed question with `/skill:research-codebase ...`, and writes the findings under `research/`. The research, orchestrator, and reviewer prompts carry `acceptance_criteria` next to the literal contract, so orchestrators should pass the ORIGINAL task text when launching follow-up Ralph runs from reviewer findings. The orchestrator starts from an observable acceptance/contract matrix derived from the literal prompt/acceptance criteria (one row per clause mapped to the concrete observable check that proves it) and is prompted to model states, transitions, and invariants explicitly when the work is stateful; it treats the research artifact as its primary implementation context, initializes/updates an OS-temp implementation notes file while generating verifiable evidence for any claims it records in the notes and reviewer artifacts, delegates implementation through sub-agents, repairs unresolved reviewer findings as one consolidated batch (with durable regression evidence for reproduced findings) rather than one finding per iteration, and asks two independent reviewers (`reviewer-a` and `reviewer-b`) to inspect the patch directly against `base_branch`. The reviewer fan-out runs reviewers on different primary model families (Claude Fable 5 and GPT-5.5 Codex, with shared fallbacks) so the adversarial review gets cross-model coverage instead of repeated passes from one model, and each reviewer is instructed to first derive its own adversarial check list from the literal contract — boundary/edge/negative probes plus state/transition/invariant probes — before relying on the implementation notes, orchestrator report, or worker-authored tests. Ralph's orchestrator and reviewers are prompted to verify user-visible behavior end-to-end when practical, using `playwright-cli`-skilled subagents for web/frontend flows that may depend on backend/API behavior and tmux-skilled subagents for TUI or terminal-app scenarios. They must assume credentials/auth/environment access exists until concrete checks plus an actual app/flow launch attempt prove otherwise; skipped E2E is valid only when exact attempted commands and observed failure output are recorded. For UI-applicable or full-stack changes, the orchestrator runs a `playwright-cli` end-to-end QA pass and records a reviewable proof video (referenced in the implementation notes and surfaced as `qa_video_path`); reviewers receive that path and must inspect the actual video before treating it as proof. When `create_pr=true`, the final `pull-request` stage attaches or links that video to the created PR/MR/review after reviewer approval. If reviewers find issues, the next `research-prompt-refinement` and research stages receive the review artifact path (whose `review-round-latest.json` now also carries a deduplicated cross-reviewer `consolidated_findings` batch) so follow-up research can address unresolved findings, and research stages fork from prior research session data when available. The loop stops only when both reviewers independently approve or `max_loops` is reached, so the bounded loop always stops with an inspectable review round. Ralph findings include the same `objective_alignment` classification used by Goal, and each reviewer derives a single authoritative `stop_review_loop` boolean from that evidence: `required_by_objective` findings mean `false` at any priority (P3 included, because severity labels alone never dismiss objective-relevant findings), `consistent_with_objective` P0/P1/P2 findings mean `false` while P3 remains a non-blocking nice-to-have, and `beyond_objective`/`contradicts_objective` findings are surfaced but non-blocking so they are not silently converted into new requirements. The loop gate approves deterministically on `stop_review_loop=true` plus a null `reviewer_error` (parse failures count as non-approval) without recomputing approval from the findings arrays. Ralph review decisions also include `requirements_traceability`, a clause-by-clause evidence map over every explicit prompt/acceptance-criteria requirement kept as audit evidence for deriving the flag; reviewers are explicitly told that process-only clauses (reviewer quorum, and the authorized post-approval PR/MR/review final action when `create_pr=true`) must never hold the flag at `false`. Worker-authored tests or snapshots passing are circular evidence unless tied to independent current-state proof. By default Ralph does not start the final `pull-request` stage, and `pr_report` is omitted. Prompt text alone does not opt in. Pass `create_pr=true` only when you explicitly want the final `pull-request` stage to inspect provider credentials and attempt provider-appropriate PR/MR/review creation, such as GitHub `gh`, Azure Repos `az repos pr create`, or Sapling/Phabricator tooling; Ralph's own PR-creation instructions live in that final stage and run only after approval.
297
297
 
298
298
  Each Ralph review artifact and `review-round-latest.json` includes a `convergence_decision` summary with `parsed`, `approved`, `stopReviewLoop`, `nextAction`, `finalActionRemaining`, and `diagnostics`. This makes malformed or missing structured reviewer output visible as a parse failure, separate from a parsed reviewer rejection or blocking finding. When `create_pr=true`, reviewers are told that PR/MR/review creation is a post-approval final action: if implementation and validation requirements are proven and only PR creation remains, the implementation can approve with `finalActionRemaining: true` and `nextAction: "pull-request"` instead of consuming another orchestration iteration. When both reviewers converge, the latest round records `approved: true`, `stopReviewLoop: true`, and `nextAction: "pull-request"` when `create_pr=true` (otherwise `"finish"`), and the implementation loop stops before the final handoff stage.
299
299
 
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@bastani/atomic",
3
- "version": "0.9.7",
3
+ "version": "0.9.8",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bastani/atomic",
9
- "version": "0.9.7",
9
+ "version": "0.9.8",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
- "@bastani/atomic-natives": "0.9.7",
12
+ "@bastani/atomic-natives": "0.9.8",
13
13
  "@bufbuild/protobuf": "^2.12.1",
14
14
  "@earendil-works/pi-agent-core": "^0.80.6",
15
15
  "@earendil-works/pi-ai": "^0.80.6",
@@ -515,16 +515,16 @@
515
515
  }
516
516
  },
517
517
  "node_modules/@bastani/atomic-natives": {
518
- "version": "0.9.7",
519
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives/-/atomic-natives-0.9.7.tgz",
518
+ "version": "0.9.8",
519
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives/-/atomic-natives-0.9.8.tgz",
520
520
  "license": "MIT",
521
521
  "optionalDependencies": {
522
- "@bastani/atomic-natives-darwin-arm64": "0.9.7",
523
- "@bastani/atomic-natives-darwin-x64": "0.9.7",
524
- "@bastani/atomic-natives-linux-arm64-gnu": "0.9.7",
525
- "@bastani/atomic-natives-linux-x64-gnu": "0.9.7",
526
- "@bastani/atomic-natives-win32-arm64-msvc": "0.9.7",
527
- "@bastani/atomic-natives-win32-x64-msvc": "0.9.7"
522
+ "@bastani/atomic-natives-darwin-arm64": "0.9.8",
523
+ "@bastani/atomic-natives-darwin-x64": "0.9.8",
524
+ "@bastani/atomic-natives-linux-arm64-gnu": "0.9.8",
525
+ "@bastani/atomic-natives-linux-x64-gnu": "0.9.8",
526
+ "@bastani/atomic-natives-win32-arm64-msvc": "0.9.8",
527
+ "@bastani/atomic-natives-win32-x64-msvc": "0.9.8"
528
528
  },
529
529
  "engines": {
530
530
  "bun": ">=1.3.14",
@@ -532,8 +532,8 @@
532
532
  }
533
533
  },
534
534
  "node_modules/@bastani/atomic-natives-darwin-arm64": {
535
- "version": "0.9.7",
536
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-arm64/-/atomic-natives-darwin-arm64-0.9.7.tgz",
535
+ "version": "0.9.8",
536
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-arm64/-/atomic-natives-darwin-arm64-0.9.8.tgz",
537
537
  "license": "MIT",
538
538
  "os": [
539
539
  "darwin"
@@ -544,8 +544,8 @@
544
544
  "optional": true
545
545
  },
546
546
  "node_modules/@bastani/atomic-natives-darwin-x64": {
547
- "version": "0.9.7",
548
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-x64/-/atomic-natives-darwin-x64-0.9.7.tgz",
547
+ "version": "0.9.8",
548
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-x64/-/atomic-natives-darwin-x64-0.9.8.tgz",
549
549
  "license": "MIT",
550
550
  "os": [
551
551
  "darwin"
@@ -556,8 +556,8 @@
556
556
  "optional": true
557
557
  },
558
558
  "node_modules/@bastani/atomic-natives-linux-arm64-gnu": {
559
- "version": "0.9.7",
560
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-gnu/-/atomic-natives-linux-arm64-gnu-0.9.7.tgz",
559
+ "version": "0.9.8",
560
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-gnu/-/atomic-natives-linux-arm64-gnu-0.9.8.tgz",
561
561
  "license": "MIT",
562
562
  "os": [
563
563
  "linux"
@@ -571,8 +571,8 @@
571
571
  "optional": true
572
572
  },
573
573
  "node_modules/@bastani/atomic-natives-linux-x64-gnu": {
574
- "version": "0.9.7",
575
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-gnu/-/atomic-natives-linux-x64-gnu-0.9.7.tgz",
574
+ "version": "0.9.8",
575
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-gnu/-/atomic-natives-linux-x64-gnu-0.9.8.tgz",
576
576
  "license": "MIT",
577
577
  "os": [
578
578
  "linux"
@@ -586,8 +586,8 @@
586
586
  "optional": true
587
587
  },
588
588
  "node_modules/@bastani/atomic-natives-win32-arm64-msvc": {
589
- "version": "0.9.7",
590
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-arm64-msvc/-/atomic-natives-win32-arm64-msvc-0.9.7.tgz",
589
+ "version": "0.9.8",
590
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-arm64-msvc/-/atomic-natives-win32-arm64-msvc-0.9.8.tgz",
591
591
  "license": "MIT",
592
592
  "os": [
593
593
  "win32"
@@ -598,8 +598,8 @@
598
598
  "optional": true
599
599
  },
600
600
  "node_modules/@bastani/atomic-natives-win32-x64-msvc": {
601
- "version": "0.9.7",
602
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-x64-msvc/-/atomic-natives-win32-x64-msvc-0.9.7.tgz",
601
+ "version": "0.9.8",
602
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-x64-msvc/-/atomic-natives-win32-x64-msvc-0.9.8.tgz",
603
603
  "license": "MIT",
604
604
  "os": [
605
605
  "win32"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/atomic",
3
- "version": "0.9.7",
3
+ "version": "0.9.8",
4
4
  "description": "Atomic coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "atomicConfig": {
@@ -77,7 +77,7 @@
77
77
  "prepublishOnly": "bun run clean && bun run build && bun run shrinkwrap"
78
78
  },
79
79
  "dependencies": {
80
- "@bastani/atomic-natives": "0.9.7",
80
+ "@bastani/atomic-natives": "0.9.8",
81
81
  "@bufbuild/protobuf": "^2.12.1",
82
82
  "@earendil-works/pi-agent-core": "^0.80.6",
83
83
  "@earendil-works/pi-ai": "^0.80.6",