Purpose: define expected CLI behavior for mpd operations.
Out of scope:
- lifecycle UX details (
--setup/--start/--stop) beyond routing notes - deep architecture internals outside this behavioral contract (see
ARCHITECTURE.md)
CLI behavior assumes fixed paths:
/opt/mpd/for the code checkout, assets, and built binary/var/lib/mpd/for state/cache and configuration:conf/— CA + service cert,platform.env, WireGuard private key (PRIVATE)env/mpd-vm.env— user-editable VM-wide env overrides (mounted into runtimes)state/— operational state: projects.json, runtimes/, dnsmasq.d/, etc.
Project backups live inside the data volume at /srv/backups/, accessed
from the laptop via fileaccess SSH/scp; see
ARCHITECTURE.md §10.
This document is a behavioral contract for AI assistants and contributors implementing CLI changes.
If implementation and docs diverge, align code to this contract or update this file in the same change.
From mpd/mpd/main.swift:
- Bare
mpd(no args) launches TUI. - If first token is positional (does not start with
-), route to project command path:mpd <project> <verb> [args...]
- Otherwise, route to global flag command path.
Hard preconditions enforced before command execution:
- non-root execution only
- executable location check against expected build path
Global command dispatch is first-match, single-action per invocation.
Operational flags include:
--status— context-aware status (text)--setup— idempotent first-run/reset; takes no argument (see below).--start/--stop— daily on/off; act on the active host adopted by--setup.--startreconcilescurrenttowardrequested(see "Resource lifecycle model" indocs/HOOKS.md);--stopfiresEventMpdPreStophooks for graceful DB shutdown, then powers off.--restart— graceful stop + restart. On mpd VM, runssudo systemctl rebootand lets the user-systemdmpd.serviceunit drive the chain (ExecStop=mpd --stopon shutdown, ExecStart=mpd --starton boot). User runsmpd --startafterward to restore projects.--check-hooks— cross-referenceassets/.../hooks/<event>.d/directories against the SwiftEventcatalogue and print warnings for orphans, removed audiences, and revision bumps. Also runs at the end ofmpd --setup.- runtime mutators:
--runtime-create,--runtime-start,--runtime-stop,--runtime-delete,--runtime - db mutators:
--db-create,--db-start,--db-stop,--db-delete
Listing is a verb, not a flag — mpd list [projects|runtimes|services|dbs]
(default projects). Read-only entity queries; services are always-on
infra started by --start.
Operational preflight is not globally enforced before command dispatch. Setup/start/stop paths perform their own environment-specific checks where needed.
--setup is mode-aware and takes no argument. It adopts the existing
host environment rather than provisioning one:
mpd --setup validates the supported distro (Debian Trixie across every
platform), verifies systemd-resolved is active (a precondition the
platform bootstrap is responsible for), and proceeds. The
active-machine label is always pinned to mpd VM regardless of
the OS hostname (which may be mpd-<digits> for concurrent
cloud-init VMs or mpd-sandbox for the sandbox platform).
If no known global flag path matches, status output is shown.
Runtimes are first-class and may be managed before any project exists.
Normal runtime-first IDE workflow (PHPStorm/VS Code remote):
- create runtime (
--runtime-create=<name>) - prepare code directory inside runtime
- register/attach project from existing directory (project command path)
Note:
- IDEs may perform git clone for you over SSH into the selected runtime directory.
- mpd should then attach/register that existing directory as a project without requiring mpd-managed clone.
Project-first bootstrap workflow:
- create project from git repo + branch + name (+ optional runtime)
- default runtime is
phpwhen not specified - project type defaults to
moodlewhen--typeis not provided
Runtime-level global CLI (no project required):
mpd list runtimes--runtime-create=<name>--runtime-start=<name>--runtime-stop=<name>--runtime-delete=<name>--runtime=<name>-> show full runtime status details
Contract intent:
- runtime lifecycle must be usable independently from project lifecycle
- project create path must support both "create from git" and "attach existing directory" workflows
- runtime-level verbs (
assets/runtimes/<runtime>/verbs/*.json)
Scope clarification:
- no-project commands use global flags (
mpd --...) - project commands always start with a project name (
mpd <project> ...)
Project command routing contract:
mpd <project>-> show project infompd create <project> [--type=<type>] ...-> create flow (default type:moodle)mpd help <project>-> project/type/runtime verb help- other verbs -> dispatch via
Mpd.Project.dispatch(...)
For non-create project verbs, project must already exist.
Meaning:
- these verbs are project-scoped (they are not available at no-project/global level)
- they apply across project types unless a runtime/type explicitly overrides behavior
Project-focused universal verbs (recommended daily surface):
createis inert beyond clone+scaffold: accepts--type,--git-repo,--git-branch,--git-depth.--git-depth=<n>does a shallow clone (passed straight togit clone --depth=) — useful for big repos like Moodle. Caveat: shallow clones implicitly--single-branch, so cross-branch operations needgit fetch --unshallowfirst. Project-typeproject-create.shseeds/srv/projects/<project>/mpd.envfrom the type'smpd-template.env(existing mpd.env preserved). No DB is provisioned here; the project is registered with statusnotConfigured. Next step ismpd configure <project>.configuretakes any number of positionalKEY=VALUEpairs matching^MPD_[A-Z0-9_]+=.*$. Swift sanitises (reserved keys likeMPD_DBget strict validation; others get a generic safe-charset check), then writes the line into/srv/projects/<project>/mpd.env(empty value deletes the line). Then runs the project-typeconfigure.shwhich sources the four-layer mpd.env (runtime defaults → type defaults → user-level → project) and emitsdbTag/urlsinto/srv/meta/<project>/{effective.json,urls.json}. Swift readsdbTag, re-sanitises, and provisions the DB container if non-empty (visible image-pull progress viapodman pull, thenpodman run -d, then per-project DB creation). The full mpd.env model — file paths, sourcing order, sanitisation, reserved keys — is documented inARCHITECTURE.md§8 "Configuration model: mpd.env".startstopdelete
The verb set above is fixed and Swift-only. There is no host-side
asset-shipped-verb mechanism: project-type-specific operations
(cache-purge, cron, upgrade, install on Moodle; rebuild,
upgrade on Astro) live as project-type tools inside the runtime
container, on PATH after you SSH in. See the mdl-* / astro-*
tables in docs/USAGE.md for the full set, and
ARCHITECTURE.md §7 for the
verb-vs-tool contract.
PHP runtime configuration knobs (PHP version, Xdebug mode, Behat
toggles, Moodle-specific defaults) live with the project type that
needs them under assets/runtimes/php/project_types/<type>/. This
section is a placeholder for runtime-wide PHP knobs and will be filled
out as those stabilize.
- CLI is non-interactive by default except explicit interactive actions (TUI, shells, interactive verbs).
- Destructive operations require confirmation unless
--yesis present. - Error messages should be actionable and include next command when possible.
- Idempotent operations should return success when already in desired state.
Implementation policy for operational commands:
- Container actions via Podman are Swift-initiated (may escalate via
sudowhen required). - Infrastructure-altering actions may combine Swift orchestration with shell helpers.
- Runtime provisioning and in-runtime operational behavior should prefer shell scripts in
assets/.
This keeps control-plane orchestration in Swift while runtime specifics stay versionable and portable in assets.
Contributor targeting:
- light developers should prefer additive
assets/extensions (new runtime/project type/verbs/scripts), - service/networking/control-plane changes are Swift-level changes.
Both modes share these correctness priorities:
- project/runtime/db/service dispatch correctness
- state transitions and status/list consistency
- help/completion consistency for implemented flags/verbs