@beremaran/ralphie 0.0.0-stage → 0.2.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 (37) hide show
  1. package/CHANGELOG.md +832 -0
  2. package/LICENSE +21 -0
  3. package/README.md +53 -2
  4. package/dist/ralphie.js +33691 -0
  5. package/docs/README.md +71 -0
  6. package/docs/architecture.md +159 -0
  7. package/docs/cli-reference.md +126 -0
  8. package/docs/configuration.md +269 -0
  9. package/docs/development.md +248 -0
  10. package/docs/getting-started.md +134 -0
  11. package/docs/operations-and-recovery.md +328 -0
  12. package/docs/safety.md +189 -0
  13. package/docs/workflows.md +411 -0
  14. package/package.json +83 -3
  15. package/vendor/mattpocock-skills/LICENSE +21 -0
  16. package/vendor/mattpocock-skills/code-review/SKILL.md +87 -0
  17. package/vendor/mattpocock-skills/code-review/agents/openai.yaml +3 -0
  18. package/vendor/mattpocock-skills/codebase-design/DEEPENING.md +37 -0
  19. package/vendor/mattpocock-skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
  20. package/vendor/mattpocock-skills/codebase-design/SKILL.md +114 -0
  21. package/vendor/mattpocock-skills/codebase-design/agents/openai.yaml +3 -0
  22. package/vendor/mattpocock-skills/diagnosing-bugs/SKILL.md +138 -0
  23. package/vendor/mattpocock-skills/diagnosing-bugs/agents/openai.yaml +3 -0
  24. package/vendor/mattpocock-skills/diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
  25. package/vendor/mattpocock-skills/implement/SKILL.md +15 -0
  26. package/vendor/mattpocock-skills/implement/agents/openai.yaml +5 -0
  27. package/vendor/mattpocock-skills/lock.json +37 -0
  28. package/vendor/mattpocock-skills/tdd/SKILL.md +38 -0
  29. package/vendor/mattpocock-skills/tdd/agents/openai.yaml +3 -0
  30. package/vendor/mattpocock-skills/tdd/mocking.md +59 -0
  31. package/vendor/mattpocock-skills/tdd/tests.md +77 -0
  32. package/vendor/mattpocock-skills/to-tickets/SKILL.md +105 -0
  33. package/vendor/mattpocock-skills/to-tickets/agents/openai.yaml +5 -0
  34. package/vendor/mattpocock-skills/triage/AGENT-BRIEF.md +207 -0
  35. package/vendor/mattpocock-skills/triage/OUT-OF-SCOPE.md +105 -0
  36. package/vendor/mattpocock-skills/triage/SKILL.md +112 -0
  37. package/vendor/mattpocock-skills/triage/agents/openai.yaml +5 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,832 @@
