Full-stack architecture
VELA is a ground-segment, advisory system. This page is the map of the whole stack; the design — architecture doc goes deeper on the reasoning graph, and data & ingest covers the telemetry pipeline.
The stack at a glance
Section titled “The stack at a glance”One composition root, two entry points
Section titled “One composition root, two entry points”vela/orchestration.py::prepare_investigation turns a scenario into a PreparedInvestigation — a
triggering AnomalyEvent, a wired in-process MCP client, and a reasoning model. Both the CLI
(vela/cli.py) and the HTTP service (vela/api/) go through it, so they drive an identical graph and
produce identical reports. Store wiring happens here, deliberately outside the agent layer.
The reasoning graph is fixed and deterministic
Section titled “The reasoning graph is fixed and deterministic”vela/agents/graph.py is an auditable blueprint — not an agent choosing its own path:
supervisor ─┬─(suppressed)──────────────────────────────► END └─(investigate)─► triage ─► investigator ─► validator ─► drafter ─┬─(procedure)─► approval ─► END └─(none)──────────────────► END- State is a
TypedDict;audit_logis a reducer. Each node returns only its ownAgentTraceStep(annotated withoperator.add) — never a read-modify-write of the accumulated list. - The approval gate is a real
interrupt(). The graph compiles with a checkpointer keyed bythread_id == investigation_id. Resuming withCommand(resume=…)continues the run. On resume the interrupted node re-executes from the top, so the only code beforeinterrupt()inapproval_nodeis deterministic and idempotent.
The MCP boundary is the audit boundary
Section titled “The MCP boundary is the audit boundary”vela/mcp/client.py defines the MCPClient Protocol — the complete data surface available to
reasoning, spanning three servers:
| Server | Tools |
|---|---|
| knowledge | channels_to_components, get_failure_modes, search_docs, get_doc_section, resolve_citation |
| telemetry | get_window, get_command_history, compare_to_baseline |
| procedure | get_procedure_templates, validate_procedure, format_report |
InProcessMCPClient calls the tool functions directly (the real path today); serving them as real
MCP endpoints over stdio/HTTP is a documented future seam. Every result is stamped with as_of for
deterministic provenance.
Stores sit behind protocols
Section titled “Stores sit behind protocols”GraphStore(vela/kg/store.py) →InMemoryGraphStore|Neo4jGraphStoreDocSearch(vela/kg/doc_search.py) →GraphKeywordDocSearch|QdrantDocSearch|HybridDocSearch
Chosen via store_backend / doc_search_backend in Settings, overridable by env. Nothing above the
MCP layer changes when you swap them (ADR 0007).
Contracts are the single source of truth
Section titled “Contracts are the single source of truth”Pydantic v2 models in vela/contracts.py (VelaModel, extra="forbid") define every shared shape.
apps/console/src/api/types.ts mirrors them by hand — a contract change updates both in the same
change. See ADR 0002.
Reasoning: deterministic by default, real Claude available
Section titled “Reasoning: deterministic by default, real Claude available”get_model returns DeterministicModel by default — required in airgap, used by the golden/CI
suite for reproducibility. AnthropicModel (vela/agents/models/anthropic.py) is implemented and
live-verified, key-gated and config-selected; its release-blocking grounding gates fail closed to
INSUFFICIENT. Prompts live in versioned .md files under vela/agents/prompts/, never inline
f-strings.
Frontend
Section titled “Frontend”One frontend: apps/console/ — the operator / production surface, contract-aligned, RBAC-gated,
wired to the live API, tested (vitest + Playwright). See Frontend console.
