compose-service-installer
Adds to docker-compose.yml every service the spec marks materialize, by running docker-architect.
compose-service-installer.md, section by section
The sections of the agent's own file, excerpted. Hover or click one to see which project rules and templates it cites. The sections are also chips: click one to jump to it.
## Why this is an agent (Form 3)
Preserves context, and keeps a model pin from leaking. /new-feature-implement must materialize the service its spec decided at design time, and its own thread cannot do it: ArchHook.java guard refuses a build-class Skill call while its orchestrator phase is open, and skips the call when a classed agent makes it (decision 0126). Running docker-architect here also keeps the skill's body out of the implement thread, and keeps its opus pin out of the turns that follow (decision 0080). The closest rejected form was giving the compose files to java-spring-boot-developer, which would have carried the skill's body into an executor group and widened the executor's territory to infrastructure (@.claude/decisions/0137-pending-compose-service-decided-at-design-materialized-at-implement.md).
## Procedure
- Check the input. Read the spec's
## Infrastructure. Nomaterializerow → return
- Drop what already exists. List the keys of the compose file's
services:block with the
- Invoke
docker-architectthrough theSkilltool, with the use case folder as the
- Check the result. Run
java .claude/hooks/ArchHook.java composeand keep the lines it
---
## Failure mode
No base pair: `` ❌ compose-service-installer stopped — docker-compose.yml (or Dockerfile) missing The base pair is project-bootstrap's. Nothing added; every materialize row stays pending. ``
docker-architect stopped, or compose reports a service red: `` ⚠️ compose-service-installer — <service>: <first line of the failure> Run /docker-architect docs/use-cases/UC-NNN-<slug>/ to finish it. ``
No rollback. The implement run reports each row as it left it, and still prints the /git-publish line: the code is green whether or not the container exists.
---
## Summary format returned to the caller
✅ compose-service-installer complete — UC-NNN-<slug>
- kafka (apache/kafka:<tag>) · added · compose: up, healthy
- postgres (postgres:<tag>) · already present
- Files: docker-compose.yml, .env.example
One line per materialize row, each with one of added, already present or failed: <reason>, and the files written. On failure, the same shape with ❌ or ⚠️ and the one line that matters.
---
## References
@.claude/decisions/0137-pending-compose-service-decided-at-design-materialized-at-implement.md@.claude/decisions/0126-guard-call-judges-classed-agent-skill-calls-by-agent-class.md—@.claude/skills/docker-architect/SKILL.md— the procedure this agent runs, and its single@.claude/agents/commons-logging-installer.md— the other installer
What it reads, writes and refuses
The skill's own contract, from SKILL.md, in the original wording.
Class
installer — the territory is agent_classes.installer.overrides.compose-service-installer in @.claude/schemas/extensions.json: the same paths skill_classes.build gives docker-architect (the compose files, docker/**, the Dockerfile, .env, .env.example, .gitignore, .dockerignore). ArchHook.java guard reads this agent's agent_type on every write, including the writes docker-architect makes while it runs here, and refuses a path outside the list with exit 2.
Executor
yes — writes while /new-feature-implement's phase is open. The class grants it (executor: true), and ArchHook.java schema cross-checks this marker against that flag in both directions.
Pattern catalog
not injected — writes no Java (agent_classes.installer.pattern_catalog: false; schema cross-checks this line).
Input (required)
the path of the use case folder, docs/use-cases/UC-NNN-<slug>/, and the materialize rows of its spec's ## Infrastructure, both sent by the caller.
Reads
UC-NNN-spec.md § Infrastructure, docker-compose.yml, and what docker-architect reads for that folder.
Writes
nothing of its own. Every write is docker-architect's, made inside this agent and judged by this agent's territory.
Invokes
docker-architect through the Skill tool, once, with the use case folder. It never writes a service block itself: that skill is the single owner of every service block (decision 0029).
Does not
create docker-compose.yml or the Dockerfile when they are missing — that base pair is project-bootstrap's, written once at generation. Does not touch a row whose decision is exists, external or pending, edit the spec, run git, or ask anything: a background agent has no AskUserQuestion (decision 0123), and docker-architect asks nothing when it is given a use case folder.
Returns
one structured summary (shape below), not the skill's output.
Source: the agent's § Contract, at nerviz e4cae27.
What the guard does with it
installer is the agent's class. ArchHook reads its agent_type on every write and judges the path against the list on the left; the skill it invokes gets no territory of its own. The text on the right is the hook's own.
write_allow of class compose-service-installer
- ✓
docker-compose*.yml - ✓
docker/** - ✓
Dockerfile - ✓
.env - ✓
.env.example - ✓
.gitignore - ✓
.dockerignore any path outside this list: refused, exit 2
A refusal exits with code 2 and the message goes back to the model.
PreToolUse Agent(compose-service-installer) audit call exit 0 guard call exit 0 SubagentStart context subagent exit 0 tests agent-start exit 0 # installer · opus · write_allow: docker-compose*.yml, docker/**, Dockerfile, .env, .env.example, .gitignore, .dockerignore
SubagentStop audit agent exit 0 tests agent-end exit 0 Stop audit flush Recording the execution trail... exit 0 schema Validating frontmatter... exit 0 guard sweep Sweeping what this turn wrote... exit 0 compose gate Checking compose services... exit 0 tests Running the verify gate on changed modules... exit 0
Where it sits on the rail
Each card is a step of /new-feature-implement. The executor runs three times, one block group each; between two groups the orchestrator carries the reports forward. Dashed steps run only when the spec needs them.
/new-feature-implement orchestrator · sonnet