Install
$ agentstack add skill-jerry0022-dotclaude-ship ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Ship
Ship completed work via PR using the dotclaude-ship MCP server tools. Supports two modes: direct (branch → main) and intermediate (sub-branch → feature branch).
> CRITICAL — cwd is required on every MCP tool call. > The ship MCP server runs in the plugin directory, NOT the target repo. > Every ship_* tool call MUST include cwd set to the current working directory of this Claude session. > Omitting cwd will cause the tool to operate on the wrong repository.
Pre-Step A — Autonomous Lockout Detection
/ship is composed by unsupervised orchestrators (run-backlog ships every queued issue this way; future AFK runners may too). Those runs are in a Post-Confirmation Lockout — the user is AFK and no AskUserQuestion can ever be answered. A modal raised mid-pipeline would hang the entire night run on a single issue. Detect that state FIRST, before any other step:
node "$CLAUDE_PLUGIN_ROOT/scripts/autonomous-lockout.js" check
Parse the JSON. If active: true, set $SHIP_LOCKOUT=true for this whole run and persist it durably: write a .claude/.ship-lockout marker in the repo root (node -e "require('fs').mkdirSync('.claude',{recursive:true});require('fs').writeFileSync('.claude/.ship-lockout','1')"). $SHIP_LOCKOUT is consumed at ~5 later gates, across a >5-min CI wait during which the conversation may compact and drop the variable from memory. At every interactive gate, re-derive $SHIP_LOCKOUT=true when the marker file exists rather than trusting recall alone — a lost lockout that silently re-enables AskUserQuestion is exactly the AFK-hang this guard exists to prevent. Clear the marker in Step 5 cleanup (delete .claude/.ship-lockout). If the command errors or the script is absent (older plugin), treat it as not locked — a normal interactive ship — and continue. The guard only ever adds non-interactive safety; it never blocks a normal ship.
The rule when $SHIP_LOCKOUT is set: never call AskUserQuestion. Every gate that would normally ask takes its documented non-interactive branch instead. The two shapes are:
- BLOCK → stop the pipeline, call
render_completion_cardwith variant
ship-blocked (reason stated), and return. The orchestrator treats the item as parked and moves on — one blocked issue never halts the queue.
- RECORD & CONTINUE → don't ask, don't block; fold the open point into a
userFinalTest item for Step 6 and proceed. Only for genuinely non-fatal points.
| Interactive gate | Normal behavior | $SHIP_LOCKOUT behavior | |---|---|---| | Pre-Step B — session activity still in progress | ask Warten/Trotzdem/Abbrechen | in-scope activity pending → BLOCK ("session activity active"); otherwise proceed | | Step 1b(e) — truly ambiguous rebase conflict | abort + ask which side wins | git rebase --abort → BLOCK ("unresolvable merge conflict — needs human decision") | | Step 1d — high-impact purpose-alignment conflict | ask (batched) | apply mechanical fixes as usual; high-impact items → RECORD & CONTINUE | | Step 2 — Codex judgment-required finding | ask Fixen/Ignorieren/Abbrechen | auto-fixable → fix inline; design/logic/security → BLOCK (finding named) | | Step 3 — major version bump | always ask | BLOCK ("needs major-version decision — not shipped unattended") |
A BLOCK under lockout is the safe outcome, not a failure: the caller parks the issue as a ⏸ Rückfrage and the queue continues. Shipping an unreviewed security finding, an ambiguous merge, or an unattended breaking change would be the actual failure. When $SHIP_LOCKOUT is false (a normal interactive ship), every gate behaves exactly as written elsewhere in this skill — unchanged.
Pre-Step B — Session Activity Guard
Before anything else, check whether this session still has work in progress.
- Check for background agents still running (Agent tool results pending)
- Check for background Bash commands still executing
- Check for TodoWrite tasks that are not yet marked
completedorcancelled
If ANY of the above are active:
> STOP. Do not proceed with shipping. > > Inform the user which activities are still in progress (agent names, task descriptions, or command summaries). > Ask via AskUserQuestion: > - "Warten bis alles fertig ist" — pause and resume /ship automatically when all activity completes > - "Trotzdem shippen" — user accepts the risk, continue with Step 0 > - "Abbrechen" — cancel /ship entirely
If $SHIP_LOCKOUT (Pre-Step A): do not ask. If genuine in-scope activity is still pending, BLOCK (ship-blocked, "session activity active"); otherwise proceed to Step 0.
This guard only applies to the current chat session, not external CI or other terminals.
> Sentinel hygiene (every exit path). ship_preflight writes a > ship-in-progress sentinel that makes the main-branch Edit guards > (pre.main.guard / pre.edit.branch) stand down for the ship's duration. It is > cleared by ship_cleanup on a successful ship — but a ship-blocked / abort > return (any render_completion_card variant ship-blocked below) skips cleanup > and would leave the sentinel stranded, silently disarming main-branch protection > until it ages out. Rule: before rendering ANY ship-blocked card, first call > ship_cleanup({ branch, cwd, keep: true }) — keep-mode deletes no branch/worktree, > it only clears the sentinel so main-branch protection resumes immediately.
Step 0 — Load Extensions
Check for optional overrides. Use Glob to verify each path exists before reading. Do NOT call Read on files that may not exist — skip missing files silently (no output).
- Global:
~/.claude/skills/ship/SKILL.md+reference.md - Project:
{project}/.claude/skills/ship/SKILL.md+reference.md - Merge: project > global > plugin defaults
Project extensions define: quality gate commands, deploy targets, version files, CI specifics.
Also capture, if present in the merged reference.md, for use later in this run:
outOfBandDeploy:— a list of path globs for artifacts a code merge does NOT
deploy (DB migrations, edge/serverless functions). Pass them to ship_preflight in Step 1a. Omit when absent — the tool applies stack-agnostic defaults.
deploy:— a deploy handler (e.g.supabase) that can actually APPLY those
artifacts post-merge. Used by Step 4d. When absent, Step 4d raises the deploy gate instead of deploying.
- Codex context: Read
{PLUGIN_ROOT}/deep-knowledge/codex-integration.md— this skill has a mandatory Codex review gate (§1 in that doc), which MUST be called via{PLUGIN_ROOT}/scripts/codex-safe.sh(5-min hard timeout, see "Hard Timeout & Failure-Tolerance" section), NEVER via the/codex:rescueAgent tool. Detect Codex availability now so Step 2 can act on it.
Step 0.5 — Load Deferred MCP Schemas
Ship tools from the dotclaude-ship MCP server are often deferred in large-tool-inventory sessions (their names appear in the SessionStart deferred-tools list, but their schemas are NOT loaded yet). Calling them directly before the schema is loaded fails with InputValidationError.
See {PLUGIN_ROOT}/deep-knowledge/mcp-deferred-tools.md for the full pattern.
Before Step 1, load all ship tool schemas in ONE ToolSearch call:
ToolSearch({
query: "select:mcp__plugin_devops_dotclaude-ship__ship_preflight,mcp__plugin_devops_dotclaude-ship__ship_build,mcp__plugin_devops_dotclaude-ship__ship_version_bump,mcp__plugin_devops_dotclaude-ship__ship_release,mcp__plugin_devops_dotclaude-ship__ship_cleanup",
max_results: 5
})
If the ToolSearch result contains all five ` entries, proceed. If ANY are missing from the returned block, the server is genuinely not registered — STOP and report to the user (do NOT fall back to gh pr create`; the guard hook will block it).
Do NOT skip this step even if you "think" the tools are available. analysis / ready / test cards have no ship-tool dependency and won't hit this — only the full pipeline does.
Step 1 — Pre-Flight & Rebase Loop
Run preflight, resolve any merge-safety issues autonomously, and re-check — repeat until the branch is clean.
1a. Run preflight
Call ship_preflight MCP tool (dotclaude-ship server). CRITICAL: Always pass cwd — the MCP server runs in the plugin directory, not the target repo. Omit base to let the tool auto-detect it.
ship_preflight({ cwd: "" })
If Step 0 captured an outOfBandDeploy: glob list from the extension, pass it: ship_preflight({ cwd: "", outOfBandGlobs: ["**/migrations/**", ...] }). Otherwise omit it — the tool uses stack-agnostic defaults.
The result carries outOfBandDeploys: { detected, files, kinds, globs } — artifacts this diff touches that a code merge will NOT deploy (#243). Carry this value forward to Step 4d. It is informational, never a hard gate (ready is unaffected).
The tool auto-detects the correct base branch:
- If on a sub-branch like
feat/42-video-filters/core, it detectsfeat/42-video-filtersas the parent and uses it as base. - Otherwise it uses the repository's default branch (resolves
origin/HEAD— typicallymain, butmasteror any other name works too). Falls back tomainiforigin/HEADis not set. - You can override by passing an explicit base:
ship_preflight({ base: "feat/42", cwd: "" }).
Check the result:
autoDetectedBase— non-null if a parent branch was detected (confirms intermediate merge).intermediate—trueif merging into a feature branch instead of main.ready: false→ report errors and STOP. Do not proceed.needsRebase: true→ continue to 1b (do NOT stop).
The tool checks: clean tree, commits ahead, all pushed, version consistency (skipped for intermediate), worktree detection, and unresolved conflict markers (no-conflict-markers).
The marker check has two scopes. A marker in the files this ship would land is a hard error — ship_release re-scans immediately before committing, so one left behind by the rebase in 1b is caught there too. A marker anywhere else in the repo is a warning: it predates this branch, so report it and open a separate fix rather than holding an unrelated release hostage. Merge-safety issues (base-ahead, file-overlap, config-conflictstyle) are warnings, not errors — they are resolved autonomously below.
1a-ii. Read mode — the repo-mode fork
ship_preflight returns a mode field. Read it. It decides which of the steps below can run at all, and ignoring it is how a ship in a repo-less project marched into rebase/push/PR and reported a merge that never happened.
| mode | What it means | How the pipeline changes | |---|---|---| | git | Repo with an origin | Full pipeline, nothing changes. | | git-no-remote | Local repo, no origin | Everything up to and including the commit runs. ship_release commits and then stops; push, PR, merge, tag and release are skipped and reported as skipped. | | file-only | Not a git repo at all | Everything that is not a git action still runs — see below. |
file-only is NOT "skip the ship". A ship is worth running in a repo-less project for everything it does besides git: the build, the test suite, the doc-freshness check, the quality gates, the worktree/merge sanity questions, and the honest report at the end. Only the git actions are meaningless there.
Concretely, in file-only:
- Run Step 2 (build + tests) and Step 3 (version bump) exactly as normal —
ship_build and ship_version_bump already handle the mode.
- Run the documentation and quality checks you would otherwise run; a
repo-less project benefits from them just as much.
- Skip Step 1b entirely (there is nothing to rebase onto) and Step 4b (no
merge to watch).
- Call
ship_releaseanyway — it returns
{ success: true, skipped: true, reason: "file-only-mode", delivered: "none" } without touching git.
- Call
ship_cleanupanyway — it clears the ship sentinel and refuses every
destructive git call.
- Render the
ready-filescompletion card, notship-successful, and pass
state: { mode: "file-only", filesModified: , delivered: "none" }. Never claim a commit, branch, PR or merge.
Report the outcome in plain terms: what was built, what the tests said, what changed on disk — and that there is no repo, so nothing was pushed.
1b. Resolve merge-safety warnings
Only runs when needsRebase: true. Otherwise skip to Step 2.
- Set diff3 (if
config-conflictstylewarning):git config merge.conflictstyle diff3
- Rebase onto base:
``bash git fetch origin git rebase origin/ ``
- If rebase succeeds (no conflicts): push and re-check (go to 1c).
- If rebase has conflicts — resolve them autonomously (do NOT ask user):
a. git diff --name-only --diff-filter=U to list conflicting files. b. For each conflicting file:
- Read the file (contains
>>>>>>markers with diff3 base section) - Analyze both sides semantically: what did our branch change vs. what did base change?
- Check chronological context: which change is newer? Do they contradict or complement each other?
- Produce a merged version that preserves both intents
- Write the resolved file, then
git add— with all four marker
lines removed, ||||||| included. Deleting the familiar three and leaving the diff3 base marker is the failure no-conflict-markers exists for; it blocks the ship at Step 4 rather than landing on main. c. git rebase --continue d. If more conflicts appear (multi-commit rebase), repeat (b)–(c) e. Truly ambiguous conflicts (both sides change the same logic in contradictory ways and the correct resolution is not determinable from code context): abort the rebase (git rebase --abort) and ask the user via AskUserQuestion with a clear, developer-readable explanation:
- Show the conflicting snippet (both sides + base)
- Explain what each side intended
- Ask which intent should win, or whether both need manual reconciliation
If $SHIP_LOCKOUT (Pre-Step A): do not ask. After git rebase --abort, BLOCK (ship-blocked, "unresolvable merge conflict — needs human decision"); the caller parks the issue and the queue continues.
- Push:
git push --force-with-leaseto update the remote branch.
- Verification test: Run the full test suite to confirm nothing broke. If tests fail, diagnose and fix before proceeding.
1c. Re-run preflight
After rebase + push + tests pass, re-run ship_preflight with the same parameters.
needsRebase: falseandready: true→ proceed to Step 2.needsRebase: true→ someone pushed to base during our rebase. Go back to 1b.ready: false(hard errors) → report errors and STOP.
This loop naturally terminates — each iteration brings the branch closer to base.
1d. Purpose Alignment Gate
After the preflight loop stabilizes (ready: true), verify the ship against the purposes of recently merged work — not just its code. Full protocol: deep-knowledge/purpose-alignment.md.
- Light check (every ship, direct + intermediate): gather the purposes of
the last 3–5 merged PRs into ` (Claude-authored bodies preferred; fallback: merge commits / CHANGELOG), extract cross-cutting conventions, and audit **in both directions**: (a) the current diff honors prior conventions — e.g. a prior branch's "all elements get hotkeys" must also cover an element added on THIS branch, even though the hotkey task never belonged to it; and (b) a convention THIS branch introduces is retro-applied to the existing artifacts on ` as part of this ship (reverse propagation).
- **Full check (a rebase/merge happened in 1b, or re-entry after
baseAdvancedDuringChecks):** additionally verify the merged content sti
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Jerry0022
- Source: Jerry0022/dotclaude
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.