@beremaran/ralphie 0.0.0-stage → 0.2.1

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