Architecture
Mentat is designed as a private workload platform with a small control plane, a host-level agent, and a CLI for operations. The goal is simple: keep deployment, scheduling, health, and service lifecycle in one system without the operational weight of a larger platform stack.
What Runs Where
mentat-server
The control plane. Receives jobs, stores state, schedules workloads, and coordinates deployments, rollbacks, and node state.
mentat-agent
Runs on each host. Starts workloads through Firecracker, Sandbox, Docker, exec, or Hull, reports status, and keeps runtime details close to the node.
mt
The operator interface. Teams use it to deploy, scale, inspect, and roll back services from a single command surface.
mentat-types
Shared types for service definitions, resources, deploy strategies, constraints, and runtime state.
Operating Model
The architecture is optimized for private infrastructure. The server decides where a workload should run, the agent materializes it on the host, and the CLI stays thin. This keeps the control plane small while still supporting mixed runtimes and deployment workflows.
1. Operator runs: mt run services.yaml
2. CLI validates the file and sends the job to mentat-server
3. Server stores desired state and picks a node
4. Server dispatches an allocation to mentat-agent
5. Agent starts the workload with the selected driver
6. Server records runtime state and returns status to the operatorKnowing What Is Wrong
A health monitor probes every registered endpoint every 10 seconds and writes a conclusion into the registry: healthy, starting, unhealthy. Past a threshold of consecutive failures it restarts the workload through the agent, with a cooldown so a slow boot does not turn into a restart storm.
The conclusion alone is rarely enough during an incident — it says what, not why. So the counters behind it are readable too: how many probes have failed in a row, whether a restart is in flight, how long ago the service was last restarted, and the condition of the node each endpoint sits on. mt diagnosereads those, probes the endpoints again on the spot, pulls the workload's recent output through the agent, and reports findings. Everything on that path is read-only, which is what makes it safe to run while something is already broken.
mt://services/{name}/health status + the counters behind it
mt://services/{name}/diagnose the above + live probes, logs, findings
mt://nodes lifecycle conditions per node
mt://registry every endpoint the agent registeredA workload started outside the agent is invisible here: the agent registers only what it spawned, ingress routes only what the registry knows, and a port answering on the host proves neither. That gap is itself one of the findings mt diagnose reports.
Why This Shape
| Small control plane | Keeps memory use and failure surface low |
| Host-level agent | Keeps runtime-specific logic close to the node |
| Thin CLI | Easy to automate from SSH, CI, or operator workflows |
| Shared types | One config model across deploys, drivers, and status |
| Driver abstraction | One platform for VMs, containers, binaries, and Hull workloads |
Service Definition Model
Services declare runtime, resources, constraints, and deploy strategy in one spec. That same model flows through scheduling, rollout, and status.
pub enum Driver { Firecracker, Sandbox, Docker, Exec, Hull }
pub enum DeployStrategy { Rolling, BlueGreen, Canary }
pub enum DriverConfig {
Firecracker(FirecrackerConfig),
Sandbox(SandboxConfig),
Docker(DockerConfig),
Exec(ExecConfig),
Hull(HullConfig),
}
pub struct ServiceSpec {
pub name: String,
pub replicas: u32,
pub config: DriverConfig,
pub resources: Resources,
pub constraints: Vec<Constraint>,
pub deploy: DeployConfig,
}Implementation Stack
| Runtime | tokio 1.x |
| HTTP API | axum 0.8 |
| Serialization | serde + serde_json + serde_yml |
| State | sled 0.34 |
| HTTP Client | reqwest (rustls) |
| Unix Sockets | hyperlocal + hyper |
| CLI | clap 4 (derive) |
| Error Handling | thiserror |
| IDs | uuid v4 |