Drivers
Mentat usa cinco drivers de runtime en un modelo zero trust. Cada workload corre en el nivel de aislamiento que se ajusta a su perfil de riesgo. Ningun driver sirve para todo — la plataforma elige el correcto.
Cuando Usar Cada Driver
| Firecracker | Kernel dedicado por servicio (KVM). Para clusters Raft, unikernels Rust y workloads de alta seguridad. ~8ms boot, ~256MB |
| Sandbox | Aislamiento con namespaces Linux (PID + mount + UTS + IPC) con cgroups v2. Para Next.js, Node.js, web apps. Sin daemon Docker. ~2MB overhead |
| Docker | Contenedores OCI para servicios existentes. Mars Mode auto-adopta contenedores en ejecucion al reiniciar |
| Exec | Binarios directos para agentes internos de confianza. Sin aislamiento — acceso a nivel host |
| Hull | Runtime de contenedores daemonless propio. Binario Zig de ~3 MB, aislamiento de 7 capas (ns + cgroups + seccomp + landlock + pivot_root), bridge veth opcional. Corre workloads BEAM / .NET / Node |
FirecrackerDriver
Usa Firecracker cuando el aislamiento importa mas. Cada workload recibe su propia frontera de kernel y un entorno de ejecucion dedicado, lo que calza mejor para servicios sensibles, plataformas internas y workloads tipo serverless privado.
Uso tipico: StreamForge y OxideStore.
Que Hace el Agent
- Prepara un root filesystem con el binario del servicio
- Configura networking tap y recursos de VM
- Inicia Firecracker y adjunta volumenes
- Levanta el workload y espera health
Ejemplo: StreamForge (args CLI)
StreamForge recibe argumentos de runtime directamente a traves de la definicion del servicio.
name: streamforge
driver: firecracker
count: 3
config:
memory_mb: 256
vcpus: 2
args:
- "--wal"
- "--data-dir"
- "/data/streamforge"
- "--raft-port"
- "8081"
- "--http-port"
- "8080"
volumes:
- source: /mnt/unikernel-volumes/streamforge
target: /dataEjemplo: OxideStore (env vars)
OxideStore lee configuracion desde variables de entorno y volumenes persistentes.
name: oxidestore
driver: firecracker
count: 1
config:
memory_mb: 256
vcpus: 2
env:
OXIDESTORE_DATA_DIR: "/data/oxidestore"
OXIDESTORE_BIND: "0.0.0.0:9000"
OXIDESTORE_REGION: "us-east-1"
volumes:
- source: /mnt/unikernel-volumes/oxidestore
target: /dataFlujo de Boot
1. mt run service.yaml
2. Server agenda la asignacion
3. Agent prepara los assets del runtime
4. Firecracker recibe config de maquina, boot source y volumenes
5. El workload inicia y reporta healthyDockerDriver
Usa Docker cuando el servicio ya existe como contenedor y la prioridad es consistencia operativa, no conversion de runtime. Es la ruta de migracion para servicios .NET, Node.js existentes y servicios de terceros.
Uso tipico: API Jarvis y otros servicios ya containerizados.
config:
driver: docker
image: "registry.example/api-service:latest"
env:
- - ASPNETCORE_ENVIRONMENT
- Production
ports:
- "8080:80"
volumes:
- source: /data/api-service
target: /app/data
read_only: trueExecDriver
Usa exec para procesos a nivel host que deben iniciar rapido y correr sin overhead de contenedor o VM. Es util para agentes de plataforma, recolectores y utilidades operativas.
Uso tipico: Node Agent
config:
driver: exec
command: /opt/bin/node-agent
args:
- "--port"
- "9090"
- "--workers"
- "4"
env:
- - RUST_LOG
- infoHullDriver
Usa Hull cuando quieras semantica de contenedor tipo Docker sin un daemon, sin registry, y sin arbol de capas OCI. Hull es un solo binario Zig static-musl de ~3 MB que inicia el workload dentro de un bundle fresco de namespaces Linux, aplica limites cgroups v2, instala una allowlist seccomp-bpf por perfil de workload, cierra el filesystem via Landlock y hace pivot_root al rootfs del contenedor — todo en una sola llamada.
Uso tipico: Titan ESB (Elixir/Phoenix/BEAM), servicios .NET AOT, servicios Node.js que no encajan en el modelo de sandbox base.
Capas de aislamiento (afuera → adentro)
- cgroups v2 — limites duros de CPU / memoria / pids
- Namespaces PID + NET + MNT + UTS + IPC (+ USER opcional en modo
--rootless) mount --make-rprivate+/procnuevo dentro del mount namespace- Allowlist seccomp-bpf (
KILL_PROCESSen violacion, curada por perfil de workload) - Allowlist de filesystem Landlock LSM (fallback gracioso en kernels < 5.13)
pivot_roota un rootfs dedicado (extraido y cacheado en/var/lib/hull/rootfs/<name>)
Networking via bridge
Pon network: bridge en el manifest y Hull crea un par veth, conecta un extremo al bridge hull0(10.88.0.0/24 por defecto), asigna la siguiente IP libre via lockfiles atomicos O_EXCL, y configura el lado del contenedor desde el host via nsenter. Las reglas masquerade de nftables yiptables -I FORWARD 1 -i hull0 -j ACCEPT se instalan idempotentemente, asi los contenedores alcanzan internet a traves de la ruta default del host.
Modo rootless
Pasa --rootless y Hull ejecuta el dance de NEWUSER incluso siendo invocado como root: el parent forkea un child userns_setup, escribe/proc/<pid>/{setgroups,gid_map,uid_map}, y el workload se ve como uid 0 dentro de un user namespace completamente nuevo. Defense in depth — no hay credenciales root a las que el workload pueda escapar.
name: titan
replicas: 1
config:
driver: hull
manifest: /etc/hull/titan.json
binary: /usr/local/bin/hull-sudo
port: 4500
resources:
cpu_mhz: 2000
memory_mb: 1024
disk_mb: 256
port: 4500
ingress:
host: www.titan-bus.com
aliases:
- titan.getmentat.run
path: /
tls: true
security:
profile: hull{
"name": "titan",
"rootfs": "/var/lib/hull/rootfs/titan",
"argv": ["/opt/titan/bin/titan", "start"],
"env": ["PHX_SERVER=true", "PORT=4500", "PHX_HOST=www.titan-bus.com"],
"profile": "beam",
"network": "bridge",
"bridge": { "subnet": "10.88.0.0/24" },
"hostname": "titan",
"cwd": "/opt/titan",
"limits": { "memory_mb": 1024, "cpu": 2.0, "pids": 4096 }
}Inspeccionar un contenedor vivo
hull inspect <name> lee~/.hull/state/<name>.json, luego imprime los numeros del cgroup en vivo, los 7 inums de namespace (viareadlink /proc/<pid>/ns/*) y los primeros 12 mount points de mountinfo. Sin daemon al que consultar —ps, stop, kill, logse inspect van todos por el mismo directorio de estado.
Volumenes Persistentes
Todos los drivers soportan almacenamiento persistente. Firecracker usa volumenes de bloque adjuntos. Docker mapea paths del host como bind mounts. Asi el mismo modelo de plataforma puede soportar servicios con datos pesados y workloads livianos stateless juntos.
volumes:
- source: /mnt/unikernel-volumes/vector-store
target: /data
read_only: false