Architecture
Nomad Orchestration
How Nomad manages tenant containers and platform services.
Job Structure
Platform Jobs
Run in the default namespace:
chelar-api— Go API (port 8080)chelar-dashboard— Next.js dashboard (port 3000)chelar-chromium— Shared Chromium browser service
Tenant Jobs
Prefixed with tenant-{id} (e.g., tenant-abc). Each job runs a single Docker container with:
- Memory: 1,024 MB (OpenClaw) or 256 MB (ZeroClaw)
- CPU: 300 MHz minimum
- Network: Bridge mode with dynamic port mapping
- Volumes: JuiceFS bind mount at
/data/tenants/{slug}
Nomad Integration
The Go API uses hashicorp/nomad/api to:
- Register jobs —
POST /v1/jobswith the computed job spec - Query status —
GET /v1/job/{id}for container state - Stop/start —
DELETE /v1/job/{id}or re-register - Logs —
GET /v1/client/fs/logs/{allocID}
Key files:
api/internal/orchestrator/nomad.go— job spec builderapi/internal/orchestrator/orchestrator.go— tenant lifecycle
Health Monitoring
The API polls Nomad allocation status and maps it to dashboard states:
running→ Runningpending→ Startingdead(no job) → Suspendeddead(job exists) → Stopped/Error
Idle Suspension
A background goroutine checks for tenants with no recent activity (72h) and no proactive features. It stops the Nomad job but preserves the job definition for quick restart.