-
Notifications
You must be signed in to change notification settings - Fork 1
Architecture
Two programs, one version line, one boundary between them and everything OmniRoute does.
OmniHarness treats OmniRoute as an opaque provider execution layer. It never reads or stores provider credentials, never talks to an upstream provider directly, and never implements quota or provider-translation logic itself. What it does do: analyze a task, choose a strategy, orchestrate agents, express model-selection intent as provider/model plus a capability, send OpenAI-compatible chat requests to the configured endpoint, and record what actually happened — cost, tokens, outcome.
internal/gateway is the only package that speaks to OmniRoute. Swapping the transport — a different gateway, a direct provider, an in-process stub for tests — is a one-file change, which is what lets the whole Go suite run without a live OmniRoute server.
USER
│
▼
CLI ──────────┐ ┌── TUI (thin consumer of the event bus)
▼ ▼
┌─────────────────────────────┐
│ core.Runtime │ wiring, lifecycle, shutdown
└─────────────┬───────────────┘
▼ typed events (internal spine)
┌──────────┬──────────┬──────────┬──────────────┬─────────────┐
│ Task │Strategy │Orchestr. │ Agent │ Context │
│ Analyzer │ Engine │ (graph) │ Runtime │ Composer │
└────┬─────┴────┬─────┴────┬─────┴──────┬───────┴──────┬──────┘
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Budget │ │ Policy │ │ Tools + │ │ Evaluate │ │ Repair │
│ Engine │ │ Engine │ │ MCP │ │ Engine │ │ Engine │
└──────────┘ └──────────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────┐
│ Model Selection Engine │
└──────────────────┬──────────────────┘
▼ intent: provider/model + capabilities
┌─────────────────────────────────────┐
│ gateway.Client → OmniRoute HTTP │ ← the ONLY boundary
└─────────────────────────────────────┘
▼
┌──────────────────┐
│ OmniRoute │ providers, accounts, quota
└──────────────────┘
Cross-cutting: event (the spine every state change flows through), session (durable SQLite state), telemetry (recorded from real events, never fabricated), memory (performance and project memory).
cmd/omniharness entry point
internal/event typed event system (spine)
internal/config TOML config + validation
internal/session session/task/agent persistence (SQLite, modernc)
internal/task Task model + Analyzer → TaskProfile
internal/strategy strategy selection from profile
internal/orchestrator task-graph scheduler, worker pool, result synthesis
internal/agent agent runtime, roles, lifecycle state machine
internal/model capability-based model selection
internal/gateway OmniRoute OpenAI-compatible client — the only boundary
internal/context context engine + composer
internal/memory project + performance memory (SQLite)
internal/tools tool registry + native tools (fs, shell, git, search, proc)
internal/mcp MCP stdio client
internal/policy risk classes, permission evaluation, approvals
internal/evaluate evaluator framework (build/test/lint/constraint/evidence)
internal/repair failure classification + repair strategies
internal/budget token/cost/time/agent/tool-call budgets
internal/telemetry metric recording + aggregation
internal/cli cobra commands (headless-first)
internal/tui the original Bubble Tea cockpit (still builds; users run the npm one)
internal/combo model-combo registry (auto/* routing combos + catalog)
internal/version build info
Dependency direction is downward only. event and config are leaves. No cycles.
The terminal UI most people run is the TypeScript one under npm/, not internal/tui — see its own layout in CONTRIBUTING.
-
The event system is the spine. A typed envelope (
Event{Type, Data}), a fan-out bus with bounded per-subscriber buffers that drop the oldest event rather than ever block the runtime, full persistence per session for replay and debugging. -
SQLite via
modernc.org/sqlite— pure Go, no CGO, so the build needs no C toolchain on any platform. This is also what let one runner cross-compile all six release binaries. - Strategy selection is a pure function of the task profile, budgets, and historical performance — testable with no runtime attached.
- Single-agent is a first-class strategy, not a degenerate case of multi-agent. The engine can say "one agent, direct" and mean it.
-
Model selection speaks intent, not identity. A capability (reasoning, fast, cheap, long-context, coding, vision, tools, research, review) resolves to a concrete
provider/modelvia config plus a live catalog probe, only at request time. - Repair changes variables, never blind-retries the identical failed execution — model, role, context, instructions, or the execution strategy itself.
- No fabricated telemetry. Every metric shown anywhere comes from a recorded event or a session row. See Security Model for what this means for the numbers a session panel is and isn't allowed to show.
- MCP is first-class, not bolted on — a native stdio JSON-RPC client, with MCP tools registered into the same registry as native tools so policy applies identically to both.
- The TUI is a consumer, not a source of truth. All state flows through the runtime event bus; it renders and sends control commands.
-
The API key is never written by
Save. Config save scrubs the key before encoding, so an env-provided key can never leak into the config file on disk.
Every spawned process — shell, git, an evaluator, an MCP server — inherits the parent environment minus OMNIROUTE_API_KEY, OMNIHARNESS_API_KEY, and ROUTER_API_KEY. That list can't be turned off from config. Third-party credentials (GITHUB_TOKEN, AWS_SECRET_ACCESS_KEY, NPM_TOKEN) are inherited by default — an agent asked to open a PR or publish a package needs them — and a deployment that doesn't want that names them in policy.secret_env. See Security Model for the full list of what's in and out of scope.