Skip to content

The mf CLI

mf is the command-line client for the managed.dev API. Every command is a thin shell over a /v1 endpoint — it’s built on the Go SDK, which is generated from the same OpenAPI spec as the API itself, so the tool doesn’t drift from the platform. The CLI is free on every plan — it’s just a client; what it can do is bounded by your key’s scopes and your team role.

Install
go install terriblegit.com/terrible/mf/cmd/mf@latest

Each group inherits the required scope of the endpoints it calls. Async commands accept --wait (poll to completion) or --follow (stream the job); without either they print the job id and return. All of them exit non-zero on job failure.

Group Representative commands Endpoint(s) Scope
mf sites list, get, create, delete --confirm-domain, restart, php-version, config, redirects, tls, transfer, audit GET/POST /v1/sites, POST …/restart, POST …/php-version, … sites:read / sites:write / sites:admin
mf envs list, create --type staging|branch, delete, refresh, reset, push, suspend, resume, exec, cache-purge GET/POST …/environments, POST …/{envID}/{action}, POST …/exec, POST …/cache/purge environments:read/write; wp.cli:exec for exec; cache:write for cache-purge
mf deploy build --builder, deployments, artifacts, releases, create, promote --to, rollback GET/POST …/builds, …/deployments, POST …/promote, POST …/rollback deployments:read / deployments:write
mf backups status, create, snapshots, restore --yes GET /v1/backups/status, POST …/backup, POST …/snapshots/{id}/restore backups:read / backups:write
mf jobs list, get, watch (alias follow) GET /v1/jobs, GET /v1/jobs/{id}, GET /v1/jobs/{id}/stream jobs:read
mf events list [--type T] GET /v1/events events:read
mf webhooks list, create --url, update, delete, roll, deliveries, replay, event-types GET/POST /v1/webhook-endpoints, POST …/roll, …/deliveries webhooks:read / webhooks:write
mf teams list, create, plan, insights, members, invites, projects, audit /v1/teams, …/members, …/invites, …/projects teams:read / teams:write
mf projects list, create, rename, assign, remove /v1/projects, …/sites sites:read / sites:write
mf keys list, create --scopes, update, revoke, roll GET/POST /v1/api-keys, POST …/roll keys:read / keys:write (isolated — never in a wildcard)
mf access ssh-keys, credentials, reset-password --yes, magic-link …/ssh-keys, …/credentials, …/magic-link credentials:read / credentials:write (isolated)
mf insights summary, timeseries --metric, pages, logs, traces, requests …/insights/* per site observability:read
mf security summary, malware overview|scans|scan, vulns …/security/*, …/malware/* security:read/write; vulnerabilities:read for vulns
mf obs logs, log-volume, traces, metrics --name, usage GET /v1/logs, /v1/metrics, /v1/traces, /v1/usage/storage observability:read
mf functions list, create, build, deploy, rollback /v1/functions, POST …/build, …/deploy, …/rollback functions:read / functions:write
mf fn setup, dev — local, docker-based function dev none (runs locally)
mf listen --forward-to URL [--type T] polls GET /v1/events events:read
mf mcp stdio MCP server; --tools lists tools the read + safe-write subset inherits the key’s scopes
mf account get, update, audit GET/PATCH /v1/account, GET /v1/account/audit account:read/write; audit:read
mf ratelimits live bucket state GET /v1/rate-limits any authenticated key
mf runtimes / mf capabilities runtime catalog / one site’s entry GET /v1/runtimes, GET /v1/sites/{id}/capabilities sites:read

Run mf <group> --help for the full flag list, or mf help for the top-level command tree. Global flags everywhere: --json, --token, --base-url. Exit codes: 0 success, 1 runtime/API error, 2 usage error, 130 interrupted.

mf login verifies and stores an API key — there is no browser flow. Omit --token and it prompts with echo disabled. With --mint it uses the key you provide to mint a narrower one (via POST /v1/api-keys) and stores that instead:

Store a down-scoped key
mf login --mint --scopes sites:read,deployments:write,jobs:read --ttl 24h

For CI, skip login and set FORGE_TOKEN in the environment:

Non-interactive auth
export FORGE_TOKEN="mfk_live_…"
mf sites list

mf deploy build calls POST …/builds and gets back a 202 with a job. --follow streams the job to a terminal state and exits non-zero if it fails, so it drops cleanly into a pipeline step:

mf deploy build
~/acme-store ❯ mf deploy build –builder wordpress –ref feature/checkout –follow
job_01J9F2KQ8M3T  build.run  queued
job_01J9F2KQ8M3T  build.run  running
job_01J9F2KQ8M3T  build.run  succeeded
✓ build succeeded — artifact art_01J9F3XW, deployed to env_01J8C4RXhttps://acme-store-feature-checkout-9a3f.preview.managed.dev

Without --wait or --follow the command prints the job id and returns — resolve it later with mf jobs watch job_01J9F2KQ8M3T. Roll a bad release back with mf deploy rollback <deploymentID>.

mf envs reads its site from --site or the config’s default_site:

Create a branch environment
mf envs create --type branch --branch feature/checkout --wait
Remove it when the branch merges
mf envs delete env_01J8C4RX --wait

Both call the environments endpoints and return jobs. See environment lifecycle for what creation, refresh, and teardown do.

mf envs exec calls POST …/environments/{envID}/exec — the same surface as a WP-CLI shell, but driven by the API and gated by the wp.cli:exec scope. Output streams back as the job runs:

A dry-run search-replace before promoting
mf envs exec env_01J8C4RX -- \
wp search-replace 'staging.example.com' 'example.com' --dry-run

mf envs cache-purge calls POST …/cache/purge (cache:write) — everything, one URL, or a surrogate tag:

Purge one URL
mf envs cache-purge env_01J8C4RX --url https://acme-store.com/pricing

mf listen polls GET /v1/events and forwards each new event to a local URL — useful for developing a webhook handler without a public endpoint. It forwards only events that occur after it starts:

Forward deploy events to a local server
mf listen --type deploy.completed --forward-to http://localhost:4000/webhooks

Each event is posted as raw JSON with a Forge-Event-Type header. It is not a signed webhook delivery — your Forge-Signature verification path isn’t exercised; test that against a real endpoint with a delivery replay.

mf keys create mints a scoped key (keys:write — an isolated scope, never granted by a wildcard). Pin it to a single site with a resource constraint; the secret prints exactly once:

A deploy-bot key pinned to one site
mf keys create --name deploy-bot \
--scopes sites:read,deployments:write,jobs:read \
--resource-type site --resource-id site_01J7QZ3M \
--ttl 720h

mf access covers the credential-grade surface (credentials:read/write, also isolated): SSH keys, SFTP/DB credentials, admin-password reset, and one-time magic links into wp-admin:

One-time wp-admin SSO link
mf access magic-link --site site_01J7QZ3M

Secrets from keys and access commands are printed exactly once — pipe them straight into your secret store.