compose-service-installer
运行 docker-architect,把 spec 标为 materialize 的每个服务加进 docker-compose.yml。
compose-service-installer.md,逐节说明
agent 自己文件的各节,为节选。把鼠标移到某一节上或点击它,可以看到它引用了哪些项目规则和模板。各节也是标签:点击即可跳转。
## 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
它读什么、写什么、拒绝什么
skill 自己的契约,取自 SKILL.md,保留原文。
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.
来源:agent 的 § Contract(nerviz e4cae27)。
guard 如何处理它
installer 是这个 agent 的类。ArchHook 在每次写入时读取它的 agent_type,并按左侧的列表判断路径;它调用的 skill 没有自己的领地。右侧文字是 hook 自己的输出。
compose-service-installer 类的 write_allow
- ✓
docker-compose*.yml - ✓
docker/** - ✓
Dockerfile - ✓
.env - ✓
.env.example - ✓
.gitignore - ✓
.dockerignore 列表之外的任何路径:拒绝,退出码 2
拒绝以退出码 2 结束,消息回到模型。
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
它在轨道上的位置
每张卡片是 /new-feature-implement 的一步。执行器运行三次,每次一组块;两组之间由编排器带着上一组的报告继续。虚线的步骤仅在 spec 需要时运行。
/new-feature-implement orchestrator · sonnet