10. Hooks (hooks)
Hooks are Python or Bun scripts in workspace/jobs/<job>/_hooks/hook_<name>.py (or .ts). They run on the CLI host, not on workers — but each run is scoped to one allocation (worker IP + alloc id).
Events (when hooks run)
| Event | Trigger |
|---|---|
post_build |
End of maand build |
pre_deploy |
Before rsync for a job wave |
post_deploy |
After rollout for a job wave |
job_control |
Instead of default make start/restart/… |
health_check |
From maand health_check (after manifest probes) |
after_allocation_started |
After a batch start/restart |
after_allocation_stopped |
After stop during reconcile |
cli |
Manual: maand hooks <name> [job] |
Declare in manifest.json under commands:
{
"hooks": {
"hook_migrate": {
"executed_on": ["pre_deploy"],
"runtime": "python"
}
}
}
Environment in scripts
Each invocation receives:
| Variable | Meaning |
|---|---|
ALLOCATION_ID |
Stable UUID |
ALLOCATION_IP |
Worker to target via SSH helpers |
JOB |
Job name |
EVENT |
Current event |
CURRENT_VERSION / NEW_VERSION |
Rollout context |
Python example:
from maand import allocation_ip, run_ssh, put_job_secret
put_job_secret("token", "…").raise_for_status()
run_ssh(allocation_ip(), "systemctl is-active myapp").raise_for_status()
Runtime HTTP API
While build/deploy/health_check/hooks runs, maand serves localhost:8080:
- GET/PUT/DELETE KV (scoped namespaces)
- Encrypted secrets
acquire_semaphore/release_semaphorefor cross-allocation lockslist_hook_demands— who depends on this job
Embedded maand.py / maand.ts wrap the API.
Reference: hook-api.md.
Hooks vs Makefile vs run_command
| Runs on | Use for | |
|---|---|---|
| Makefile | Worker | Process start/stop, compose, systemd |
| Hook | CLI host | KV, secrets, migrations, custom rollout logic, SSH orchestration |
maand run_command |
Worker | Ad-hoc ops, debugging |
Rule of thumb: if it must mutate catalog/KV or coordinate multiple allocations, use a hook. If it only touches local process files on one host, use Makefile.
Batching
Hooks run in rollout order, max_concurrent_upgrades workers per batch (see hook-api.md). Tune the manifest field for wider or narrower parallel bursts.
maand hooks hook_migrate api --verbose
Use semaphores when only one allocation should run DDL at a time, even within a batch.
Single-batch runs (BATCH_INDEX=0, BATCH_COUNT=1): hook-one-shot.md.
Tutorial: hooks-tutorial.md
CLI: hooks.md.