- Get Started

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

ComponentTechnologyPurpose
Flow Enginepocketflow-core (Tokio)Routes work between agent nodes via typed Actions; retries failed nodes up to max_retries=3
SharedStoreIn-memory / Redis (fred)Central state machine - tickets, worker_slots, pending_prs, flow_recovery. Dual-mode: in-memory for dev, Redis for production.
Coder WorkspaceWorkspaceTransport traitProvisions ephemeral workspaces via Coder API; installs CLI module, manages lifecycle, tears down after merge. Local mode unchanged.
AI GatewayCoder AI Gateway + LiteLLM fallbackRoutes LLM calls centrally. API keys managed by Coder, never exposed inside workspaces. Falls back to LiteLLM for air-gapped.
GitHub ClientMCP + REST (reqwest)Issue discovery, PR creation, CI polling, merging. Identity via Coder external auth - no PATs.
TUIopenflows-tui (ratatui)Setup wizard, live dashboard, doctor diagnostics

WorkspaceTransport - the Coder integration abstraction

All filesystem and process operations route through the 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:

  1. NEXUS polls GitHub - discovers open issues, syncs them as tickets into SharedStore
  2. NEXUS assigns - matches ticket to an idle FORGE worker, updates worker_slots
  3. NEXUS provisions Coder workspace - ephemeral workspace created from template; coder_module installs the CLI code agent
  4. FORGE writes PLAN.md - segment breakdown inside the workspace; SENTINEL reviews before any code is written
  5. SENTINEL reviews plan - writes CONTRACT.md (AGREED / CHANGES_REQUESTED)
  6. FORGE implements - segment by segment; after each commit SENTINEL writes segment-N-eval.md
  7. SENTINEL final review - writes final-review.md; APPROVED unblocks PR creation
  8. FORGE opens PR - via GitHub MCP; STATUS.json written with PR_OPENED
  9. VESSEL polls CI - 10s interval; detects conflicts early via mergeable field
  10. VESSEL merges - squash merge with ticket reference; emits ticket_merged
  11. LORE documents - writes ADR, updates CHANGELOG.md, commits via GitHub MCP
  12. Workspace torn down - Coder workspace destroyed; no lingering state, no stale credentials
  13. NEXUS loops - picks next ticket or halts gracefully if no work remains

SharedStore Keys

KeyTypeDescription
ticketsMap<TicketId, TicketStatus>All tickets: open, assigned, in_progress, completed, merged
worker_slotsMap<WorkerId, WorkerStatus>All workers: idle, assigned, working, suspended, done
pending_prsVec<PrEntry>PRs waiting for VESSEL to merge
flow_recoveryRecoveryStateDetected inconsistencies for NEXUS to resolve
event_ringRingBuffer (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.

LayerHow it works
1. Decision ToolPrimary path. LLM calls submit_decision structurally - reasoning in text, decision in tool args. Zero extraction needed. Works across all providers.
2. Enhanced Extraction7 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. Retryrecover_decision() sends a clarified prompt up to DECISION_RETRY_LIMIT=2 times before giving up.
4. Safe DefaultReturns a no_work AgentDecision with [SELF-HEAL] prefix instead of crashing. The agent skips this cycle and tries again next time.
5. Flow RecoveryFlow::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()

On every poll cycle, NEXUS runs 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