Job kinds
Almost everything the dashboard does to a server is a job: a named, whitelisted action the control plane dispatches to that server’s agent over the WebSocket link. This page is the map of the job-kind domains — what each family does, and where you drive it in the panel. It’s a reference, not a task page; for the invocation contract see The mz CLI.
Jobs are created with POST /v1/servers/:id/jobs, polled with GET /v1/jobs/:id,
and streamed live with GET /v1/jobs/:id/stream (Server-Sent Events). The endpoint
is the single funnel every server action flows through.
How a job flows
Section titled “How a job flows”A job kind is a string like site.create or cron.run — a <domain>.<action>
pair. When you click something in a server or site section, the panel:
- Validates your input against a per-kind schema (domain format, profile slug, port range, …). The API never accepts a raw command — you pick a kind from a fixed whitelist and the server builds the arguments.
- Builds the
mzarguments for that kind (site.create→site create <domain> --profile … --json). This mapping is fixed in code. - Checks your plan and role — the job’s domain decides which capability group and license tier it needs (see below).
- Dispatches the arguments to the agent over the WebSocket link. The agent runs
them in its native Go engine — shelling out only to public tools (nginx,
docker, wp-cli, certbot, systemctl…), never to
mzitself. - Streams stdout/stderr back as it runs, ending with an exit code. Read commands
return JSON; long-running ones (deploys, updates,
cron run) emit log lines.
The control plane stores the job row and its captured log lines (for the status +
stream endpoints); the actual state lives on the box (nginx vhosts, /etc/cron.d,
databases, containers). MZPanel doesn’t mirror server state — it reads and writes it
through jobs.
The domain map
Section titled “The domain map”Every job kind belongs to a domain. Each domain maps to the same-named mz command
family and, usually, to one section of the dashboard.
| Domain | What it does | Where in the panel |
|---|---|---|
site | Create, clone, delete, inspect, enable/disable, logs, env, per-site limits | Server Sites, per-site shell |
app | Single-container Docker apps — create, build, releases, rollback, previews, env | Server Apps |
stack | Docker Compose stacks — deploy, up/down, adopt, git-build, previews | Server Apps (stacks) |
deploy | Git-deploy pipelines — init, run, rollback, PR previews | Per-site Deploy |
db | MariaDB databases + users, dumps, tuning, phpMyAdmin magic links | Server Databases |
pg | PostgreSQL databases, tables, VACUUM, remote allowlist, pgvector | Server Databases (Postgres) |
mongo | MongoDB databases, collections, compact, mongo-express | Server Databases (MongoDB) |
php | PHP versions, extensions, php.ini/FPM config, restart, optimize | Server PHP |
ssl | Issue, renew, delete certificates; HTTPS redirect; auto-renew | Server SSL, per-site SSL |
dns | dig lookups + authoritative BIND9 zones/records on the box | Server DNS & TLS |
mail | Mail server install, domains, mailboxes, aliases, queue, webmail | Server Mail |
docker | Container lifecycle (start/stop/logs/exec/stats), engine df/prune | Server Docker |
container, image, volume, network | Docker resource prune/create/remove/pull/scan | Server Docker (Resources) |
cron | Managed cron jobs — add, run, pause, edit, logs; WP-cron dispatcher | Server Cron jobs |
daemon | Supervisor-managed long-running processes | Server Services (daemons) |
service | System service control (start/stop/restart/enable) + logs | Server Services |
security, waf | UFW firewall, Fail2ban, SSH policy, ClamAV scans, WP integrity, ModSecurity WAF | Server Security, per-site Security |
user | System users + SSH key management, lock, sudo, key audit | Server Users |
wp, cache | WordPress content, updates, tools, cache (page/object), optimize, SEO | Per-site WP sections |
ai, litellm, rag, mcp | AI-on-VPS — model pull, LiteLLM keys/usage, RAG, MCP servers | Server AI |
system | Timezone, hostname, reboot, clear caches, Livepatch | Server Settings |
updates | OS package updates — list, apply, history, unattended | Server Updates |
storage | Disk usage, du drill-down, safe cleanups | Server Storage |
quota, plan, tuning | Disk-quota reporting, resource-plan packages, stack retuning | Server settings / plans |
extension | Optional server add-ons (apt/repo/docker) — install/remove/update | Server Extensions |
lb | Load-balancer desired-state apply/remove on the node | Fleet Load balancers |
migrate | Migrate-in — scan, import, cross-server pull/receive | Server Migrate |
logs, metrics | Log tailing + metric snapshots (read-only) | Terminal / Monitoring |
One job kind = one mz command
Section titled “One job kind = one mz command”Every job kind maps 1:1 to an mz command with identical arguments — the panel
and the CLI share one dispatch. site.create builds exactly mz site create <domain> --profile <slug> --json; cron.run builds mz cron run <id>. There is no separate
CLI implementation and no “CLI feature gap”: a new job kind is an mz command the
moment it ships.
That equivalence is why the CLI and the dashboard can’t drift, and why an on-box AI (ClaudeCode / MCP) can drive the box with the same verbs the panel uses. See The mz CLI for how to invoke them and For AI agents for the machine-readable entry points.
Reads, mutations, and gating
Section titled “Reads, mutations, and gating”- Read kinds (
site.list,db.status,ssl.list,metrics.get, …) collapse to theobservecapability — any team member who can see the server can run them. - Mutations map to a capability group by domain: content (
site,wp), infra (php,ssl,db,dns,docker,app,stack, …), or sysadmin (service,security,user,system,updates,storage,backup,migrate). Your role must hold that group. - Some kinds require a plan. Resource limits and plans, RAG/MCP AI, and several
extensions are Pro+; LiteLLM keys are Plus+. Over-tier jobs are refused at the API
with a
tier_requirederror before anything reaches the box. See Plans & quotas. - Secrets are masked. Registry passwords, git tokens and Ubuntu Pro tokens are stripped from the persisted payload and the audit log.
Gotchas & troubleshooting
Section titled “Gotchas & troubleshooting”- Backups use a separate dispatch path.
backup.*kinds (including Backup v2:backup.v2-run,backup.v2-list,backup.v2-restore, …) are not created through this generic/jobsendpoint — they’re driven by the dedicated backup routes so they can carry sealed destination credentials. They still run as jobs on the same agent; you just kick them off from Backups, not the raw jobs API. - The whitelist is the security boundary. The API refuses any kind or argument shape not in its schema — you cannot pass a free-form command. If a new action isn’t wired as a kind yet, it simply can’t be dispatched from the panel.
- A missing native handler returns exit 127. The agent is native-only; if a kind
has no Go handler on that agent version, the job fails with
127rather than silently falling back. Updating the agent usually fixes it. - Jobs need the agent online. Dispatch requires a live WebSocket link. When a server is offline, mutation jobs can’t run and read views fall back to the last cached values.
- Cross-org jobs 404, not 403. Requesting a job in another org returns not found so the panel never leaks that the job exists.
Related
Section titled “Related”- The mz CLI — the invocation contract for the same commands.
- mz command catalog — every command, by domain.
- For AI agents — machine-readable entry points.
- Architecture — how the agent and control plane connect.