Configuration reference
Maand reads configuration from the bucket root and workspace/. Edit these files, then run maand build (and usually maand deploy) for changes to take effect.
Run commands from the bucket directory (the directory created by maand init).
Related: build.md · concepts.md · commands.md
Prerequisites (CLI host and workers)
| Where | Required tools |
|---|---|
| CLI host | maand (built with CGO_ENABLED=1), bash, ssh, rsync, python3; bun when any hook uses .ts/.js |
| Workers | python3, make, rsync, bash, timeout; sudo when use_sudo = true |
SSH: private key in secrets/<ssh_key> authorized for ssh_user on every worker. See quickstart.
maand.conf (bucket root)
SSH, certificate, and job-config selector settings. Created on first maand init; not overwritten on later inits.
ssh_user = "agent"
ssh_key = "worker.key"
ssh_port = 22
use_sudo = true
certs_ttl = 60
certs_renewal_buffer = 10
job_config_selector = ""
log_format = "kv"
| Field | Default | Purpose |
|---|---|---|
ssh_user |
agent |
Remote user for deploy, job control, and run_command |
ssh_key |
worker.key |
Private key file under secrets/ |
ssh_port |
22 |
SSH port for worker connections and worker health checks |
use_sudo |
true |
Prefix remote rsync and some commands with sudo |
certs_ttl |
60 |
Days until generated leaf certificates expire |
certs_renewal_buffer |
0 if omitted |
Leaf: regenerate when within this many days of NotAfter (0 = only after expiry). CA: same window for expiring status in maand cat certs and stderr warning on maand build — CA is never auto-renewed; an expired CA fails build |
job_config_selector |
"" |
Suffix for bucket.jobs.<selector>.conf (see below) |
log_format |
kv |
Bucket log encoding: kv, json, or jsonl (JSON lines) |
Full TLS guide: certs.md.
Path on disk: <bucket>/maand.conf. Worker key path used at runtime: secrets/<ssh_key>.
workspace/bucket.conf
Bucket-wide settings (TOML). Created on maand init with a default port pool:
port_range = "30000,39999"
my_setting = "value"
| Key | Purpose |
|---|---|
port_range |
Inclusive "min,max" pool for maand-assigned ({}) job ports only; fixed manifest ports are not limited to this range. When omitted or empty, build uses 30000,39999. |
| Other keys | Copied to KV namespace vars/bucket at build (including port_range when set or defaulted) |
Job manifests declare ports as {} (assign from pool) or a fixed integer (any port number). See build.md.
Job memory and CPU: manifest bounds vs bucket overrides
Memory and CPU are configured in two places; maand.conf picks which override file applies to the current environment.
| Layer | File | Role |
|---|---|---|
| Bounds | workspace/jobs/<job>/manifest.json → resources.memory / resources.cpu |
Min and max the job is allowed to use (checked into git with the job) |
| Reservation | workspace/bucket.jobs.conf or workspace/bucket.jobs.<selector>.conf |
Actual memory/CPU for this bucket/environment — must be within manifest min/max |
| Environment pick | maand.conf → job_config_selector |
Chooses which bucket.jobs*.conf file build reads |
Example manifest bounds:
"resources": {
"memory": { "min": "256 mb", "max": "2 gb" },
"cpu": { "min": "500 mhz", "max": "2000 mhz" }
}
Example reservation for job api in the current environment:
[api]
memory = "512 mb"
cpu = "1500 mhz"
Build stores the reservation as current_memory_mb / current_cpu_mhz and validates:
manifest min ≤ bucket.jobs value ≤ manifest max
Worker capacity in workers.json must cover the sum of reservations on each host.
workspace/bucket.jobs.conf (optional)
Per-job TOML sections. memory and cpu set the reservation for that job; other keys are copied to KV only.
[api]
memory = "512 mb"
cpu = "1500 mhz"
my_setting = "staging-only"
Environment selector (job_config_selector)
Set job_config_selector in maand.conf to switch environments without editing job manifests. Build loads one override file:
job_config_selector in maand.conf |
Override file read |
|---|---|
"" (default) |
workspace/bucket.jobs.conf |
"prod" |
workspace/bucket.jobs.prod.conf |
"staging" |
workspace/bucket.jobs.staging.conf |
Pattern: bucket.jobs.<selector>.conf where <selector> matches job_config_selector.
Example layout:
workspace/
├── bucket.jobs.conf # default / dev reservations
├── bucket.jobs.staging.conf # used when job_config_selector = "staging"
└── bucket.jobs.prod.conf # used when job_config_selector = "prod"
Change job_config_selector, then maand build. Manifest min/max stay the same; only the active reservation file changes.
Overrides are written to vars/bucket/job/<job> at build. Only memory and cpu affect reservations and worker validation.
Full guide (validation, placement labels, examples): resources-and-placement.md.
workspace/jobs/<job>/vars.conf (optional)
Stable job-scoped variables synced into vars/bucket/job/<job> at build (merged with bucket.jobs*.conf; stale keys removed). See KV namespaces.
workspace/disabled.json (optional)
Drain or pause workloads without removing workspace files. Always follow edits with maand build.
Full guide: disable and drain.
workspace/workers.json
Worker catalog — hosts, labels, capacity, tags. See concepts.md and build.md.
To fill memory and cpu from live hosts, run maand collect facts --generate-workers > workspace/workers.json, then maand build — see collect.md.
workspace/jobs/<job>/manifest.json
Job definition — selectors, resources, commands, certs, health. Canonical reference: manifest.md.
Upgrading configuration after a maand binary upgrade
After installing a newer maand binary, run maand init before any other command. The CLI checks schema version on every command (except init) and refuses to run when the database is behind the binary.
maand init # schema migrations; keeps bucket_id and CA
maand build
maand deploy
If you skip init, commands such as build or deploy print an error like database schema upgrade required … run maand init to upgrade.
See day-2 operations.