---
name: monoceros-ship
description: 'Implement an approved plan file and review the result against it. Runs the implementer, gates on the acceptance command, then the reviewer, and repairs at most twice. Use when the user approves a plan written by /monoceros-plan, or names a plan to implement.'
argument-hint: '[<app>/<slug> | slug]'
---

<!-- Generated by `monoceros apply`. Edits here are overwritten on the
     next apply. To customise, copy this file into a project's
     `.claude/skills/monoceros-ship/SKILL.md`, which wins over the global
     one and is yours to keep. -->

Implement the plan named by: $ARGUMENTS

Plans on disk, as absolute paths under `{{PLANS_DIR}}/`:

!`find {{PLANS_DIR}} -name '*.md'`

The working directory is: !`pwd`

The app is the path segment right after `projects/` in that path. If the
path has no `projects/` segment, the working directory is not inside an app.

## 1. Resolve the plan

Match the argument against that list. `<app>/<slug>` is the unambiguous form;
a bare slug resolves against the working directory's app first, then against
the whole list. Exactly one match: use it. No match or several: show the list
and ask which one is meant, and touch nothing until they say.

No argument at all: show the plans for the working directory's app and ask.

Then read the plan's **Reply to the user in** field. Everything you say from
here on is in that language, from the first sentence, not English with a
translation after it. English when the field is missing.

## 2. Implement

Delegate to the `monoceros-implement` subagent. It starts with an empty
context, so name the plan, the acceptance command and the language every time:

    Implement the plan at {{PLANS_DIR}}/<app>/<slug>.md.
    Read the whole file first, including the out-of-scope and host-steps
    sections, then work the steps in order.
    Run <the acceptance command from the plan> and paste the tail of its real
    output.
    Reply in <the plan's language>.
    Report back. You do not delegate: the review is run from here.

**Gate on the deterministic check.** Before any review, the acceptance command
must have run green and the implementer must have shown you the real output.
If it failed, hand the failure back to the same subagent so it keeps its
context. Do not fix the code yourself and do not weaken the criteria to make it
pass.

## 3. Review

Then, the same way:

    Review the change against {{PLANS_DIR}}/<app>/<slug>.md.
    Establish the facts first: run the plan's acceptance command, read
    `git diff` and the untracked files from `git status` in full, and take the
    plan's steps and acceptance criteria out of it.
    Verdict on the very first line, evidence under it.
    Reply in <the plan's language>.

Use the `monoceros-review` subagent. It is read-only by design, so it reports
findings and never fixes them.

## 4. Repair, twice at most

On `CHANGES_REQUIRED`, hand the numbered items back to the **same** implement
subagent with `SendMessage`, addressed by the id it ran under. It keeps its
context that way, so you send the findings and not the plan again. A fresh
subagent would start from nothing and re-read everything to fix two lines.
Then gate on the acceptance command again, and review again.

Two repair rounds, and one earlier stop that matters more than the counter:
**if a finding survives a round, stop immediately.** Changing findings mean
progress; the same finding twice means the plan is wrong, and a third attempt
burns tokens to prove it.

When you stop without a PASS, say so as clearly as you would say PASS: what is
still open, what the reviewer said, and your read of why, which is usually the
plan itself.

## 5. Report

Whatever the outcome: the verdict, the acceptance output, what is running and
where to see it, the host steps the user still has to do, and the command to
carry on with. The user was away while this ran, and the report is all they
get.

Carry the implementer's **Host steps** section over verbatim. It is the part
that gets dropped, and dropping it is why a run once ended with green tests, a
working app, and nothing reachable in the browser.
