diff --git a/.scratch/distributed-inference-network/issues/15-ralph-agent-agnostic-status-aware.md b/.scratch/distributed-inference-network/issues/15-ralph-agent-agnostic-status-aware.md new file mode 100644 index 0000000..f43ad2d --- /dev/null +++ b/.scratch/distributed-inference-network/issues/15-ralph-agent-agnostic-status-aware.md @@ -0,0 +1,140 @@ +# US-015 — Ralph: agent-agnostic runner + status-field-aware dashboard + +Two tightly coupled improvements to the Ralph workflow tooling: + +1. **Status-field awareness** — `ralph_progress.py` currently reads `passes: true/false` everywhere. Replace all `passes` references with the rich `status` field introduced in the prd.json schema migration. Surface `to-revise` and `needs-review` stories as an attention list rather than treating them like failed or blocked tasks. + +2. **Agent-agnostic runner** — Ralph currently hardcodes `agentPlugin: "codex"` and always calls `ralph-tui run --agent codex`. Make the agent selectable per session with first-class support for Claude Code CLI, OpenRouter (unified API covering GPT-4, Mistral, DeepSeek, Llama, etc.), and the existing Codex plugin. + +## Part 1: Status-field awareness in ralph_progress.py + +### What to replace + +Every occurrence of `story.get("passes")` in `scripts/ralph_progress.py` must be replaced with a helper that reads the `status` field with a `passes` fallback for backward compatibility: + +```python +# Status → done mapping (backward-compat: passes=True counts as done if no status field) +_DONE_STATUSES = {"done"} +_ATTENTION_STATUSES = {"to-revise", "needs-review"} +_ACTIVE_STATUSES = {"in-progress"} +_DESIGN_STATUSES = {"in-design"} + +def _is_done(story: dict) -> bool: + status = story.get("status") + if status: + return status in _DONE_STATUSES + return bool(story.get("passes")) # fallback + +def _needs_attention(story: dict) -> bool: + return story.get("status") in _ATTENTION_STATUSES + +def _is_active(story: dict) -> bool: + return story.get("status") in _ACTIVE_STATUSES + +def _is_in_design(story: dict) -> bool: + return story.get("status") in _DESIGN_STATUSES +``` + +### `_story_sets` rewrite + +Current behaviour lumps `to-revise` into the "done" bucket (because `passes=True`) or the "open" bucket. New behaviour: + +``` +done → status == "done" (or passes=True fallback) +attention → status in {to-revise, needs-review} ← new bucket +active → status == "in-progress" +in-design → status == "in-design" (treated as blocked — needs human before agent) +ready → status == "open" AND all deps done +blocked → status == "open" AND some dep not done +``` + +### `_deps_done` rewrite + +Dependency is satisfied when the dep story `_is_done()` — not when `passes=True`. + +### Dashboard additions + +``` +Ralph progress: Distributed Inference Network +PRD: .scratch/distributed-inference-network/prd.json +[############################] 13/15 complete (86%) +Done: 13 Ready: 1 Attention: 2 Blocked: 0 + +⚠ Attention required (review before running): + ⚠ US-002 02 — Two-node shard pipeline + Wire format replaced by US-011 binary protocol; verify tests. + ⚠ US-005 05 — OpenAI-compatible gateway + Gateway orchestration superseded by US-014; defer until US-014 lands. + +→ US-014 14 — Tracker-as-first-layer-node (inference entry point) +``` + +### `auto` command behaviour + +`auto` skips `to-revise` and `needs-review` stories — they need human review before an agent re-runs them. Add `--include-revise` flag to override this for unattended runs. + +### `_review_report` additions + +Include a dedicated **Attention Required** section in the generated review brief listing all `to-revise` and `needs-review` stories with their `status_reason`. + +--- + +## Part 2: Agent-agnostic runner + +### Agent selection + +Add `--agent` option with these values: + +| Value | CLI invoked | Config required | +|-------|-------------|-----------------| +| `codex` | `ralph-tui run --agent codex ...` | `OPENAI_API_KEY` (existing) | +| `claude` | `ralph-tui run --agent claude ...` | `ANTHROPIC_API_KEY` | +| `openrouter` | `ralph-tui run --agent openrouter ...` | `OPENROUTER_API_KEY` + `--model` | +| `custom` | `--agent-cmd ` | user-defined | + +If `ralph-tui` does not natively support a requested agent plugin, `ralph_progress.py` falls back to invoking the agent CLI directly with the task prompt file, bypassing `ralph-tui run` entirely. + +### Persistent agent config + +Save the last-used agent choice to `.ralph-tui/agent-config.json` so it doesn't have to be passed on every command: + +```json +{ + "agent": "openrouter", + "model": "anthropic/claude-opus-4", + "updatedAt": "2026-06-29T..." +} +``` + +`--agent` on the CLI always overrides the saved config. `ralph_progress.py set-agent --agent openrouter --model openai/gpt-4o` writes the config file. + +### OpenRouter adapter + +When `agent == "openrouter"` and `ralph-tui` doesn't natively support it, `ralph_progress.py` implements a thin adapter: + +1. Read the task prompt from the issue file + prd.json story +2. POST to `https://openrouter.ai/api/v1/chat/completions` with `OPENROUTER_API_KEY` +3. Stream response to stdout +4. Watch prd.json for `status` change to detect task completion +5. Timeout after configurable duration (default: 10 minutes per task) + +The OpenRouter model is set via `--model` (e.g. `openai/gpt-4o`, `mistralai/mistral-large`, `meta-llama/llama-3-70b-instruct`). Default: `anthropic/claude-opus-4`. + +### `custom` agent + +`--agent custom --agent-cmd ./my-agent.sh` — Ralph passes the task prompt file path as `$1`. The script exits 0 on success. This makes Ralph compatible with any future agent tool without code changes. + +--- + +## Acceptance Criteria + +- All `passes` reads in `ralph_progress.py` replaced with `_is_done()` helper (with fallback) +- `_story_sets` returns five buckets: done, attention, active, in-design, ready, blocked +- Dashboard shows `⚠ Attention required` section with `status_reason` for each affected story +- `auto` skips `to-revise` / `needs-review` by default; `--include-revise` overrides +- `ralph_progress.py set-agent --agent ` writes `.ralph-tui/agent-config.json` +- `--agent codex|claude|openrouter|custom` accepted by all subcommands that invoke Ralph +- `ralph_progress.py run-next --agent openrouter --model openai/gpt-4o` runs a task via OpenRouter adapter +- `ralph_progress.py run-next --agent custom --agent-cmd ./my-agent.sh` runs a task via custom script +- `python -m pytest` passes from repo root +- Commit only this story's changes diff --git a/.scratch/distributed-inference-network/prd.json b/.scratch/distributed-inference-network/prd.json index 03677ff..9d132db 100644 --- a/.scratch/distributed-inference-network/prd.json +++ b/.scratch/distributed-inference-network/prd.json @@ -353,10 +353,33 @@ "US-013" ], "status": "open" + }, + { + "id": "US-015", + "title": "15 \u2014 Ralph: agent-agnostic runner + status-field-aware dashboard", + "description": "Two improvements to the Ralph workflow tooling. (1) Status-field awareness: replace all passes:true/false reads in ralph_progress.py with the rich status field. Surface to-revise and needs-review stories as an attention list in the dashboard; auto command skips them by default. (2) Agent agnosticism: make the agent selectable per session \u2014 codex (existing), claude (Claude Code CLI), openrouter (unified API for GPT-4/Mistral/Llama/DeepSeek via OPENROUTER_API_KEY + --model), or custom (--agent-cmd path to any script). Persist agent choice to .ralph-tui/agent-config.json. When ralph-tui does not natively support a requested agent, ralph_progress.py falls back to a thin adapter that calls the agent API directly with the task prompt.", + "acceptanceCriteria": [ + "All story.get('passes') reads in ralph_progress.py replaced with _is_done() helper that reads status field with passes fallback", + "_story_sets() returns six buckets: done, attention (to-revise/needs-review), active (in-progress), in-design, ready, blocked", + "Dashboard shows \u26a0 Attention required section listing to-revise/needs-review stories with status_reason", + "auto command skips to-revise and needs-review stories; --include-revise flag overrides", + "_review_report includes Attention Required section with status_reason for all affected stories", + "ralph_progress.py set-agent --agent [--model ] writes .ralph-tui/agent-config.json", + "--agent codex|claude|openrouter|custom accepted by show, run-next, auto, review subcommands", + "run-next --agent openrouter --model openai/gpt-4o successfully runs a task via OpenRouter API", + "run-next --agent custom --agent-cmd ./my-agent.sh runs a task via custom script (prompt file as $1)", + "Saved agent config is loaded as default when --agent is not passed on the CLI", + "python -m pytest passes from repo root", + "Commit only this story's changes" + ], + "priority": 15, + "status": "open", + "notes": "Source issue: .scratch/distributed-inference-network/issues/15-ralph-agent-agnostic-status-aware.md", + "dependsOn": [] } ], "metadata": { - "updatedAt": "2026-06-29T13:15:00.000Z", + "updatedAt": "2026-06-29T13:20:00.000Z", "statusVocabulary": { "open": "Not started", "in-design": "Decisions pending before implementation can begin",