1
+ # Changelog
2
+
3
+ All notable changes to Ralphie are documented here. The project follows
4
+ [Semantic Versioning](https://semver.org/) and the Keep a Changelog structure.
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [0.2.0] - 2026-10-07
9
+
10
+ This release replaces the in-process pi agent with headless harness CLIs and
11
+ moves every setting into a configuration file. It contains breaking changes to
12
+ the command line, the configuration, the run state, the JSON Lines output, and
13
+ the way issues are selected and handed back to humans. Read the Removed and
14
+ Changed sections before upgrading.
15
+
16
+ ### Added
17
+
18
+ - Transient harness failures no longer hand issues off. A rate, usage, session
19
+ or quota limit, an overloaded or unreachable provider, exhausted credits or an
20
+ expired login now defers the issue untouched (no labels or comments change),
21
+ stops the rest of the queue, and exits `75` with a message naming the failure
22
+ and its reset time. Definite failures still hand off. `scripts/live-smoke.ts`
23
+ reports such a halt as INCONCLUSIVE and requires a decomposition to have a
24
+ child worked to a genuine outcome before it passes. It also waits for the
25
+ created issues to appear in the label listing before it starts Ralphie, passes
26
+ the implementation scenario only when Ralphie reported the closure and a new
27
+ commit added `greeting.txt`, and saves each run's `--output json` log to a
28
+ temp file whose path and `Run completed` line it prints.
29
+ - Parallel reviewer sessions in one working directory no longer collide while
30
+ skills are injected (`ENOTEMPTY` when setting a same-named repository skill
31
+ aside). They share one injection, and the last release restores the checkout,
32
+ including directories Ralphie created.
33
+ - Harnesses and roles. Every agent session runs on a headless harness CLI:
34
+ Claude Code (`claude`, the default), Codex (`codex`), pi (`pi`) or OpenCode
35
+ (`opencode`). The `harnesses` (per-harness `model`, `effort`, `approval`) and
36
+ `roles` keys assign a harness, model and effort to each of the eight roles
37
+ (`triager`, `preflight`, `implementer`, `fixer`, `standards-reviewer`,
38
+ `spec-reviewer`, `resolution-verifier`, `decomposer`). Every role falls back
39
+ to `roles.default`, both reviewers to `roles.reviewer`, and the fixer to the
40
+ implementer. See `docs/configuration.md`.
41
+ - OpenCode is experimental. Its adapter has not been verified against a live
42
+ model, so startup refuses any role assigned to `opencode` until the
43
+ configuration sets `harnesses.opencode.experimental: true`.
44
+ - YAML configuration. Ralphie reads `$XDG_CONFIG_HOME/ralphie/config.yaml` (else
45
+ `~/.config/ralphie/config.yaml`, or `--config <path>`), validated with a
46
+ strict schema at startup. Settings layer from defaults, the top level, the
47
+ matching `repos."owner/repo"` entry, and repeatable `--set path=value`
48
+ overrides. Review rounds and verification fixes are configurable under
49
+ `limits`, and `labels` maps the five canonical triage labels.
50
+ - `ralphie init` detects the harnesses on PATH and writes a commented config
51
+ file at the default location (or `--config`), never overwriting an existing
52
+ one. A run without a config file points at it.
53
+ - `approval: safe | yolo` (top level, per repository, and per harness) sets how
54
+ the editing roles run. Startup verifies that every assigned harness is
55
+ installed, that safe approval is available, and that pi and OpenCode editing
56
+ roles are set to `yolo`, failing within seconds with the config change that
57
+ fixes it.
58
+ - `limits.sessionTimeoutMinutes` (`edit` 60, `readOnly` 15) bounds each session;
59
+ a timeout kills the session's process group. `limits.maxBudgetUsd` caps spend
60
+ per session, enforced only by Claude Code, with a startup warning for the
61
+ other harnesses.
62
+ - Vendored skills. Sessions run Matt Pocock's `triage`, `to-tickets`,
63
+ `implement`, `tdd`, `code-review`, `codebase-design` and `diagnosing-bugs`
64
+ skills from a pinned copy in `vendor/mattpocock-skills/`, packaged with the
65
+ release. Ralphie injects them (or `skills.dir`) into the harness's project
66
+ skills directory for the session, excludes them from Git, removes them
67
+ afterwards, and generates `docs/agents` tracker and label docs only when the
68
+ repository lacks them. `bun run skills:sync` refreshes the copy and a
69
+ scheduled workflow opens a PR when upstream moves.
70
+ - Hand-offs, always on. Anything that needs a human moves the issue to
71
+ `needs-info` (missing information, conflicting requirements, cannot
72
+ reproduce, outdated premise; Triage Notes comment) or `ready-for-human`
73
+ (exhausted implementation attempts or verification repairs, the
74
+ decomposition depth limit, an external dependency, a decision that needs
75
+ human judgment; write-up with the diagnostics location). Ralphie replaces
76
+ the issue's single triage state label, so the next run's intake skips it.
77
+ Every comment Ralphie posts starts with the AI disclaimer.
78
+ - Opt-in AFK triage (`triage.enabled`, default off). A read-only `triager`
79
+ session runs the vendored `/triage` over unlabelled issues, `needs-triage`
80
+ issues and `needs-info` issues the reporter has answered. It promotes an issue
81
+ to `ready-for-agent` with an Agent Brief (implemented in the same run), hands
82
+ off to `needs-info` or `ready-for-human`, or closes an already implemented
83
+ issue as completed once a fresh resolution verifier proves it. It never
84
+ applies `wontfix` and never writes `.out-of-scope/`.
85
+ - Candidate-commit review gate. After verification Ralphie creates a local
86
+ candidate commit and runs a standards reviewer and a spec reviewer in
87
+ parallel over the range diff; smells never block. Approved candidates are
88
+ squashed into the single delivered commit.
89
+ - Session isolation: sessions start without `GH_TOKEN`, `GITHUB_TOKEN` and the
90
+ enterprise variants, with an empty `GH_CONFIG_DIR`, origin's push URL
91
+ disabled inside the workspace, and a fingerprint check that fails any
92
+ read-only session that changed the checkout.
93
+ - `bun run smoke:live`, an opt-in script that runs the CLI against a scratch
94
+ repository per installed harness. It is not part of `bun run check` or CI.
95
+ - Harness-neutral session events in JSON Lines output (see Changed) and a
96
+ shared contract suite for harness adapters.
97
+
98
+ ### Changed
99
+
100
+ - Breaking: JSON Lines events that reported the `grounding` and
101
+ `issue-grounding` stages now report `preflight` (pre-flight work) or
102
+ `hand-off` (hand-off decisions and their verification).
103
+ - Every terminal implementation failure (repeated blocking review findings, a
104
+ review fix that changes nothing, a failed or timed-out session, a repair that
105
+ changes the tree after the last review) now ends in an
106
+ `implementation_exhausted` hand-off, not only an exhausted retry budget.
107
+ - Agent session failures in pre-flight, resolution verification and
108
+ decomposition now become `ready-for-human` hand-offs too; checkout and GitHub
109
+ errors still fail so the next run retries.
110
+ - Session isolation also removes `SSH_AUTH_SOCK` and askpass helpers, empties
111
+ the global and system git config and credential helpers, disables git
112
+ terminal prompts and makes `GIT_SSH_COMMAND` fail, so a session cannot push
113
+ over ssh even in yolo mode. Keys readable on disk or in a keyring still need
114
+ a dedicated OS user.
115
+ - The latest `## Agent Brief` comment is exempt from the 4000-character comment
116
+ trim and the 20-comment limit when issues are read.
117
+ - `--notify-needs-attention` and `--needs-attention-label` fail with tailored
118
+ errors; startup now checks each harness against a minimum version and skips
119
+ the `triager` role when `triage.enabled` is false.
120
+ - Breaking: Ralphie is invoked as `ralphie [owner/]repo` and requires the
121
+ configuration file; a missing file fails with the path it looked for. A bare
122
+ repository name takes its owner from `defaultOwner` or the `gh` login.
123
+ - Breaking: intake reads only open issues carrying the `labels.ready-for-agent`
124
+ label (and every `intake.requireLabels` label). Issues without them are never
125
+ read, so existing queues must be labelled or run with `triage.enabled`.
126
+ - Breaking: one read-only pre-flight session per issue replaces the grounding
127
+ session and the 0-5 complexity assessment. It returns `actionable` with
128
+ `fitsOneSession`, `already_resolved`, `blocked` (skipped without a label
129
+ change) or `hand_off`. Open-blocker skips from queue order are `skipped`
130
+ outcomes that change nothing on GitHub. Decomposition no longer carries a
131
+ complexity estimate.
132
+ - Breaking: hand-offs replace "needs attention" and the notification flags
133
+ throughout. The outcome kind, result field, progress stage and status, and
134
+ artifacts are renamed (`hand-off`, `hand_off`, `hand-off-decision`,
135
+ `pending-hand-off`). The implementer's own result keeps
136
+ `status: needs_attention`, which is routed as a hand-off request.
137
+ - Breaking: run state is version 15 (version 13 replaced `selection` with the
138
+ per-role assignments, 14 renamed the hand-off fields, 15 added the `deferred`
139
+ outcome). Older state is not
140
+ migrated, and artifacts written by earlier versions (`complexity-decision`,
141
+ decomposition breakdowns with `body` and `estimatedComplexity`) are not read.
142
+ - Breaking: `--output json` carries `session_event` records instead of
143
+ `agent_event` records: `{type, sessionID, directory, harness, title?, event}`
144
+ where `event` is one harness-neutral shape (`session_started`,
145
+ `assistant_text`, `tool_call`, `tool_result`, `error`, `usage`,
146
+ `session_finished`). Tool names and inputs are the harness's own. See
147
+ `docs/operations-and-recovery.md`.
148
+ - Breaking: decomposition runs the vendored `/to-tickets` skill. Children use
149
+ `{key, title, whatToBuild, acceptanceCriteria, dependsOn}` and are created
150
+ blockers first in the to-tickets template (`## Parent`, `## What to build`,
151
+ `## Acceptance criteria`, `## Blocked by`) with the agent-ready label and the
152
+ parent's `intake.requireLabels` labels. The parent issue's body is never rewritten
153
+ any more; it is recognised by its native sub-issues, and closed with one
154
+ disclaimed comment when its children are done.
155
+ - Implementation runs the vendored `/implement` skill, and the implementer
156
+ writes the commit message (no separate commit-message session). Fixes resume
157
+ the implementer's session where the harness allows it, starting a fresh
158
+ session when resuming fails or the estimated context nears 400,000 characters.
159
+ - Read-only sessions have no shell on Claude Code, so Ralphie puts the range
160
+ diff in the reviewers' prompts.
161
+ - Structured results are validated values, with the optional hand-off request
162
+ as a field of the result instead of a tool call; repair sessions can no
163
+ longer raise one.
164
+ - Interactive output: the TUI header no longer shows a model. Pause (`p`), stop
165
+ (`s`) and quit (`q`) are unchanged.
166
+
167
+ ### Removed
168
+
169
+ - Breaking: the in-process pi SDK runtime, its credential store and model
170
+ catalog, and the `@earendil-works/pi-agent-core` and `@earendil-works/pi-ai`
171
+ dependencies. Ralphie no longer reads `~/.pi/agent/auth.json`,
172
+ `PI_CODING_AGENT_DIR` or provider API-key variables; each harness CLI keeps
173
+ its own login. The pi CLI remains available as a harness.
174
+ - Breaking: the TUI model picker (`m`).
175
+ - Breaking: `--branch` (`-b`), `--verify-command`, `--issue-label`,
176
+ `--issue-sort`, `--implementation-attempts`, `--max-decomposition-depth`,
177
+ `--workspace`, `--model` and `--thinking`. Each fails with an error naming
178
+ the configuration key that replaces it (`docs/configuration.md`).
179
+ - Breaking: `--notify-needs-attention`, `--needs-attention-label` and the
180
+ `notifications` configuration section. Hand-offs are always on, so there is
181
+ nothing left to opt into; each flag fails with a tailored error (see
182
+ Changed).
183
+
184
+ ## Before the harness release
185
+
186
+ Everything below predates the harness release. It was kept under a single
187
+ Unreleased heading, so it mixes what shipped in v0.1.0 to v0.1.2 with changes
188
+ merged afterwards and is not attributed to a version. Mentions of removed
189
+ surfaces (OpenCode, the pi SDK, `--on-needs-attention`, `lgtm`, and so on)
190
+ describe history, not the current tool.
191
+
192
+ ### Removed
193
+
194
+ - Remove the `quiet` and `verbose` output modes. `--output` now accepts only
195
+ `default` (live transcript and progress) and `json` (JSON Lines). The
196
+ structured `details` payload is no longer rendered on human-readable lines;
197
+ JSON output and the `events.jsonl` audit retain it.
198
+
199
+ - Remove `--max-issues`, `--implementation-fallback-model`, `--resume`,
200
+ `--dry-run`, and `--clean`. Every run now processes the whole matching open
201
+ issue queue with no budget, retries always use the selected model, and there
202
+ is no preview or resume path. The workspace is removed before preparation
203
+ and after a successful run; cleanup is skipped when the run fails, drains
204
+ with issue failures, or is cancelled. Notification recovery, state loading,
205
+ legacy-state migration, and the read-only dry-run executor and planner are
206
+ gone. `RunState` is version 12.
207
+
208
+ - Remove the halt policies. `--on-needs-attention` and `--on-issue-failure` are
209
+ gone; a needs-attention outcome or an ordinary issue failure now always
210
+ records the outcome, leaves the issue open, and continues the queue. A
211
+ drained run exits `1` when any issue failed, and the former handled-stop exit
212
+ status `2` no longer exists.
213
+
214
+ - Remove dead integration weight inherited from the removed modes: managed
215
+ feature-branch revision safety, the feature-branch and base-restore Git
216
+ operations, the always-false `allowMissingRemoteBranch` seam, unused safety
217
+ exports, and progress rendering for events pi never emits (compaction,
218
+ automatic/summarization retries, queue/session/entry updates, thinking-level
219
+ changes, and bash execution updates). No behavior change.
220
+
221
+ - Remove the `pr` workflow. Ralphie now always delivers through the direct
222
+ `lgtm` path: the `--workflow` flag, feature branches, pull requests, the
223
+ post-PR review/revision coordinator, the check gate, and the read-only check
224
+ observer are gone, along with their Git, run-state, artifact, prompt, test,
225
+ and documentation surfaces. `RunState` is version 10.
226
+
227
+ - Remove every top-level execution mode other than the issue workflow. The
228
+ `--mode` flag, `maintain-issues`, `get-pipelines-green`, and
229
+ `--duplicate-action`/`--max-attempts`/`--pipeline-timeout` are gone, along
230
+ with the maintenance snapshot/planning/state subsystem, the pipeline
231
+ delivery/diagnostics/repair subsystem, and their tests and docs.
232
+
233
+ - Replace the external OpenCode server integration and the multi-harness/ACP
234
+ discovery layer with an in-process agent runtime (itself replaced by the
235
+ harness CLIs, see above). Deleted
236
+ `src/harness/` (six-kind harness contracts and Antigravity
237
+ executable/ACP discovery) and `src/opencode/` (server client, transport,
238
+ permission watcher, and model-variant catalog). `--opencode-url`,
239
+ `--opencode-token`, `OPENCODE_URL`, `OPENCODE_TOKEN`, and the mandatory
240
+ Antigravity preflight are gone; no external agent server is required.
241
+
242
+ - Remove every non-npm distribution channel: the native standalone bundles
243
+ (four-platform `bun compile` builds, `scripts/install.sh`, `bun run targets`
244
+ catalog machinery), the Homebrew tap/formula (generators, validators,
245
+ reconciliation, checksums), the Docker image and container registry
246
+ publication (GHCR, OCI indexes, tag plans, SBOM/SLSA attestations), and the
247
+ release checksum/Sigstore verification surface (`SHA256SUMS`). The release
248
+ and public-distribution workflows are replaced by one tag-triggered publish
249
+ workflow (`.github/workflows/npm-publish.yml`): validate the tag/package
250
+ version (`scripts/validate-npm-context.ts`), build the package bundle,
251
+ smoke-check the packed tarball, and `bun publish`. `bunx
252
+ @beremaran/ralphie` is the only supported way to run Ralphie.
253
+
254
+ - Remove the shared redaction implementation (`src/shared/redaction.ts`,
255
+ `tests/shared/redaction.test.ts`) and every `[REDACTED]` reporting assertion.
256
+ `redactSensitiveText`/`redactSensitiveValue` no longer exist; the terminal
257
+ control sanitizer they contained moved to `src/shared/terminal.ts`
258
+ (`stripTerminalControls`).
259
+
260
+ ### Changed
261
+
262
+ - Replace the hand-rolled interactive renderer with OpenTUI, the same
263
+ terminal rendering core OpenCode 1.0 uses. Interactive runs now render a
264
+ borderless layout: a background header line with the repository, active
265
+ model, and pause state; an issue sidebar with outcome glyphs and a
266
+ processed count; a per-issue streaming transcript with role bullets,
267
+ indented assistant text, dim thinking, and one-row tool calls with elapsed
268
+ time; and a footer status line. The sidebar lists the discovered queue
269
+ with each issue's outcome and follows the active issue until the user
270
+ navigates; `[`/`]` (or Ctrl+Left/Right) switch between processed, active, and
271
+ queued issues. Interactive runs start paused so the discovered plan can be
272
+ inspected before work begins; `p` resumes or pauses the queue between issues,
273
+ `s` stops the queue after the active issue and drains the run with a "Run
274
+ stopped by request" summary, and `q` cancels immediately. The
275
+ footer/breadcrumb/terminal-controller stack and its PTY test suites are gone. Plain (piped/CI) and JSON output are unchanged in
276
+ shape, and the interactive renderer loads lazily so help, plain, and JSON
277
+ paths never touch the native module.
278
+
279
+ - Report the discovered issue queue and skipped issues through progress:
280
+ `issue-queue` events carry the pending issue numbers and titles, and an issue
281
+ that no longer matches the filters is reported as skipped instead of
282
+ disappearing silently. Plain output gains one line per skipped issue and the
283
+ JSON audit gains the queue details.
284
+
285
+ - Give GitHub adapters an owned session. `connect()` authenticates once and
286
+ the capability adapters read the client internally, so no port method,
287
+ executor context, or workflow call carries an Octokit handle; the SDK is
288
+ confined to `src/github/adapters/`.
289
+
290
+ - Inject `Clock`, `IdGenerator`, and `RunLayout` through the runtime bundle.
291
+ Workflow, artifacts, and recovery no longer call `new Date()`,
292
+ `randomUUID()`, or compose workspace paths; the composition root resolves
293
+ the workspace expansion and run layout.
294
+
295
+ - Move parent completion and issue preparation into `issues/app/` with their
296
+ contracts in `issues/ports.ts`, and add the `IssueWorkflow` driving port so
297
+ the CLI depends on the use-case contract rather than the workflow function.
298
+
299
+ - Add shared port contract suites under `tests/contracts/` that run the same
300
+ behavioral spec against in-memory fakes and the live adapters for
301
+ `RunEventLog` and `IssueArtifactStore`.
302
+
303
+ - Restructure the source into hexagonal, context-first packages: each bounded
304
+ context (`agent`, `pi`, `github`, `git`, `issues`, `progress`, `run`,
305
+ `process`, `workspace`, `workflow`) owns its `ports.ts` contract, its domain
306
+ model, and its `adapters/` implementation together. `src/runtime.ts` and
307
+ `src/command.ts` are the only modules that instantiate adapters. Non-adapter
308
+ code imports no `node:fs`, `node:child_process`, vendor SDK, or process
309
+ stream; Octokit appears only inside the `github` context; the artifact and
310
+ recovery file systems are injected ports implemented under
311
+ `src/issues/adapters/`. `tests/architecture.test.ts` enforces these rules.
312
+
313
+ - Decouple execution from presentation. The progress contract now lives in
314
+ `src/ports/progress.ts` (no rendering or I/O dependencies), the renderers in
315
+ `src/progress/` implement it, and execution code no longer imports the
316
+ presentation layer. The `events.jsonl` audit moved out of the renderer into
317
+ `src/run/event-log.ts` and is closed by the run before workspace removal; the
318
+ dead `writeRaw`/`stopPersisting` surface is gone. `tests/architecture.test.ts`
319
+ enforces the import directions and process-stream ownership.
320
+
321
+ - Verification is now opt-in. The `package.json` `bun run check` discovery
322
+ default is removed; when no `--verify-command` is supplied the deterministic
323
+ gate is skipped and review proceeds on the staged diff. Supplied commands
324
+ still run through `/bin/sh`, their evidence is still bound to the staged
325
+ tree, and non-zero exits still trigger the bounded repair loop.
326
+
327
+ - Collapse every per-stage thinking setting into one `--thinking` level applied
328
+ to all sessions. The `--grounding-thinking`, `--implementation-thinking`,
329
+ `--complexity-thinking`, `--review-thinking`, and `--commit-thinking` flags
330
+ are gone; the default level remains `medium`.
331
+
332
+ - Pi is now the only execution backend. `--model provider/model` resolves
333
+ against pi's built-in catalog (defaulting to the model saved in pi's
334
+ `settings.json`), thinking flags accept pi levels (`off` through `max`), and
335
+ credentials resolve through `~/.pi/agent/auth.json`
336
+ (`PI_CODING_AGENT_DIR`) with provider environment variables as fallback.
337
+ - Agent tools are pi's built-in `read`, `write`, `edit`, and `bash`, rooted at
338
+ the repository checkout and guarded before execution (delivery-state shell
339
+ denylist plus workspace path containment); review-profile sessions expose
340
+ read-only tools. JSON transcript records are now `agent_event`, and the
341
+ progress stage `opencode-runtime` is `agent-runtime`.
342
+ - Add `@earendil-works/pi-agent-core`, `@earendil-works/pi-ai`, and
343
+ `proper-lockfile` as runtime dependencies; pi packages stay external to the
344
+ bundle so their lazy provider SDKs install through npm.
345
+
346
+ - Complete the post-PR review and revision lifecycle. `pr` delivery now
347
+ persists the immutable pull-request base/head, runs a resumable coordinator
348
+ with one shared five-attempt review budget, performs fresh exact-tree
349
+ non-force revisions when findings require changes, publishes head-scoped
350
+ review attempts idempotently, and records review/revision/publication/check/
351
+ merge boundaries in RunState v9 and the per-issue delivery artifact.
352
+ Merging requires a fail-closed proof containing approved structured review
353
+ evidence and a stable green check snapshot for the same PR/base/head; stale
354
+ or incomplete proof cannot merge. Exhaustion and recoverable delivery
355
+ failures retain the open issue, branch, and PR. Added service, coordinator,
356
+ workflow, resume, failure-boundary, and end-to-end coverage plus the
357
+ lifecycle/recovery documentation.
358
+
359
+ - Complete the first user-visible `--mode maintain-issues` release slice. The
360
+ mode is a bounded one-shot issue-reconciliation pass separate from the
361
+ default `--mode issues` delivery queue: read-only OpenCode planning feeds
362
+ schema/policy validation, while deterministic GitHub services perform only
363
+ live-revalidated additive labels, managed questions/answers, and reciprocal
364
+ relationship or duplicate links. Duplicate closure remains an explicit
365
+ `--duplicate-action close` opt-in with link → existing `duplicate` label →
366
+ duplicate-close ordering; uncertainty, stale data, and insufficient evidence
367
+ skip or replan instead of guessing. Versioned maintenance state checkpoints
368
+ every action for exact resume, and maintenance dry runs perform no workspace,
369
+ GitHub, state-file, artifact, or event-log mutation. Added offline
370
+ fake-GitHub/OpenCode integration coverage for reconciliation, ambiguity,
371
+ interruption/resume, output modes, permissions, dry-run isolation, and exit
372
+ codes (`tests/integration/maintain-issues.test.ts`). The documentation records
373
+ the required permissions, output/recovery contract, and first-release
374
+ non-goals; no mutation-enabled network smoke test is included.
375
+
376
+ - Dependency-blocked issues (open queue prerequisites) are recorded as
377
+ needs-attention outcomes but no longer publish a needs-attention GitHub
378
+ comment or label: the opt-in notifier is reserved for agent-reported
379
+ blockers that need a human decision, while queue-order blocks resolve by
380
+ completing the open dependencies. The `--on-needs-attention` halt/continue
381
+ policy and run-level progress events are unchanged.
382
+
383
+ - Progress detail, activity rows, and short JSON snapshots are no longer
384
+ redacted. The reporting boundary now preserves supplied values verbatim
385
+ (`src/progress/activity.ts` sanitizes only terminal control sequences),
386
+ matching the already-lossless `opencode_event` transcript records and
387
+ durable event log. Credentials and other sensitive values pass through into
388
+ transcripts, breadcrumbs, JSON Lines, and `events.jsonl` exactly as
389
+ supplied; only terminal control sequences are stripped from human-readable
390
+ rows. Documentation (`README.md`, `docs/architecture.md`, and
391
+ `docs/operations-and-recovery.md`) now describes this intentional unredacted
392
+ output contract.
393
+
394
+ - Validate OpenCode model/variant compatibility before execution and fail fast
395
+ on silent turns. After the OpenCode runtime starts, the workflow lists the
396
+ server's model catalog (`src/opencode/server.ts`, `src/opencode/variants.ts`)
397
+ and checks every planned stage variant (grounding, complexity,
398
+ implementation, review, commit message, plus the implementation fallback
399
+ model) against the variants each model advertises (`default` is always
400
+ accepted). Unsupported combinations abort the run before any issue work with
401
+ the offending stage, model, available variants, and the exact
402
+ `--*-thinking` flag to adjust, instead of failing mid-run with a misleading
403
+ contract error. Separately, structured and unstructured prompts now treat a
404
+ turn that produces no assistant message (for example a server-side model
405
+ resolution failure) as a distinct silent-turn failure naming the model,
406
+ variant, and session, with no pointless contract-violation retries; genuine
407
+ contract misses now emit the transcript and include a response preview in
408
+ the error. Covered by `tests/opencode-variants.test.ts`, new silent-turn
409
+ cases in `tests/opencode-client.test.ts`, and fail-fast workflow tests.
410
+
411
+ - Lock down the cross-mode display contract with end-to-end regression
412
+ coverage: the interactive in-progress activity surface is measured in
413
+ physical terminal rows (never newline counts) and stays within the shared
414
+ three-row replaceable region across repeated tool calls, long
415
+ commands/paths, narrow terminals and resize, interleaved streamed assistant
416
+ text, ANSI/control-sequence boundaries, completion, failure, and cleanup;
417
+ streamed assistant text is preserved exactly, plain/CI output stays
418
+ deterministic and append-only with no carriage-return or ANSI cursor bytes,
419
+ JSON Lines output remains parseable and lossless, and quiet mode surfaces
420
+ no routine activity. The command-runtime display suite drives the real
421
+ coordinator wiring through `runCommand`, and the docs describe the bounded
422
+ interactive region, concise completion/error summaries, and the
423
+ noninteractive fallback.
424
+
425
+ - Route the OpenCode event stream and progress updates through the compact activity
426
+ surface in the real coordinator/CLI path: tool-call start/delta/end, tool
427
+ execution start/update/end, bash execution updates, streamed thinking,
428
+ compaction/retry lifecycle, and active progress changes map to bounded
429
+ activity rows in the replaceable interactive region. The human transcript no
430
+ longer streams multi-line partial/final tool output or streamed thinking;
431
+ each tool completion emits at most one concise `✓ <tool> done` line, and a
432
+ failure emits one sanitized, 140-character-bounded line with enough error
433
+ detail to act. Assistant text deltas, session headers, durable breadcrumbs,
434
+ and lossless JSON `opencode_event` records are unchanged, the region never clears
435
+ or corrupts assistant response bytes, and `--output verbose` keeps the live
436
+ row count at its fixed three-row cap. Plain, JSON, and quiet modes retain
437
+ their append-only/structured/failure-only contracts. Coordinator-level tests
438
+ cover repeated calls, missing ids, interleaved assistant text, success and
439
+ failure, and mode-specific behavior.
440
+
441
+ - Render the interactive activity view in one replaceable three-row terminal
442
+ region: the sticky stage/status line plus the bounded activity rows share a
443
+ single region whose total height never exceeds three terminal rows (no panel
444
+ added beneath the footer), every row is clipped before it can wrap, and each
445
+ replacement repaints the region in place using the terminal stream boundary
446
+ primitives: repaints are deferred while a transcript fragment is open
447
+ mid-line or a control sequence is incomplete, and the region clears/restores
448
+ without overwriting streamed assistant text, splitting an ANSI/control
449
+ sequence, or inserting bytes into a partial line. Resize, disposal, stale
450
+ rows, and completion removal are handled; cursor controls remain limited to
451
+ interactive mode, and plain, CI, piped, JSON, and quiet surfaces stay
452
+ append-only or structured with no cursor-control artifacts.
453
+
454
+ - Finalize the interactive footer layout as `durable-transcript-breadcrumbs`
455
+ (`INTERACTIVE_FOOTER_LAYOUT_STRATEGY`, `INTERACTIVE_FOOTER_USES_SCROLL_REGION=false`,
456
+ `INTERACTIVE_FOOTER_USES_RESERVED_ROW=false`): the status is an in-place
457
+ replaceable region below streamed content, never a reserved bottom row or
458
+ DECSTBM scroll region, so reserved-row/scroll-region cursor manipulation is
459
+ disabled (no DECSTBM, CUP, alternate-screen, or save/restore sequences; only
460
+ in-place erase and single-row step-up repaint the region with strict
461
+ clear-before-draw). Interactive mode requires stdin and stderr TTYs with `CI`
462
+ neither `"true"` nor `"1"`; footer-only repaints coalesce at roughly 100–125 ms
463
+ while transcript token deltas stream immediately; partial-line/control-open
464
+ fragments defer repaints, rows clip at their paint-time width, resize repaints
465
+ only at a safe boundary, and completion/interruption (SIGINT/Ctrl-C)/failure
466
+ erases the region, settles on a fresh line, and emits no further bytes.
467
+ Plain/CI output is deterministic append-only with no `ESC`/carriage-return or
468
+ footer residue, verbose never expands the three-row cap, quiet keeps failures
469
+ and handled needs-attention stops only, and JSON stays JSON Lines on stdout
470
+ with stderr empty. `README.md` and `docs/operations-and-recovery.md` now
471
+ publish exactly this tested contract,
472
+ locked by `tests/progress/interactive-footer-layout-strategy.test.ts`, the PTY
473
+ streaming-stress fixture, the real-PTY lifecycle fixture, and the
474
+ noninteractive cleanup matrix.
475
+
476
+ - Deliver managed feature-branch revisions as one deterministic operation
477
+ with authoritative remote reconciliation: the revision safety checks run
478
+ before staging/commit and again immediately before the push, the exact-tree
479
+ revision commit is created from the allowed staged tree, the push uses only
480
+ Git's non-force mode to the explicit `HEAD:refs/heads/<branch>` destination
481
+ ref, and the outcome is classified from the authoritative post-push
482
+ `git ls-remote` read (never from a tracking ref or command response alone).
483
+ The discriminated, typed outcome distinguishes `confirmed` delivery (remote
484
+ equals the new commit with a clean checkout, including a lost push response
485
+ reconciled to success), `external-movement` (remote no longer equals the
486
+ expected prior head: halt without retry or force), and `ambiguous` delivery
487
+ (remote read cannot prove whether the new commit arrived; the created clean
488
+ commit is retained for safe reconciliation). Movement detected before
489
+ staging/commit prevents the commit from being created, cancellation is
490
+ checked at every mutation boundary, the push is attempted at most once, and
491
+ the `lgtm` direct-push path and its shared, regression-tested helpers are
492
+ unchanged.
493
+
494
+ - Tighten human transcript bounds to 3 lines/140 characters: tool incremental
495
+ output uses `LIVE_OUTPUT_LIMIT=140`, thinking/assistant streams use the same
496
+ 140-character bound, and final previews truncate to 3 lines/140 characters
497
+ with the existing truncation marker. Truncated tool, thinking, and assistant
498
+ streams still report background totals (total characters and lines with a
499
+ `truncated` marker). JSON and durable logs remain lossless.
500
+
501
+ - Add the needs-attention recovery contract across the OpenCode boundary, issue
502
+ executor, recovery service, and local end-to-end path: bounded fenced
503
+ `needs-attention` blocks (`reason` one of `outdated_premise`,
504
+ `conflicting_requirements`, `missing_information`, `external_dependency`, or
505
+ `cannot_reproduce`, plus an optional message capped at 2,000 characters)
506
+ accompany the required schema-valid fenced `json` result from grounding,
507
+ complexity, implementation, review-fix, commit-message, review, and
508
+ decomposition sessions; each signal is confirmed by exactly one fresh
509
+ read-only verifier session before any further artifact, Git, or GitHub
510
+ mutation. A confirmed `needs_attention` disposition persists the structured
511
+ decision with its summary, evidence, questions, and issue-freshness
512
+ fingerprint, leaves the source issue open, performs no GitHub mutation and
513
+ no commit or push, and restores the clean checkpoint by removing staged,
514
+ unstaged, and untracked agent changes; verifier rejection continues the
515
+ original attempt, and diagnostic, restoration, or repository-invariant
516
+ failures are reported as recoverable rather than successful. Recovery
517
+ diagnostics live under
518
+ `runs/<run-id>/issues/<issue-number>/needs-attention-<id>/` with
519
+ `changes.patch` and `metadata.json`, keyed by fingerprint and reused only on
520
+ exact matches.
521
+
522
+ - Bound every command execution with a hard deadline so a hung process cannot
523
+ stall an unattended issue run: OpenCode task shell commands default to a
524
+ 120-second timeout with a 600-second maximum (an omitted `timeout` gets the
525
+ default and a larger declared timeout is clamped), Ralphie-owned git/gh and
526
+ workspace commands default to a 10-minute timeout via `CommandRunnerLive`,
527
+ and deterministic verification commands run under a 30-minute timeout. A
528
+ timed-out command is killed and reported as `CommandTimeoutError` with the
529
+ deadline and command in the message; agent tool calls surface
530
+ `Command timed out after N seconds` with partial output and can retry with
531
+ an explicit timeout.
532
+
533
+ - Resolve open dependencies on decomposed tracking parents transitively to
534
+ their open leaf children in the issue queue, so a child depending on a
535
+ decomposed-but-open container issue can never deadlock against a parent
536
+ that is never queued for execution.
537
+ - Surface dependency-blocked end-of-run issues as explicit needs-attention
538
+ outcomes (reason `external_dependency`) with evidence naming each open
539
+ dependency, instead of failing the run with a bare "blocked by open
540
+ dependencies" error: `--on-needs-attention halt` stops with the handled
541
+ stop; `continue` completes the run with the preserved issues still pending,
542
+ and no GitHub notification or label is published for queue-order blocks
543
+ (the opt-in notifier is reserved for agent-reported blockers).
544
+ - Pin grounding and resolution-verification evidence to the exact
545
+ checked-out commit: the read-only prompts now name the checked-out SHA
546
+ alongside the repository path and target branch.
547
+
548
+ ### Fixed
549
+ - Live OpenCode transcript streaming renders every `thinking_delta` / `text_delta`
550
+ (and tool output update) inline on the already-open `⋯ thinking` / `✦ assistant`
551
+ row instead of forcing one token per `│`-prefixed line; incremental deltas no
552
+ longer break the open stream, so interactive output wraps naturally at the
553
+ terminal width and durable progress/breadcrumb lines still interleave cleanly.
554
+ - Repeated structured-output attempts that never produce a schema-valid result
555
+ now trip a circuit breaker that aborts the OpenCode session after five
556
+ consecutive failures and reports the likely cause instead of letting the
557
+ model retry until the prompt-attempt budget expires.
558
+ ### Changed
559
+
560
+ - Added `--max-decomposition-depth` (default `3`) and persisted it in run state.
561
+ A direct or review-escalated decomposition beyond the configured ceiling now
562
+ leaves the issue open as `decomposition_limit_reached` needs attention and
563
+ continues independent queued work instead of failing and halting the run;
564
+ dependent issues remain blocked.
565
+
566
+ - OpenCode implementation sessions now allow ordinary composed shell commands,
567
+ pipes, redirection, and interpreters while continuing to reject explicit
568
+ orchestration-owned Git/GitHub mutations.
569
+ - Implementation completion is schema validated. Unresolved empty diffs enter
570
+ a bounded fresh-session retry loop with verifier evidence, configurable
571
+ implementation thinking, retry count, and optional fallback model.
572
+ - A tentative `already_resolved` grounding route now continues through
573
+ complexity assessment when fresh verification finds unresolved work. The
574
+ verifier evidence seeds the first implementation session, unresolved
575
+ resolution artifacts cannot short-circuit resumed work, and operational or
576
+ malformed verification failures still fail closed.
577
+ - `--on-issue-failure continue` restores failed issue checkouts and drains
578
+ independent queued work before returning an aggregate non-zero result;
579
+ failed prerequisites continue to block dependent issues.
580
+
581
+ - Deterministic verification command failures now enter a bounded repair loop
582
+ instead of immediately failing the issue and halting the queue. Each repair
583
+ receives the exact staged diff and bounded failed-command evidence in a fresh
584
+ mutating session, is restaged and reverified, and must pass before review or
585
+ commit. Repairs that change an approved staged tree force another review;
586
+ exhausted repairs and verification integrity faults still fail closed.
587
+
588
+ - Decomposition now uses native GitHub sub-issues and dependencies: every
589
+ created or recovered child is attached to the original issue as a native
590
+ sub-issue, declared `dependsOn` edges become native `blocked_by`
591
+ relationships, and the decomposed parent stays open as a tracking issue
592
+ instead of being closed as a duplicate. Child bodies keep only the stable
593
+ recovery marker and dependency list, and decomposed parents are never
594
+ re-queued for execution. Native relationships are reconciled idempotently on
595
+ resume; conflicting hierarchy or markers halt with a recovery diagnostic.
596
+ - Dequeued issues are refreshed from GitHub before branch or OpenCode work; closed or
597
+ label-ineligible issues are durably skipped without mutations, and cached
598
+ grounding, complexity, and resolution decisions now require matching live
599
+ issue freshness metadata.
600
+ - The `pr` workflow now gates merged delivery: after creating or finding the
601
+ matching feature-branch pull request it persists the PR number and head SHA,
602
+ publishes review attempts, waits for the exact-SHA check observer to reach
603
+ its documented green state, re-reads the PR immediately before merging, and
604
+ invokes the expected-head merge only while the head is unchanged. A failed,
605
+ cancelled, timed-out, absent, unknown, changed-head, closed, or unmergeable
606
+ gate retains the feature branch and PR, persists an active recoverable
607
+ closure gate, and never merges or closes the source issue; resume locates
608
+ the existing PR instead of duplicating it, continues polling pending gates,
609
+ invalidates saved green evidence on a changed head, re-observes failed
610
+ gates on a later rerun, and reconciles an already-merged PR without another
611
+ merge call. Run state version 6 records the PR number, observed head SHA,
612
+ latest normalized check snapshot, observation start/last-update timestamps,
613
+ gate status, and terminal reason for an active PR closure, with migration
614
+ coverage for versions 2–5. The `lgtm` workflow and dry-run paths are
615
+ unchanged, and GitHub mutations remain in the deterministic `src/github/`
616
+ services.
617
+
618
+ ### Added
619
+
620
+ - `bun run probe:structured-output` accepts `--union` to pre-flight a model
621
+ against the exact grounding decision contract plus `--model provider/model`,
622
+ `--agent`, and `--variant` for targeting a specific model before a run.
623
+ - The `pr` gate now streams dedicated `pr-gate` progress events for
624
+ registration (pull-request number and exact head SHA), poll progress only
625
+ for meaningful check transitions (registration, checks registering,
626
+ appearing or disappearing, and status changes: unchanged polls never
627
+ emit), head invalidation, and terminal success/failure, timeout, and
628
+ cancellation with the check summary and reason. Human and verbose output
629
+ explain the PR number, exact SHA, check summary, and reason; JSON output
630
+ exposes the structured normalized snapshot and timestamps; quiet output
631
+ suppresses the routine gate milestones while still reporting gate failures.
632
+ The observer exposes an optional `onTransition` callback invoked only on
633
+ meaningful transitions, and a merged gate record now retains the green
634
+ observation snapshot as persistent merge evidence.
635
+ - Deterministic PR-gate regression coverage: a local end-to-end PR workflow
636
+ with a fake GitHub check service that records merge calls and proves none
637
+ occur before a stable green snapshot, resume from pending/green/failed and
638
+ already-merged gate states, unknown and cancelled gate outcomes, expected-head
639
+ merge rejection recording a stale gate, pending-to-failure and mixed Check
640
+ Run/commit-status transitions, and quiet/JSON rendering of gate events.
641
+
642
+ - A deterministic, read-only pipeline observation service
643
+ (`src/github/pipeline-observation.ts`) that polls normalized pipeline
644
+ snapshots for one exact SHA: it tolerates an initial registration grace
645
+ period while no checks are visible, keeps polling while any item is pending,
646
+ requires configurable stable terminal confirmations, fails closed on
647
+ unknown, cancelled, failing, and empty terminal results, collects every
648
+ page from Check Runs and legacy commit statuses, uses bounded exponential
649
+ backoff and bounded rate-limit retries with delta-seconds, HTTP-date, and
650
+ reset metadata without retrying before server hints or sleeping past an
651
+ absolute deadline, honors caller cancellation reasons, emits only
652
+ meaningful state transitions, and finishes with a race-safe remote-HEAD
653
+ check that reports a stale result when the branch advances so callers can
654
+ follow a newly advanced HEAD.
655
+ - Complete the `--mode get-pipelines-green` release slice. The dedicated
656
+ direct base-branch runner authenticates and prepares one selected branch,
657
+ observes every supported Check Run, Check Suite, legacy status, and Actions
658
+ workflow source for one exact SHA, collects bounded terminal-sanitized
659
+ diagnostics, and runs a persisted repair/verify/commit/non-force-push loop.
660
+ A green exit requires a non-empty all-passing snapshot with no source or
661
+ completeness errors and a final current-HEAD proof; pending, acceptable,
662
+ failing, cancelled, unknown, and no-pipeline outcomes fail closed. The
663
+ versioned pipeline state adapter records absolute deadlines, confirmed-push
664
+ attempts, checkpoints, fingerprints, diagnostic references, and commit
665
+ evidence atomically; resume invalidates stale snapshots, reconciles an
666
+ ambiguous push without duplicate charging, and preserves the original
667
+ deadline. Dry-run performs authentication, preparation, observation, and
668
+ diagnostics only. The CLI reference, end-to-end trace, safety model,
669
+ operations/recovery guide, architecture map, and README document the mode,
670
+ output/exit contract, incompatible flags, provider limitations, untrusted CI
671
+ handling, artifact paths, cancellation, and recovery behavior.
672
+ - An opt-in `RALPHIE_RUN_GITHUB_SUB_ISSUES_SMOKE` integration test that
673
+ exercises the real native sub-issue and dependency API in a configured
674
+ sandbox repository: attachment and dependency idempotency, reads, live
675
+ parent-completion reconciliation, and cleanup.
676
+ - Deterministic decomposed-parent completion: finishing the final child
677
+ reconciles its tracking parent immediately, and every non-dry-run run
678
+ reconciles discovered decomposed parents, closing a parent as `completed`
679
+ only when every native sub-issue is closed. Parents awaiting sub-issue
680
+ attachment recovery, non-Ralphie parents, and already-closed parents are
681
+ left untouched.
682
+ - Dry-run decomposition reporting: a complexity 4–5 dry run performs the
683
+ read-only breakdown session and reports the intended native sub-issue
684
+ hierarchy: children to create or reuse, sub-issue attachments, dependency
685
+ edges, and the open tracking parent: without mutating GitHub or writing
686
+ artifacts. An unverified needs-attention signal from the planning session is
687
+ reported as a needs-attention route without invoking recovery.
688
+ - A deterministic GitHub issue-relationship domain service
689
+ (`src/github/issue-relationships.ts`) that lists, attaches, and validates
690
+ native sub-issues and dependencies with idempotent, response-loss-safe
691
+ mutations and actionable unsupported-endpoint errors.
692
+ - A terminal output controller (`src/progress/terminal-controller.ts`) that
693
+ wraps the footer view scheduler and the shared `ProgressOutput` primitives
694
+ and arbitrates every transcript/raw write with the terminal stream boundary
695
+ tracker: an active footer is cleared before transcript or durable progress
696
+ output, token deltas are forwarded immediately, and the footer is restored
697
+ only at safe line boundaries. Durable progress lines are deferred while a
698
+ transcript fragment is open mid-line so progress never merges with,
699
+ overwrites, or falsely closes the fragment; footer bytes are emitted only
700
+ through the strategy's footer surface and never enter transcript/control
701
+ payload or durable scrollback; every replacement repaint clears a visible
702
+ footer before drawing the new one; durable transcript breadcrumbs remain
703
+ the safe default fallback with cursor-reserved-row behavior disabled by
704
+ default. Coverage exercises partial transcript lines, progress
705
+ interleaving, immediate token forwarding, split ANSI/control strings,
706
+ footer suppression while unsafe, restoration after a safe boundary, and
707
+ strict clear-before-draw ordering through fake sinks and fake strategies.
708
+ - A persisted `created-issue-dependencies` artifact that records each child's
709
+ dependency issue numbers so queue eligibility never depends on live GitHub
710
+ state alone.
711
+
712
+ - A single package-version authority with build-time commit metadata and plain
713
+ or JSON `--version` output that works without repository or OpenCode configuration.
714
+ - An isolated package smoke check that inspects the tarball allowlist, installs
715
+ production dependencies in a fresh project, and verifies scoped identity and
716
+ manifest-backed `--version` output.
717
+ - Staged-tree-bound deterministic verification before review, after review
718
+ fixes, and before commit, with persisted command evidence and repeatable
719
+ `--verify-command` overrides.
720
+ - Stage-specific thinking controls for grounding, complexity routing, review,
721
+ and commit-message generation.
722
+ - Discriminated top-level CLI configuration for issue,
723
+ `maintain-issues`, and `get-pipelines-green` modes, including duplicate
724
+ handling policy, bounded attempts, and strict pipeline timeout values.
725
+ - Read-only issue grounding with a persisted needs-attention deferral: blocked
726
+ issues keep their evidence, questions, and freshness fingerprint, remain
727
+ open, and are never closed or marked complete; complexity is never a
728
+ needs-attention reason.
729
+ - An explicit `halt` (default) / `continue` needs-attention policy with
730
+ versioned run-state migration, resume conflict protection, exit status `2`
731
+ for handled stops and exit `0` only when `continue` drains the queue.
732
+ - Confirmed needs-attention recovery that atomically preserves bounded,
733
+ binary-safe worktree diagnostics before restoring and verifying the exact
734
+ clean issue checkpoint.
735
+ - Resumable needs-attention handoffs with one fresh read-only verifier for every
736
+ executor signal, immutable confirmation before recovery, and idempotent,
737
+ freshness-bound diagnostics across interruptions.
738
+ - Durable needs-attention notification recovery: structured outcomes and label
739
+ intent are saved before GitHub mutation, and resume retries the stable marker
740
+ without rerunning agent work.
741
+ - An explicit, disabled-by-default `--notify-needs-attention` CLI opt-in with a
742
+ trimmed `--needs-attention-label`; label-only usage is rejected, dry runs
743
+ never notify, and failed notifications retain their intent for safe resume
744
+ and retry.
745
+ - Native Bun CLI foundation with GitHub, Git, workspace, and OpenCode domain
746
+ services.
747
+ - Resumable issue execution with complexity routing, bounded review loops,
748
+ deterministic commits and pushes, and dependency-aware decomposition.
749
+ - Typed progress events, JSON Lines output, and diagnostics.
750
+ - Structured no-change resolution verification with persisted evidence.
751
+
752
+ ### Changed
753
+
754
+ - Refresh each issue before mandatory grounding, route actionable work through
755
+ the existing complexity thresholds, require fresh concrete verification for
756
+ already-resolved closure, and keep needs-attention outcomes out of closure
757
+ and PR delivery. Complexity is never a needs-attention reason.
758
+ - Document the cross-mode display contract: interactive sticky footer and
759
+ contextual OpenCode session output, periodic and lifecycle breadcrumbs, the
760
+ `LIVE_OUTPUT_LIMIT` character threshold and human-preview defaults, active
761
+ leaf-stage status, append-only plain/CI output, quiet output limited to
762
+ failures and handled needs-attention stops,
763
+ lossless JSON Lines without human breadcrumb records, and the independent
764
+ durable progress-event log preserving supplied values (never redacted).
765
+ - Expose grounding and needs-attention decisions consistently across default,
766
+ interactive, verbose, quiet, and JSON Lines output, including complete
767
+ evidence, questions, artifact paths, policy, and final outcome counts.
768
+ - Make dry-run grounding and routing strictly read-only: report all routes,
769
+ reuse persisted decisions without rewriting issue artifacts, and keep resumed
770
+ dry runs away from implementation, delivery, and Git/GitHub mutations.
771
+ - Refresh live issue and comment metadata when resuming pending work, and reuse
772
+ needs-attention grounding only while its freshness fingerprint matches;
773
+ changed or invalid artifacts are atomically invalidated before regrounding.
774
+ - Keep OpenCode configuration separate from persistent workspace state:
775
+ `--opencode-url`/`OPENCODE_URL` and `--opencode-token`/`OPENCODE_TOKEN` are
776
+ operator-owned inputs, while local background-service discovery remains
777
+ outside the workspace state tree.
778
+ - Define noninteractive `github.com` authentication through the preferred
779
+ `GH_TOKEN` and fallback `GITHUB_TOKEN` environment variables, without
780
+ requiring `gh auth login` or a mounted GitHub CLI profile.
781
+ - Document the published scoped Bun package and use
782
+ `bunx @beremaran/ralphie` for installation, version verification, dry-run,
783
+ and workflow examples; the scope distinguishes this CLI from the unrelated
784
+ unscoped npm package named `ralphie`.
785
+ - Resolve dependencies on decomposed closed issues to their open descendants,
786
+ stop repeated identical review findings early, permit safe compound shell
787
+ inspection commands, and use GitHub REST API version `2026-03-10`.
788
+ - Polish human-readable OpenCode streaming with grouped session blocks, readable tool
789
+ calls, indented de-duplicated tool output, bounded previews, and safe handling
790
+ of terminal control sequences while preserving the lossless JSON event stream.
791
+ - Stream the complete OpenCode event transcript, including token-level thinking
792
+ and assistant output plus tool calls and results, and remove parallel issue
793
+ and OpenCode session execution.
794
+ - Consolidate the CLI surface: fold `--issue-order` into
795
+ `--issue-sort <field>[:asc|desc]`; use `--thinking` for the selected OpenCode
796
+ variant and `--opencode-url`/`--opencode-token` for the external server;
797
+ replace `--start-clean` and `--cleanup` with `--clean <start|end|both>`;
798
+ and replace `--verbose`, `--json`, and `--quiet` with
799
+ `--output <default|verbose|quiet|json>`.
800
+ - Keep model selection under `--model <provider/model>` and server credentials
801
+ under `OPENCODE_URL` and `OPENCODE_TOKEN`; the retired embedded-agent flags
802
+ and `RALPHIE_MODEL_*` environment variables are no longer part of the CLI.
803
+
804
+ ### Added
805
+
806
+ - Native Bun CLI foundation with GitHub, Git, workspace, and OpenCode domain
807
+ explicit service factories, and an ordinary runtime dependency object.
808
+ - Focus execution on one required repository and accept all configuration through
809
+ CLI arguments and flags; remove JSON configuration, named projects, repository
810
+ patterns, and multi-repository orchestration.
811
+ - Use the external `@opencode-ai/client` server integration, operator-run
812
+ OpenCode sessions, a permission watcher and denylist for defense in depth,
813
+ and fenced structured-output/needs-attention responses validated by Zod.
814
+ - Rely on the authoritative non-force Git push for GitHub branch policy and
815
+ permission enforcement while retaining destination, commit, and divergence
816
+ safety checks.
817
+ - Render interactive progress through a bounded replaceable terminal region with
818
+ nested-stage tracking instead of creating an OpenTUI renderer.
819
+ - Close completed implementation issues after verified delivery, with
820
+ idempotent recovery for interrupted or ambiguous GitHub responses.
821
+
822
+ ### Fixed
823
+
824
+ - Prevent final progress events from recreating a workspace removed by
825
+ `--clean end`.
826
+ - Prevent viewport repainting, split-stream output, and accumulating
827
+ `CliRenderer` destroy listeners during long runs.
828
+ - Prevent no-change agent runs from being silently skipped without proving
829
+ whether the issue is already resolved.
830
+
831
+ [Unreleased]: https://github.com/beremaran/ralphie/compare/v0.2.0...HEAD
832
+ [0.2.0]: https://github.com/beremaran/ralphie/compare/v0.1.2...v0.2.0