Feature: radioactive-ralph — Go rewrite with mirror workspaces and inventory-aware biases¶
Historical plan note: This PRD captures an earlier architecture direction. It still discusses marketplace/plugin packaging, service-managed daemon behavior, and skill-era helper terminology that are no longer the active product contract.
Created: 2026-04-14 Version: 4.0 (Go pivot; supersedes v3.0 which assumed Python) Timeframe: four PRs, several weeks total
Priority: P0 (the project does not work today)¶
Table of contents¶
Overview
Critical constraints
Architecture
Core concepts
Per-repo config directory
XDG state directory
Four workspace knobs
Variant-default matrix
Safety floors
Capability inventory + skill biases
Pre-flight wizard (capability-matching)
Daemon lifecycle
Managed-session strategy
Service integration (brew / launchd / systemd)
Skills as entry points
Tasks (M2 → M4, M1 already merged)
Acceptance criteria
Technical notes
Risks
Out of scope
1. Overview¶
radioactive-ralph M1 (merged in PR #26) deleted broken daemon claims,
stubbed non-functional Python code behind NotImplementedError, fixed
the marketplace install, and aligned the docs with the target
architecture. This PRD covers the remaining milestones — M2-M4 — which
are now written in Go, not Python.
The daemon’s job is narrow and well-defined:
Manage
claude -psubprocesses with--input-format stream-jsonstdin/stdout, resume them on death via--resume <uuid>.Own a SQLite event log (with sqlite-vec for task dedup) that survives daemon crashes and multi-day runs.
Run a capability-matching pre-flight wizard that discovers installed skills/MCP servers, lets the operator pick preferences for ambiguous categories (multiple review skills, multiple docs-query methods), and persists the choices to a committed per-repo
config.toml.Apply variant profiles that encode parallelism, model tiering, commit cadence, termination policy, safety floors, and skill-preference biases.
Manage git worktrees off a mirror clone in XDG state, isolating all Ralph’s work from the operator’s real working tree.
Expose a Unix socket for
radioactive_ralph status / attach / enqueue / stop.Integrate with OS service managers (
brew serviceson macOS,systemd --useron Linux, WSL2+systemd on Windows) so the three service-appropriate variants (green, immortal, blue –daemon) can run as durable background services.
Everything else — code review, PR classification, work discovery, commits, CI checks, merge queue — happens inside the worktree Claude sessions using whatever skills the operator has installed. The daemon dispatches and supervises; Claude does the work. This is the key architectural decision that shrinks the daemon to a small, sharp tool.
2. Critical constraints¶
2.1 No external injection into interactive Claude sessions¶
Claude Code 2.1.89+ exposes no supported mechanism to inject user-role
messages into a running interactive session from an external
process. The only cross-process channel is the
--input-format stream-json stdio protocol in headless (-p) mode.
Therefore the daemon never “manages” an outer Claude session — every
managed session is a claude -p subprocess the daemon spawned itself,
with its stdin piped.
2.2 The daemon does one thing well¶
Code review, PR merging, branch hygiene, work discovery, CI monitoring — Claude already knows how to do all of these, and does them better when given a good prompt and access to the right skills in the worktree. Re-implementing any of that in the daemon violates the single-responsibility contract and duplicates capability that already exists inside the session.
Preserved Python modules that violated this (reviewer.py,
pr_manager.py, work_discovery.py, forge/*) are not ported to
Go. They stay in reference/ for history and are deleted along with
the rest of the reference tree at v1.0.0.
2.3 Capability inventory shapes every spawn¶
What skills, MCP servers, subagents, and Claude Code plugins the operator has installed varies per machine and per project. The daemon discovers this inventory at launch time and uses it to steer each managed session:
If
coderabbit:reviewis installed and the operator prefers it,red-ralphtells Claude “after every fix, invoke /coderabbit:review.”If
plugin:context7:context7is installed,professor-ralphtells Claude “during planning phase, query context7 for library docs.”If
sec-context-depthis installed,blue-ralphtells Claude “invoke /sec-context-depth on every diff you review.”
Variant profiles declare preferred categories (review, security
review, docs query, debugging, brainstorming). The operator resolves
ambiguity (multiple review skills) once during radioactive_ralph init. The
supervisor composes per-spawn system prompts based on
(variant, stage, operator preferences, actual inventory).
2.4 Distribution is native binaries, not pip install¶
Ralph is distributed as a Go binary via:
Homebrew tap (
jbcom/homebrew-tap) — primary on macOS and Linux, including WSL2+LinuxbrewPlugin skill — marketplace skill that bootstraps the binary on first run
curl | shinstall script — hosted atjonbogaty.com/radioactive-ralph/install.shScoop + WinGet — Windows native package managers, both published from one GoReleaser tag
No code signing in initial releases. All three primary install paths
bypass macOS Gatekeeper (brew formulae, curl | sh, and skill-invoked
shell installs do not set the com.apple.quarantine xattr).
Direct-download users from GitHub Releases will see a Gatekeeper
warning and can bypass with xattr -d com.apple.quarantine <binary>.
This is the standard FOSS practice (lazygit, zellij, mise, atuin,
hugo, asdf-vm all ship unsigned).
3. Architecture¶
OPERATOR (~/src/myproject/)
→ runs `radioactive_ralph init` once per repo (capability-matching wizard)
→ either `radioactive_ralph run --variant X` (direct) or `/green-ralph` (skill)
or `brew services start ralph-green` (for green/immortal/blue)
DIRECT CLI SKILL WRAPPER
│ │
┌────────┴──────────┐ ┌─────────┴────────────┐
│ pre-flight checks │ │ skill discovers, │
│ (tmux? gh? git?) │ │ runs `radioactive_ralph init` │
│ spawn supervisor │ │ if needed, launches │
│ via multiplexer │ │ `radioactive_ralph run --detach` │
└────────┬──────────┘ └─────────┬────────────┘
│ │
└────────────┬─────────────────┘
▼
┌──────────────────────────────┐
│ RALPH SUPERVISOR (Go) │
│ backgrounded via: │
│ tmux (optimal) → │
│ screen (workable) → │
│ syscall.Setsid fallback │
│ launchd/systemd (service) │
│ │
│ Unix socket for IPC │
│ SQLite + sqlite-vec log │
│ Variant profile + inventory │
└──────────────┬────────────────┘
│ resolves workspace
▼
┌──────────────────────────────┐
│ WORKSPACE MANAGER │
│ isolation / object_store / │
│ sync_source / lfs_mode │
│ │
│ shared → operator's repo │
│ shallow → $XDG/shallow/ │
│ mirror-* → $XDG/mirror.git │
└──────────────┬────────────────┘
│ spawns + manages
▼
┌──────────────────────────────┐
│ MANAGED CLAUDE SUBPROCESSES │
│ claude -p --input-format │
│ stream-json, one per │
│ worktree; daemon pipes │
│ messages in, reads events │
│ out, resumes on death. │
│ System prompt injects │
│ variant's skill biases. │
└──────────────────────────────┘
▲
│ ralph attach / ralph status
│ via Unix socket
│
OPERATOR (other terminal)
XDG state layout:
$XDG_STATE_HOME/radioactive-ralph/ (on macOS: ~/Library/Application Support/radioactive-ralph/)
└── <repo-hash>/ # sha256(abspath(operator-repo))[:16]
├── mirror.git/ # only if any variant uses mirror-* isolation
├── shallow/ # only if any variant uses shallow isolation
├── worktrees/
│ └── <variant>-<n>/
├── inventory.json # capability discovery output
├── state.db # SQLite + sqlite-vec event log
├── state.db-wal
└── sessions/
├── <variant>.sock # per-variant Unix socket
├── <variant>.pid # supervisor PID + flock
├── <variant>.alive # heartbeat mtime
└── <variant>.log # supervisor stdout/stderr
Operator’s repo stays clean — only .radioactive-ralph/config.toml
and .radioactive-ralph/.gitignore are committed;
.radioactive-ralph/local.toml is gitignored for operator-specific
overrides.
4. Core concepts¶
4.1 Per-repo config directory¶
~/src/myproject/.radioactive-ralph/
├── config.toml # committed: capabilities, variant policy, workspace defaults
├── .gitignore # committed: excludes local.toml
└── local.toml # gitignored: operator-specific (tmux pref, log level, etc.)
radioactive_ralph init creates this tree, runs the capability-matching wizard,
writes both TOML files, and appends .radioactive-ralph/local.toml to
the repo’s root .gitignore. Missing config.toml = refuse to run
with a clear message.
config.toml example post-init:
# Auto-generated by `radioactive_ralph init`. Re-run `radioactive_ralph init --refresh` to
# detect newly-installed skills without losing your choices.
[capabilities]
# Skills Ralph biases toward during certain tasks. Operator chose
# these during init from the set of actually-installed skills.
review = "coderabbit:review"
security_review = "sec-context-depth"
docs_query = "plugin:context7:context7"
brainstorm = "superpowers:brainstorming"
debugging = "superpowers:systematic-debugging"
# Skills the operator doesn't want Ralph to bias toward even if present.
disabled_biases = []
[daemon]
default_object_store = "reference"
default_lfs_mode = "on-demand"
copy_hooks = true
allow_concurrent_variants = true
[variants.green]
# Empty section = use the variant's hardcoded defaults.
[variants.red]
review_bias = "coderabbit:review"
[variants.blue]
security_review_bias = "sec-context-depth"
[variants.immortal]
object_store = "full" # multi-day discipline
[variants.old_man]
# Safety floor: object_store = "full" is pinned. See docs.
4.2 XDG state directory¶
$XDG_STATE_HOME/radioactive-ralph/<repo-hash>/ via Go’s
platformdirs-equivalent (stdlib os.UserConfigDir + fallback to
$XDG_STATE_HOME). Per-repo per-machine.
<repo-hash> = sha256(abspath(operator-repo-root))[:16], stable per
location. Operator cloning the same repo to two paths gets two
independent workspaces.
4.3 Four orthogonal workspace knobs¶
Knob |
Values |
Default |
Purpose |
|---|---|---|---|
|
|
varies by variant |
Where the work happens |
|
|
|
Share operator’s objects or fully clone |
|
|
|
Where the mirror fetches from |
|
|
|
How LFS content is handled |
Safety floors can pin any knob for risky variants. Precedence: CLI
flags > env vars (RALPH_*) > config.toml per-variant > config.toml
[daemon] default > variant profile default > project default.
4.4 Variant-default matrix¶
Variant |
Isolation |
Parallel |
Object store |
LFS |
Gate |
|---|---|---|---|---|---|
blue |
|
0 |
n/a |
pointers-only |
— |
grey |
mirror-single |
1 |
reference |
pointers-only |
— |
red |
mirror-pool |
8 |
reference |
on-demand |
— |
green |
mirror-pool |
6 |
reference |
on-demand |
— |
professor |
mirror-pool |
4 |
reference |
on-demand |
— |
fixit |
mirror-single |
1 |
reference |
pointers-only |
— |
immortal |
mirror-pool |
3 |
full |
pointers-only |
— |
savage |
mirror-pool |
10 |
reference |
on-demand |
|
old-man |
mirror-single |
1 |
full (floor) |
on-demand |
|
world-breaker |
mirror-pool |
10 |
full (floor) |
full |
|
4.5 Safety floors¶
Variant |
Floor |
Override path |
|---|---|---|
Any with |
Tool allowlist must exclude |
Impossible (compile-time validator) |
old-man |
|
Two CLI flags (both |
world-breaker |
|
Two-step override + explicit spend cap |
savage |
Spend cap required; fresh gate per invocation |
Operator raises cap with |
savage, old-man, world-breaker |
Refuse to run when invoked under launchd/systemd (service context) |
No override — service-unsafe by design |
Default-branch detection uses git symbolic-ref refs/remotes/origin/HEAD,
falling back to the hardcoded list
{main, master, trunk, develop, production, release/*}.
4.6 Capability inventory and skill biases¶
Discovered at radioactive_ralph init (for operator review) and at each radioactive_ralph run
(for runtime steering). Shell-based discovery:
Enumerate
~/.claude/skills/*/SKILL.mdfrontmatternamefieldParse
~/.claude/settings.jsonformcpServers,enabledPlugins,extraKnownMarketplacesParse
.claude/settings.jsonin the repo for project-scoped additionsEnumerate
~/.claude/plugins/cache/*/directoriesCall
claude plugin marketplace list --jsonif the CLI exposes it
Stored as inventory.json:
{
"generated_at": "2026-04-14T20:45:00Z",
"claude_version": "2.1.89",
"skills": ["coderabbit:review", "context7:query-docs", "..."],
"mcp_servers": [{"name": "context7", "reachable": true}],
"agents": ["code-reviewer", "feature-dev:code-explorer"],
"environment": {"gh_authenticated": true, "in_claude_code": true}
}
Variant profiles declare SkillBiases map[BiasCategory]BiasSnippet.
At spawn time, supervisor:
Reads config.toml
[capabilities]+[variants.<name>]overrides.Reads inventory.json.
For each bias category the variant cares about, picks the operator’s preferred skill if available in inventory, else falls back to variant’s default, else skips silently.
Injects the chosen bias snippets into the system prompt via
--append-system-prompt.
Missing biases are logged at INFO. radioactive_ralph doctor flags drift.
4.7 Pre-flight wizard (capability-matching)¶
radioactive_ralph init is a first-class CLI command, not just a config bootstrap.
Discover: run shell commands to enumerate skills, MCP servers, agents, plugins.
Categorize: group findings by capability type (review, security review, docs query, etc.). Multi-candidate categories are flagged for operator input.
Ask: for each multi-candidate category, prompt operator to pick preferred or explicitly disable. Single-candidate categories auto-select with a one-line confirmation.
Suggest per-variant defaults: “red-ralph will bias toward coderabbit:review during fix cycles — override?”
Write: config.toml + local.toml +
.gitignoreentries. All choices commented with alternatives for later edit.
radioactive_ralph init --refresh re-discovers and proposes updates without
losing existing choices.
Universal pre-flight checks run at radioactive_ralph run start (not init):
gh auth statusgreenclaude --versionwithin pinned supported rangeWorking tree clean (offer to stash/branch if not)
Not on default branch (offer to branch if so, for destructive variants)
Multiplexer available (tmux → screen → setsid)
--yes skips non-blocking checks; blocking checks still require answer
(operator can pre-answer in config.toml).
4.8 Daemon lifecycle¶
Entry:
radioactive_ralph run --variant Xresolves profile + overrides, runs pre-flight, if OK spawns supervisor via multiplexer (or runs in-foreground for--foreground/ service invocation).Supervisor boot:
Acquire flock on
<variant>.pid(refuses if live supervisor)Open SQLite in WAL + load sqlite-vec extension (soft-fail to FTS5)
Bind Unix socket
Start heartbeat goroutine (touches
<variant>.aliveevery 10s)Load variant profile + resolved workspace config + inventory
Replay event log to rebuild in-memory state
Protocol-ping: spawn throwaway
claude -p, send “reply PONG”, verify parse. Abort boot on failure.Initialize WorkspaceManager per isolation mode
Start session pool
Workspace init (first run for variant): WorkspaceManager creates mirror/shallow/worktree as needed. Copies operator’s
.git/hooks/to mirror’s.git/hooks/unlesscopy_hooks = false. Detects LFS usage. Applies knobs.Session pool: for each slot, create/reuse worktree, spawn
claude -p --input-format stream-json --session-id <uuid>with stage-appropriate system prompt (variant + inventory biases). Record session in SQLite.Event loop: read stream-json events from each session, append to event log (parsed + raw for protocol-drift resilience), act on result events. On subprocess exit, classify:
clean → task done, pick next
context-exhausted → resume with
--resume <uuid>+ sentinel re-prompt (“what task ID are you working on?”)rate-limited → exponential backoff, resume when clear
crashed → log, resume once, escalate to operator on repeat
operator-killed → graceful drain
IPC: Unix socket serves
status,attach,enqueue,stop,reload-configas JSON lines.Termination: per variant policy. Drain events, close socket, remove PID, clean worktrees per variant rule, exit.
4.9 Managed-session strategy¶
Every managed invocation:
claude -p --bare \
--input-format stream-json \
--output-format stream-json \
--include-partial-messages --verbose \
--permission-mode <acceptEdits | bypassPermissions> \
--allowedTools <variant.ToolAllowlist> \
--model <variant.ModelForStage(currentStage)> \
--session-id <stableUUID> \
--append-system-prompt <variant-system-prompt-with-inventory-biases>
--bareskips project CLAUDE.md / hook / MCP auto-discovery for reproducibility. Variant provides system prompt via--append-system-prompt.--permission-mode defaultnever used (no TTY for interactive prompts).acceptEditsfor normal variants;bypassPermissionsfor old-man / world-breaker behind their gates.
Spend tracking: supervisor parses usage field from stream-json result
events, accumulates per-model in SQLite, computes USD from pricing
table. Cap-hit → graceful stop, voiced as
“Ralph burned his allowance. Going home.”
Session ID pinning via --session-id <uuid> avoids Claude Code issue
#44607 (interactive mode ID ≠ on-disk filename; does not affect -p mode).
4.10 Service integration¶
Three variants are eligible to run as persistent system services:
Variant |
Service suitable? |
Scheduler kind |
|---|---|---|
green |
✅ always-on daemon |
|
immortal |
✅ always-on, survives reboot |
|
blue (with |
✅ PR observer |
|
grey |
⏰ timer, not daemon |
weekly |
professor |
⏰ timer, not daemon |
daily |
red, fixit |
❌ on-demand only |
(value in operator reading the output) |
savage, old-man, world-breaker |
❌ refuse service context |
fresh confirmation gate required |
The CLI exposes radioactive_ralph service install --variant X that emits the
appropriate plist (macOS), systemd user unit (Linux), or Scoop
persistence entry (Windows), and wraps brew services / systemctl --user commands.
--foreground flag on radioactive_ralph run runs the supervisor inline (stdout /
stderr to caller), bypassing the multiplexer. This is what the service
unit’s ExecStart invokes so launchd / systemd is the actual
supervisor.
Floor-gated variants detect service context (env vars
LAUNCHED_BY=launchd or INVOCATION_ID=* for systemd) and refuse to
run, printing a clear error and exiting non-zero. Detected at pre-flight,
before any workspace setup.
4.11 Skills as entry points¶
Each skills/<variant>/SKILL.md ≤30 lines. Skeleton:
---
name: green-ralph
description: The Classic. Unlimited loop, sensible model tiering. Launches the ralph daemon in the background.
---
If `.radioactive-ralph/config.toml` is missing, run `radioactive_ralph init`
interactively and wait for the operator to review.
Otherwise shell out: `radioactive_ralph run --variant green --detach`
The daemon's own pre-flight checks, Ralphspeak banter, and handoff
message handle everything else. Return whatever the CLI prints to the
operator.
Rich behavioral lore moves into internal/variant/green.go docstrings
and docs/variants/green-ralph.md which auto-regenerates from
Profile at build time (M3).
4.6 Plans discipline + Fixit as advisor¶
Every repo using radioactive-ralph must have .radioactive-ralph/plans/index.md
with YAML frontmatter (status, updated, domain,
variant_recommendation) referencing at least one real plan file.
Alternatively, [daemon] plans_dir = "xdg" in config.toml puts plans
under XDG state instead of in-repo (private plans on public repos).
Nine of the ten variants refuse to run without a valid plans
setup. The refusal message directs operators to radioactive_ralph run --variant fixit — because fixit-ralph is the only variant capable of
reasoning about which Ralph to use.
Fixit auto-detects its mode from the plans state:
Advisor mode — no plans dir, malformed
index.md, or--advisepassed. Walks the codebase + any provided description, writes a recommendation to.radioactive-ralph/plans/<topic>-advisor.md. Primary variant always; alternate only when real tradeoffs exist. If Fixit recommends itself that’s fine — still the only Ralph that made the call. With--auto-handoffAND high confidence AND no tradeoffs, Fixit spawns the recommended variant as a follow-up.ROI banger mode — valid plans setup present. Classic Joe-Fixit persona: N cycles, highest-ROI task per cycle, ≤5 files / ≤200 LOC PRs, bill at the end.
This structure enforces plans-first discipline: no variant grinds
against a repo that hasn’t had its scope examined, and exactly one
variant knows how to do that examination. The rename from
joe-fixit-ralph to fixit-ralph (2026-04-14) reflects this
expanded role — the Joe-Fixit persona is preserved as character
flavor, but the variant does more than ROI now.
5. Tasks¶
M1 (merged, PR #26)¶
Done. Marketplace fix, README/docs truthfulness, dead Python code
removed, broken implementations stubbed behind NotImplementedError,
two broken tests fixed, all canonical domain docs rewritten, PRD
committed.
M2 — Go rewrite of the daemon (this branch)¶
Subdivided into commits so the git log tells the story. Each commit
passes go test ./... + golangci-lint run.
M2.T0 — Python → reference/ ✅ (first commit on this branch)
M2.T1 — Go bootstrap:
go.mod,cmd/ralph/main.gowith kong CLI skeleton,Makefile, GitHub Actions CI (go test, golangci-lint, govulncheck), replace existing Python workflows.M2.T2 —
internal/xdg+internal/config: repo-hash derivation, state-dir path helpers, kong CLI struct, TOML loader, precedenceResolve()function, safety floor enforcement.M2.T3 —
internal/inventory: shell discovery of skills / MCPs / plugins, JSON roundtrip, consumed by init + supervisor.M2.T4 —
internal/db: SQLite + sqlite-vec (viamodernc.org/sqliteasg017/sqlite-vec-go-bindings), WAL, schema migrations,EventLog.Append/.Replay, tasks + sessions + task_vec tables, raw + parsed payload storage.
M2.T5 —
internal/ipc: net.UnixListener server + client, JSON-line protocol,status/attach/enqueue/stop/reload-configcommands, heartbeat file mtime for liveness.M2.T6 —
internal/multiplexer: tmux / screen / syscall.Setsid probe,SpawnDetached(cmd, logPath, pidPath).M2.T7 —
internal/workspace: IsolationMode / ObjectStoreMode / SyncSourceMode / LfsMode enums,WorkspaceManagerdispatching on isolation, mirror init with--reference, two-remote fetch (local/origin), worktree add/remove/reconcile, LFS detectionper-mode config, repack-on-corruption recovery.
M2.T8 —
internal/session:ClaudeSessionwrappingclaude -pviaexec.CommandContext, stream-json stdin/stdout (bufio Scanner),SendUserMessage/Events/Interrupt/WaitForIdle/Resume, protocol-ping handshake, sentinel re-prompt after resume with task-ID verification,PromptRenderercombining variant + inventory biases.M2.T9 —
internal/service:radioactive_ralph service install/uninstall/list/statuscommands, platform-dispatching among launchd / systemd-user / brew-services, service-context detection in pre-flight.M2.T10 —
internal/supervisor: PID flock, socket bind, event replay, session pool, IPC request loop, multi-variant coexistence via per-variant paths, graceful termination.M2.T11 —
internal/initcmd: capability-matching wizard, writesconfig.toml+local.toml, appends to repo.gitignore, supports--refreshto re-discover without losing choices.M2.T12 —
internal/doctor: environment health — git version, claude version range, gh auth, tmux/screen/setsid, platformdirs writable, config.toml present.M2.T13 —
internal/voice: Ralph personality templates (thin in M2, variant-specific fills in M3).M2.T14 —
cmd/ralph/main.go: kong CLI wiring —init / run / status / attach / stop / doctor / service / version+ hidden_supervisor.M2.T15 — Homebrew tap + GoReleaser + install script: create
jbcom/homebrew-taprepo viagh,.goreleaser.yamlwith brew + Scoop + WinGet + tarballs + checksums + cosign provenance, install script atdocs/install.sh, docs page explaining the three install paths.M2.T16 — Integration tests: always-on
radioactive_ralph init+ralph run --variant blue --detachround-trip. Gated-on-CLAUDE_AUTHENTICATED realclaude -pspawn + resume + sentinel verification.M2.T17 — macOS + Linux CI matrix: run integration tests on both platforms. Windows is deferred (WSL2+systemd coverage is enough).
M3 — Ten variants + pre-flight + voice + worktree orchestration¶
M3.T1 —
internal/variant/profile.go:Profile,Stage,Model,TerminationPolicy,PreflightQuestion,VoiceProfile,SafetyFloors,BiasCategory,BiasSnippettypes.M3.T2 — Ten variant files:
internal/variant/{green,grey,red, blue,professor,joe_fixit,immortal,savage,old_man,world_breaker}.go. Each ≤300 LOC, each faithful to the current SKILL.md.M3.T3 — Safety floors enforcement: compile-time validators for
shared-isolation tool allowlist; runtime two-step override for destructive variants’ object_store.M3.T4 — Dry-run + spend-cap: first-invocation dry-run mode for risky variants; spend-cap tracking parses stream-json
usageevents.M3.T5 —
internal/voicefills: per-variant voice template library, used by pre-flight questions, status output, attach stream, handoff messages.M3.T6 — Pre-flight wizard as question registry: severity-tiered (blocking / warning / info), CLI + skill renderers share the registry.
M3.T7 — Skills rewritten to ≤30 lines: each SKILL.md delegates to
radioactive_ralph run.M3.T8 — Auto-generated variants-matrix.md:
cmd/matrixgenreads everyProfile, emitsdocs/reference/variants-matrix.md. CI drift check fails on diff.M3.T9 — Per-variant docs pages:
docs/variants/*.mdauto-generated from profiles + hand-written lore sections allowed above/below.M3.T10 — Unit tests per variant: parameterized test asserts every profile’s fields in range, tool allowlist subset of known tools, gated variants declare gates, blue excludes Edit+Write, grey is single-pass with max_parallel=1, safety floors non-overridable.
M4 — Integration harness + doctor + service install + release 1.0.0¶
M4.T1 — Integration scenarios: full grey-ralph single-pass end-to-end against fake origin; green-ralph SIGTERM mid-run; session death + resume continuity; pre-flight refusal for old-man on default branch; safety-floor override two-step; mirror
--referencerepack-on-corruption recovery; LFS detection applied per-variant; hook preservation (operator’s pre-commit runs inside mirror); multi-variant coexistence (green + grey simultaneous supervisors).
M4.T2 — Service install integration:
radioactive_ralph service install --variant greenwrites plist/unit correctly;brew services startinvokes supervisor in foreground; service-context detection refuses floor-gated variants.M4.T3 —
radioactive_ralph doctorcomprehensive: exit 0 green, exit 1 with ranked remediation. Checks git version, claude version range, gh auth, tmux/screen/setsid fallback, platformdirs writable, sqlite-vec loadable, workspace config.toml present, inventory fresh.M4.T4 — Docs completion: final architecture diagram, UX walkthrough with both CLI + skill + service paths, auto-generated variants matrix committed.
M4.T5 — Release 1.0.0: GoReleaser publishes to GitHub Releases
Homebrew tap + Scoop bucket + WinGet (microsoft/winget-pkgs PR). Install script live at
jonbogaty.com/radioactive-ralph/install.sh.assets/demo.gifrecords fullradioactive_ralph init→radioactive_ralph run --variant grey→ PR opens →radioactive_ralph stop.
M4.T6 — Purge
reference/: delete the entire Python tree in one commit at release.radioactive-ralph==0.5.1on PyPI remains available; no further Python releases.
6. Acceptance criteria¶
M2¶
go test ./...passes locally and in CI on both macOS and Linuxgolangci-lint runcleangovulncheck ./...cleanradioactive_ralph --versionprints the compiled versionradioactive_ralph initin a fresh temp repo creates.radioactive-ralph/correctly and writes a sensible starterconfig.tomlwith capability discoveriesradioactive_ralph run --variant blue --detachlaunches a backgrounded supervisor;radioactive_ralph statusreturns healthy;radioactive_ralph stopterminates cleanly; no leftover PID/socket/worktreeradioactive_ralph doctorexit 0 on healthy machine, exit 1 with remediation list on brokenGated integration test (real
claude -p,CLAUDE_AUTHENTICATED=1): spawn, inject message, verify response event, kill, resume, sentinel re-prompt succeeds.claude-plugin/marketplace.jsonvalidates underclaude plugin validate .(unchanged from M1)GoReleaser dry-run succeeds:
goreleaser release --snapshot --cleanproduces all artifacts (brew formula, Scoop manifest, WinGet manifest, tarballs, checksums)Homebrew tap repo
jbcom/homebrew-tapexists with an initial Formula/ralph.rb placeholder
M3¶
All 10 variant profiles type-check and pass
golangci-lintSafety-floor tests pass (single-flag rejected, two-step accepted)
grey: single-pass withMaxParallel == 1blue: excludes Edit + Write from tool allowlist (compile-time)Auto-generated variants-matrix.md is stable across consecutive runs
Skills ≤30 lines each
M4¶
All integration scenarios pass (gated ones skip cleanly without
CLAUDE_AUTHENTICATED)radioactive_ralph doctorpasses on both macOS and Linux CI runnersradioactive_ralph service install --variant greeninstalls and can bebrew services start-ed on macOS CI1.0.0 published to GitHub Releases, Homebrew tap, Scoop, WinGet
Install script at
jonbogaty.com/radioactive-ralph/install.shworks end-to-end on macOS and Linuxreference/deleted
7. Technical notes¶
Go deps (target):
github.com/alecthomas/kong— CLI parsinggithub.com/BurntSushi/tomlorgithub.com/pelletier/go-toml/v2— config TOMLmodernc.org/sqlite— pure-Go SQLite (no CGo)github.com/asg017/sqlite-vec-go-bindings— vec0 virtual tablegithub.com/gofrs/flock— cross-platform file lockinggithub.com/google/uuid— session IDsstdlib:
os/exec,encoding/json,bufio,net,syscall,context,sync,log/slog
No Anthropic SDK. The daemon speaks to Claude only through the
claude -p binary. If we ever need a direct Anthropic API call (we
don’t in the current design), it’s a ~100-line net/http struct.
No GitHub API client. Forge interactions happen inside worktree
Claude sessions via the gh CLI, which Claude already knows how to
drive.
--bare flag on every managed spawn for reproducibility.
Supervisor owns the system prompt via --append-system-prompt.
Session ID strategy: stable UUID per session, pinned via
--session-id <uuid>. Supervisor stores in SQLite. Resume reuses.
sqlite-vec vs FTS5: prefer sqlite-vec for semantic task dedup; soft-fail to FTS5 if extension loading fails at runtime.
State directory: $XDG_STATE_HOME/radioactive-ralph/<repo-hash>/
on Linux / WSL; ~/Library/Application Support/radioactive-ralph/ <repo-hash>/ on macOS per Apple conventions.
Cross-platform daemon detach: syscall.Setsid() + fork/exec
pattern for the Python-free fallback (Linux + macOS). Windows is not
supported for the radioactive_ralph run direct invocation; Windows users invoke
via WSL2+Linuxbrew where the Linux path works. The ralph binary on
Windows only supports radioactive_ralph init / status / doctor (config-manipulation
commands); the supervisor requires a POSIX environment.
Release tooling: GoReleaser generates brew, Scoop, WinGet artifacts
from one .goreleaser.yaml on git tag push. No code signing in initial
releases. cosign for supply-chain provenance.
8. Risks¶
R1 — Stream-json protocol drift¶
Pin claude version range in doctor. Protocol-ping on supervisor boot.
Raw + parsed payload storage so forward-compat fixes can replay old
events.
R2 — Session file format drift¶
Sentinel re-prompt with task-ID verification after every resume. Task-state checkpoints rich enough to reseed a fresh session if resume fails.
R3 — Pre-flight UX complexity¶
Silent-when-passing detectors. Remembered answers in config.toml.
--yes flag. Three severity levels.
R4 — Multiplexer quirks on macOS¶
tmux strongly recommended (doctor top-priority remediation). Stdlib
syscall.Setsid fallback instead of external daemon library.
Heartbeat file detects liveness independently of PID.
R5 — Risky variants running unattended¶
Per-variant safety floors (object_store = full pinned for destructive
ones; two-step override). Spend caps. First-invocation dry-run consent.
Mirror-based isolation keeps destructive ops in XDG, never operator’s
working tree. Service-context detection refuses floor-gated variants
under launchd/systemd.
R6 — Scope creep¶
Explicit out-of-scope list. Public API = CLI + Profile fields.
No internal package is semver-stable.
R7 — config.toml teammate breakage¶
Two-file split (config.toml committed, local.toml gitignored per-
operator). radioactive_ralph init --local-only bootstraps a teammate’s local.toml.
R8 — Multi-variant race conditions¶
Per-variant-scoped paths (<variant>.sock, etc.). SQLite WAL handles
interleaved writes. allow_concurrent_variants config toggle.
R10 — LFS surprises¶
Auto-detect on init. Variant-appropriate defaults. excluded mode
refuses tasks that touch LFS paths with clear error.
R11 — Hook skipping¶
Copy operator’s .git/hooks/ into mirror on init. copy_hooks = false
opt-out.
R12 — Spend-tracking pricing drift¶
Pricing table is a generated constant updated on each release. Doctor warns when >30 days old.
R13 — GoReleaser cascade failures¶
GitHub Actions release.yml pins GoReleaser version. Brew tap / Scoop bucket / WinGet PR each retriable.
R14 — Inventory staleness¶
radioactive_ralph init --refresh re-discovers without losing choices. Supervisor
logs at INFO when config.toml references skills not in inventory.
9. Out of scope¶
Web dashboard beyond
radioactive_ralph attachstreamingMulti-operator coordination (one operator per daemon per variant per repo)
Non-git workspaces
Hosted / SaaS mode
LLM providers other than Anthropic
MCP server acting as a live bridge (confirmed impossible in Claude Code 2026)
Automatic pricing-table updates (out-of-band release cadence)
Variant modules published as separate packages (operator customization via config.toml is the extension story)
Direct internal git operations in the daemon (every git op happens via Claude in a worktree, or via
os/execin the workspace manager for mirror/worktree management only)Direct forge API calls in the daemon (Claude uses
ghCLI in worktrees)Direct Anthropic API calls in the daemon (Claude runs via
claude -psubprocesses)Windows
radioactive_ralph rundirect invocation (WSL2+Linuxbrew is the Windows path)macOS code signing / notarization (unsigned FOSS binaries are the ecosystem standard; brew + curl|sh bypass Gatekeeper)