System Design
OpenFlows is built as an async, event-driven system in Rust using the PocketFlow engine - a directed graph where agents are nodes that communicate through a typed SharedStore. Each agent runs inside an ephemeral Coder workspace that is provisioned when a task is assigned and torn down after merge. LLM calls route through the Coder AI Gateway; GitHub identity comes from Coder external auth.
Core Components
| Component | Technology | Purpose |
|---|---|---|
| Flow Engine | pocketflow-core (Tokio) | Routes work between agent nodes via typed Actions; retries failed nodes up to max_retries=3 |
| SharedStore | In-memory / Redis (fred) | Central state machine - tickets, worker_slots, pending_prs, flow_recovery. Dual-mode: in-memory for dev, Redis for production. |
| Coder Workspace | WorkspaceTransport trait | Provisions ephemeral workspaces via Coder API; installs CLI module, manages lifecycle, tears down after merge. Local mode unchanged. |
| AI Gateway | Coder AI Gateway + LiteLLM fallback | Routes LLM calls centrally. API keys managed by Coder, never exposed inside workspaces. Falls back to LiteLLM for air-gapped. |
| GitHub Client | MCP + REST (reqwest) | Issue discovery, PR creation, CI polling, merging. Identity via Coder external auth - no PATs. |
| TUI | openflows-tui (ratatui) | Setup wizard, live dashboard, doctor diagnostics |
WorkspaceTransport - the Coder integration abstraction
WorkspaceTransport trait. In Coder mode, this provisions real Coder
workspaces via the API. In local mode, it falls back to Git worktrees on disk.
The rest of the system is transport-agnostic - it doesn't know or care where the
agent runs.
Data Flow
A typical issue-to-merge cycle follows this sequence:
- NEXUS polls GitHub - discovers open issues, syncs them as tickets into SharedStore
- NEXUS assigns - matches ticket to an idle FORGE worker, updates worker_slots
- NEXUS provisions Coder workspace - ephemeral workspace created from template;
coder_moduleinstalls the CLI code agent - FORGE writes PLAN.md - segment breakdown inside the workspace; SENTINEL reviews before any code is written
- SENTINEL reviews plan - writes
CONTRACT.md(AGREED / CHANGES_REQUESTED) - FORGE implements - segment by segment; after each commit SENTINEL writes
segment-N-eval.md - SENTINEL final review - writes
final-review.md; APPROVED unblocks PR creation - FORGE opens PR - via GitHub MCP;
STATUS.jsonwritten with PR_OPENED - VESSEL polls CI - 10s interval; detects conflicts early via
mergeablefield - VESSEL merges - squash merge with ticket reference; emits
ticket_merged - LORE documents - writes ADR, updates
CHANGELOG.md, commits via GitHub MCP - Workspace torn down - Coder workspace destroyed; no lingering state, no stale credentials
- NEXUS loops - picks next ticket or halts gracefully if no work remains
SharedStore Keys
| Key | Type | Description |
|---|---|---|
tickets | Map<TicketId, TicketStatus> | All tickets: open, assigned, in_progress, completed, merged |
worker_slots | Map<WorkerId, WorkerStatus> | All workers: idle, assigned, working, suspended, done |
pending_prs | Vec<PrEntry> | PRs waiting for VESSEL to merge |
flow_recovery | RecoveryState | Detected inconsistencies for NEXUS to resolve |
event_ring | RingBuffer (1000) | Last 1000 events - powers TUI real-time monitoring |
Crash Recovery & Self-Healing
Agents are LLM-driven, and LLMs are unpredictable. OpenFlows doesn't pretend otherwise - it has a five-layer crash recovery stack that catches failures at every level, from malformed LLM output to crashed nodes.
| Layer | How it works |
|---|---|
| 1. Decision Tool | Primary path. LLM calls submit_decision structurally - reasoning in text, decision in tool args. Zero extraction needed. Works across all providers. |
| 2. Enhanced Extraction | 7 fallback parsing strategies when text-only response: clean JSON, markdown blocks, last JSON object, truncated repair, line-by-line, loose key extraction, pattern matching. |
| 3. Retry | recover_decision() sends a clarified prompt up to DECISION_RETRY_LIMIT=2 times before giving up. |
| 4. Safe Default | Returns a no_work AgentDecision with [SELF-HEAL] prefix instead of crashing. The agent skips this cycle and tries again next time. |
| 5. Flow Recovery | Flow::run() catches node errors, retries up to max_retries=3, routes to node_error or awaiting_human handler. NEXUS marks ticket AwaitingHuman and suspends the worker. |
NEXUS reconcile()
reconcile() - it detects orphaned
tickets, unmerged PRs, stale workers, and completed_without_pr states,
then resumes at the correct phase. If a worker is stuck, NEXUS can re-assign the
ticket or escalate to AwaitingHuman. The system self-heals without
human intervention for all recoverable failures.
Design Principles
- Architecture is the product - agents plan before they execute. FORGE writes
PLAN.md, SENTINEL reviews it, and only then does code get written. Engineering goes in, software comes out. - Ephemeral Coder workspaces - each FORGE worker gets a fresh workspace provisioned from template; torn down after merge. No lingering state, no stale credentials, no disk bloat.
- Ephemeral reviewers - SENTINEL is spawned fresh per evaluation in its own workspace; no accumulated bias.
- Adversarial review - FORGE and SENTINEL can use different LLM providers (e.g. Anthropic for FORGE, OpenAI for SENTINEL), creating natural adversarial review - the reviewer uses a different model family than the writer.
- Flow recovery - NEXUS detects and resumes broken pipeline phases on every cycle via
reconcile(). - Human-in-the-loop only when needed - CommandGate for dangerous commands;
AwaitingHumanescalation only for spec ambiguity, security concerns, or resource limits. - Centrally managed LLM keys - API keys live in the Coder AI Gateway, never inside workspaces. Air-gapped deployments fall back to LiteLLM with self-hosted models.
- Dual-backend state - in-memory for dev/tests, Redis for production; zero config change required.