althor
All work
Case study · Active development

Spire

An AI-native infrastructure control plane built in Rust — operator surface for running agents against real systems without handing them master keys.

The premise

Most agent frameworks assume the agent is the operator. Spire assumes the operator is the operator and the agent is a tool the operator wields. The control plane decides which actions auto-execute, which actions queue for approval, which actions are forbidden, and what the audit story is for every one. The agent is a powerful subordinate, not a co-pilot.

That framing changes every layer. Tool access is read-only by default. Writes go through policy. Policy decisions are recorded. Approvals are first-class workflow objects, not chat messages.

Architecture

AgentMCP tool layer (scoped, read-only guards)Policy check (is this a protected resource?)Confidence gate (≥ threshold → auto-apply · < threshold → queue approval)Staged remediation (dry-run → apply → verify → audit)Audit event · reversible · reviewable

Single-binary deploy

The whole control plane — backend, frontend, embedded migrations, MCP client — ships as one Rust binary in a small Docker image. rust-embed bundles the React build into the binary; SQLite is the persistence layer; bollard talks to the local Docker socket. There is no orchestration to maintain because there is nothing to orchestrate.

This isn't minimalism for its own sake. It's the single feature that makes Spire trivially deployable on a homelab, an edge node, or an air-gapped review environment. The operator surface follows the operator wherever they are.

Policy-gated approvals

Every action the agent proposes routes through a policy check. Reads of non-sensitive data auto-execute. Writes against critical services queue. The policy is declarative — protected resources, action types, confidence thresholds — and lives next to the audit log so a reviewer can trace why a given action did or didn't auto-apply.

Approvals are not chat messages. They are objects with state (pending, approved, denied, expired), a reviewer, a justification, and a hard link to the audit event the action produced. They survive restarts. They are queryable by who and when.

MCP tool layer

Spire exposes its capabilities to the agent through MCP servers, one per concern: containers, observability, library, infrastructure, home automation, database. Each server enforces its own auth boundary; each server's tools are read-only-first; writes are tagged and policy-checked at the control-plane layer.

The agent never sees a Docker socket. It sees list_containers, get_logs, restart_container — and restart_container is policy-gated.

Three-second cancellable countdown

Auto-applied actions don't execute instantly. They show in the operator UI with a three-second countdown that the operator can cancel with one keystroke. This is a small UX detail with a large effect: the operator stays in the loop on auto-applied actions without being blocked by them. The countdown is the seam between automated and supervised — and it's where the operator's hand stays on the kill switch.

Decisions and trade-offs

Rust over Node

The control plane runs as a single long-lived process, talks to system sockets, and parses moderately large structured streams. The runtime characteristics that matter — stable memory, no GC pauses, deterministic shutdown — are easier to get right in Rust than in Node. The frontend is React; the backend is not.

SQLite, not Postgres

The control plane's data is operator-scale, not internet-scale. SQLite holds it comfortably and removes a whole class of operational surface. The persistence layer is a file. Backups are a copy. There is no migration of an external database to manage.

Read-only by default

Every new tool starts read-only. Adding a write capability is an explicit step that requires writing the policy that gates it. This isn't a code-review checklist; it's a structural property of how tools are added.

Stack

Rust Axum sqlx SQLite bollard tokio React Vite Tailwind Motion xyflow Model Context Protocol rust-embed

What's interesting about it

All work