The formal protocol AI agents follow to add a new service to PMA. Lives at
.claude/commands/install-service.md— a slash command that Claude (or any agent supporting Claude Code's command spec) can invoke. Phase-based, with regression requirements at every step.
User entry: type /install-service <svc> in Claude Code. Then it's the
agent's job to follow the protocol; the operator approves at gates.
A runbook is a list of steps a human reads + executes. A skill is a
state-tracked protocol an agent executes. Differences:
| Runbook | Skill |
|---|---|
| Human reads + interprets each step | Agent reads + executes |
| Errors → human re-reads + adapts | Errors → state file captures + agent retries or escalates |
| Output: "I did X" | Output: state-tracked artefacts (skill-state.json, ticket, PR, manifest, recovery playbook) |
| Quality varies per operator | Quality is enforced by protocol regression checks |
Install Skill is purpose-built for "an agent (Claude / GPT) should be able
to add a new service to PMA with minimal operator intervention". Every
phase has explicit success criteria + state-tracked checkpoints.
| Phase | Output |
|---|---|
| 0. Setup | Ticket filed (Golden Rule 1), feature branch, skill-state.json initialised |
| 1. Discovery | Service image found + verified, port chosen, dependencies enumerated, manifest field choices made |
| 2. Package scaffold | packages/<svc>/ with all required files; just compose-generate; just contract-validate passes |
| 3. SSO + config | tpl.env populated; bootstrap installs cleanly in test env; SSO wired |
| 4. Verify + commit | Health probes pass; E2E test runs; recovery playbook added if any quirk discovered; PR opened with template-compliant body |
Throughout the skill, state lives at
.asd/workspace/skill-state/install-service.json:
{
"skill": "install-service",
"service": "vaultwarden",
"ticket": "#3950",
"branch": "feat/3950-install-vaultwarden",
"phases": {
"0-setup": "complete",
"1-discovery": "complete",
"2-package-scaffold": "in_progress",
"3-sso-config": "pending",
"4-verify-commit": "pending"
},
"artefacts": {
"manifest": "packages/vaultwarden/manifest.yaml",
"compose": "packages/vaultwarden/docker-compose.yaml",
"net_manifest": "packages/vaultwarden/net.manifest.yaml",
"tpl_env": "packages/vaultwarden/tpl.env",
"install_just": "packages/vaultwarden/install.just"
},
"checks": {
"image_exists": true,
"port_chosen": 8222,
"sso_type": "oidc",
"compose_generates": true,
"contract_validates": true
}
}
The agent updates this after every meaningful action. If the agent
hands off to a human (or vice versa), the state file is the handoff
artefact.
Managed via bun scripts/helpers/skill-state.ts.
Each phase has explicit exit criteria the agent must satisfy:
just ticket create)feat/<ticket>-...)skill-state.json shows phase 0 completedocker manifest inspect <image>:<tag>)sso.type choice justified (oauth/oidc/saml/proxy/custom)just compose-generate regenerates without errorsjust contract-validate passestpl.env is complete; bootstrap-env populates .env without leftover placeholdersjust sso-check <svc> returns ✓If any exit criterion fails, the phase doesn't advance — agent fixes the
gap, retries the check, then advances.
Some phases pause for operator approval before continuing:
sso.type. The agent's discovery may have a wrongPhases 2-3 are agent-only (state-tracked, but no operator gate).
install-service is one of several skills in .claude/commands/. Others:
| Skill | Purpose |
|---|---|
install-service |
Add a new service |
add-sso |
Wire SSO for an already-installed service that has sso.configured: false |
add-e2e-test |
Add Playwright E2E test for a service |
add-mcp-tool |
Add a new MCP server tool |
migrate-data |
Migrate data from a SaaS to a PMA service |
Each follows the same phase + state-tracked + regression-required pattern.
Pre-skill workflow: an operator wanting to add a service Googled
"how to add to PMA", read CLAUDE.md, fumbled with the manifest schema,
ran into 3 cycles of "oh I forgot X". 4-8 hours of work.
With Install Skill: operator (or AI agent) runs /install-service vaultwarden. Agent walks the protocol, asks for input at gates. 60-90
minutes for a new service, with quality enforced by protocol checks.
The skill is the formal contract for "this is how a service gets added";
the existence of the skill is what makes "agents can add services" credible.
/pma/cookbook/install-a-new-service — the operator-facing recipe (what the skill ends up doing)./pma/internals/package-system — what gets produced..claude/commands/install-service.md in the repo — the actual skill definition.scripts/helpers/skill-state.ts — the state-tracking helper.