tpdc-plugin/skills/ship/SKILL.md
TPDC end-to-end — take a feature request in natural language and ship it as a PR with CI green. Orchestrates intake → plan → execute → run-tests → push → open-PR → auto-fix-CI with confirmation gates at the irreversible steps. This is the user-facing entry point for TPDC. Trigger when the user says "ship this feature", "/tpdc:ship", or pastes a feature request expecting an autonomous pipeline.
npx skillsauth add mtrejo11/tpdc-engine shipInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The TPDC entry point. Take a natural-language feature request and walk it through the full 8-stage pipeline, presenting the user with summaries and confirmation gates at the irreversible steps (after plan, before push, before auto-fix-CI loop). Returns a PR URL plus the final CI status.
request (string, required): natural-language feature description from the user.repoRoot (string, optional): absolute path to the target repo. Defaults to the current working directory; verify with Bash (git rev-parse --show-toplevel) if missing.maxLocalFixRetries (number, optional): retries for failing local tests via tpdc_execute fix-mode. Default 3.maxCIFixRetries (number, optional): retries for failing CI runs. Default 3. Passed to auto-fix-ci.baseBranch (string, optional): PR base. Default main (the open-PR stage detects automatically when omitted).draft (boolean, optional): open PR as draft. Default false.Return one of:
{
"status": "success",
"prUrl": "https://github.com/owner/repo/pull/N",
"prNumber": N,
"ciConclusion": "success",
"localFixRetries": 0,
"ciFixRetries": 0
}
{
"status": "halted",
"stage": "intake" | "plan" | "execute" | "run-tests" | "push" | "open-pr" | "auto-fix-ci",
"reason": "...",
"context": { ... stage-specific halt context ... }
}
Every halt has a stage and a concise reason. Surface this to the user so they know where to pick up manually.
repoRoot (use Bash: cd "$repoRoot" && git rev-parse --show-toplevel to verify it's a git repo).runId: ship-$(date +%Y%m%d-%H%M%S)-$(openssl rand -hex 3) via Bash. Use it consistently across all MCP tool calls.<runId> against <repoRoot> (base: <baseBranch>)."/tpdc:intake skill)Read tpdc-plugin/skills/intake/SKILL.md and follow its workflow end-to-end:
Read / Grep / Glob to auto-resolve obvious questions.IntakeArtifact.mcp__plugin_tpdc_tpdc__tpdc_validate_intake_artifact. Iterate on errors.Result: a validated IntakeArtifact (the schema-default-applied version from the validator).
If the intake skill itself halted (user aborted, or readiness: "not_ready" after exploration), return:
{ "status": "halted", "stage": "intake", "reason": "<reason>", "context": { "lastArtifact": <partial> } }
/tpdc:plan skill)Read tpdc-plugin/skills/plan/SKILL.md and follow its workflow with the validated intake from stage 1 as the input.
The plan skill includes its own validation via tpdc_validate_plan_artifact (including DAG / dependency invariants). Iterate on errors there.
Result: a validated PlanArtifact.
Show the user a compact summary:
plan.titleplan.objective (one paragraph)<stepNumber>. <title>)riskLeveltestCommands listThen ask with concrete options (use AskUserQuestion in Cowork mode or a 3-option chat question otherwise):
"Plan looks ready. How do you want to proceed?
- Run it as planned (continue to execute)
- Tweak the plan first (let me revise — I'll ask what to change)
- Stop (halt the workflow here)"
Branch:
additionalContext, validate, return to this gate.{ status: "halted", stage: "plan", reason: "User stopped after plan review" }.Call mcp__plugin_tpdc_tpdc__tpdc_execute:
{
"runId": "<runId>",
"intakeTitle": "<intake.title>",
"plan": <plan>,
"repoRoot": "<repoRoot>"
}
Hold onto the returned ExecuteResult — you'll need its worktreePath, branch, baseSha, filesChanged, diff for downstream stages.
Interpret the result:
status: "completed" → continue to stage 4.
status: "no_changes" → halt with reason: "Execute produced no changes. The plan may have been a no-op against this repo.".
status: "max_turns_exceeded" → continue, but mark this run as WIP (the agent hit the cap but produced a partial commit). Track wipReason = "Execute halted at max_turns. Output is partial." for the open-PR stage. Skip stage 4 (don't run tests on partial work). Skip stage 5 (no push). Skip stage 6 (no PR). Return halted.
Actually: in WIP mode, do push as a draft PR so the user has somewhere to inspect the partial work. Adjust the flow: skip to stage 5 with draft: true + wipReason; skip stage 4; tests will run on the PR itself once opened. Don't auto-fix-CI.
status: "tool_error_loop" | "model_refused" → halt with that reason; don't push.
Only entered when execute completed cleanly.
localRetry = 0
Loop:
Call mcp__plugin_tpdc_tpdc__tpdc_run_tests:
{
"runId": "<runId>",
"worktreePath": "<executeResult.worktreePath>",
"commands": "<plan.testCommands>"
}
Interpret:
status: "all_passed" | "no_commands" → break the loop, continue to stage 5.status: "some_failed" | "errored":
If localRetry >= maxLocalFixRetries: halt the loop. Two options:
wipReason: "Local tests still failing after <N> fix retries." and draft: true.reason: "Local tests failing after <N> retries. Worktree at <path>.".Otherwise: invoke fix-mode execute:
{
"runId": "<runId>",
"intakeTitle": "<intake.title>",
"plan": <plan>,
"repoRoot": "<repoRoot>",
"existingWorktree": { "path": "...", "branch": "...", "baseSha": "..." },
"failureContext": {
"attempt": <localRetry + 1>,
"previousCommands": [
/* per-command from the failing run-tests result */
],
"previousFinalSummary": "<executeResult.finalSummary>"
}
}
On status: "completed": localRetry++, loop back to step 1.
On status: "no_changes" | "max_turns_exceeded" | etc.: halt with the specific reason.
This is the local equivalent of auto-fix-ci but without the confirmation gates — local fixes don't affect a remote and the user already approved the plan. The cap is the safety.
Call mcp__plugin_tpdc_tpdc__tpdc_push:
{
"runId": "<runId>",
"repoRoot": "<repoRoot>",
"worktreePath": "<executeResult.worktreePath>",
"branch": "<executeResult.branch>"
}
status: "pushed" → continue to stage 6.status: "failed" | "errored" → halt with reason: "Push failed: <stderr first line>. Likely auth or branch protection. Worktree at <path>; you can push manually.".Call mcp__plugin_tpdc_tpdc__tpdc_open_pr:
{
"runId": "<runId>",
"repoRoot": "<repoRoot>",
"branch": "<executeResult.branch>",
"baseBranch": "<baseBranch>",
"intake": <intake>,
"plan": <plan>,
"execute": <executeResult>,
"tests": <runTestsResult>,
"draft": <draft (true if WIP)>,
"wipReason": "<wipReason if set>"
}
status: "opened" → continue to gate 2.status: "gh_missing" → halt with reason: "gh CLI not installed. Install it and run gh auth login, then run /tpdc:open-pr to retry from this stage.".status: "failed" | "errored" → halt with that reason.Show the user:
<prUrl>"<branch> → base <baseBranch>"<plan.riskLevel>"Ask:
"PR is open. What's next?
- Wait for CI + auto-fix any failures (will use /tpdc:auto-fix-ci, up to <maxCIFixRetries> retries)
- Wait for CI but don't auto-fix (just monitor; halt on first failure)
- Stop here (PR open, you'll check CI yourself)"
Branch:
tpdc_wait_ci once. Return with ciConclusion. Don't loop.{ status: "success", prUrl, prNumber, ciConclusion: "skipped", ... }. The PR is open; the user will handle CI manually./tpdc:auto-fix-ci skill)Read tpdc-plugin/skills/auto-fix-ci/SKILL.md and follow its workflow with these inputs:
{
"runId": "<runId>",
"repoRoot": "<repoRoot>",
"branch": "<executeResult.branch>",
"intake": <intake>,
"plan": <plan>,
"executeResult": <executeResult>,
"maxRetries": <maxCIFixRetries>
}
The auto-fix-ci skill includes its own confirmation gates per iteration.
Interpret the result:
{ status: "success", retries } → return { status: "success", prUrl, prNumber, ciConclusion: "success", localFixRetries, ciFixRetries: retries }.
{ status: "halted", reason, retries, lastLogs? } → return:
{
"status": "halted",
"stage": "auto-fix-ci",
"reason": "<auto-fix-ci's reason>",
"context": { "prUrl": "...", "lastLogs": "...", "ciFixRetries": <retries> }
}
(Note: even on halt, the PR is open and the user can pick up from there.)
There are two explicit user gates in this skill (after plan, after PR open) plus the two gates per iteration inside auto-fix-ci (attempt fix? force-push?). That's the minimum to satisfy VISION.md §7.5 ("Never apply patches silently — always show diffs and require confirmation"):
Local test fix-ups (stage 4) don't need a gate because the user already approved the plan and nothing is going to a remote. The cap (maxLocalFixRetries) is the safety. If we add gates here too, ship loses its end-to-end flow.
draft: true + wipReason. The PR template surfaces the WIP warning so reviewers know it's not done.gh_missing. It's an infra issue, not a code issue. Surface it clearly so the user can install gh once.Keep these in your scratchpad as you progress:
runIdrepoRoot, baseBranch, draft (final, possibly upgraded to true via WIP path)intake (validated)plan (validated)executeResult (post-execute) — this is the source of worktreePath, branch, baseSharunTestsResult (post-stage-4) — for the PR bodylocalFixRetries (count, for the final summary)prUrl, prNumber (post-stage-6)wipReason (only when set)tpdc_record_run_event per stage (v0.4.0-alpha.9+)The canonical run summary lives at <repoRoot>/.tpdc/memory/runs/<runId>.md. As of alpha.9, the ship skill writes it via the tpdc_record_run_event MCP tool — one structured call per stage, no manual markdown editing. The tool validates the payload (Zod discriminated union on eventType) before touching disk, so a malformed call is rejected with a per-field error list rather than silently producing a broken file.
This replaces the older prompt-driven pattern (asking the executor agent to write to memory itself). The executor MAY still keep ad-hoc memory notes — that's separate. But the per-run summary is the orchestrator's responsibility now.
Call tpdc_record_run_event at these points in the workflow:
| When | event payload |
| --- | --- |
| After stage 3 (execute) completes (any status — including halts) | { eventType: "execute_complete", task: <intake.title>, status: <executeResult.status>, branch: <executeResult.branch>, filesChanged: <executeResult.filesChanged>, finalSummary: <executeResult.finalSummary>, toolCallCount: <executeResult.toolCallCount>, turnCount: <executeResult.turnCount> } |
| After stage 4 (run-tests), when it ran | { eventType: "tests_complete", status: <runTestsResult.status>, commands: [{ command, passed }, ...] } |
| After stage 6 (open-PR) succeeds | { eventType: "pr_opened", prUrl, prNumber, draft?, wipReason? } |
| After wait-CI or auto-fix-CI terminates | { eventType: "ci_complete", conclusion, localFixRetries, ciFixRetries } |
| On any halt (every halt branch in this skill) | { eventType: "halt", stage: <stage>, reason: <reason> } |
Each call appends one ## <Section> block. The first call creates the file with a # TPDC run <runId> header; subsequent calls just append.
Don't fabricate fields. If a field isn't actually known (e.g., ciFixRetries when auto-fix-CI wasn't run), omit it — the tool's schema marks those optional precisely so callers don't pad with zeros that look like real data.
Don't worry about ordering across reruns. If a stage runs multiple times (fix-mode execute, auto-fix-CI iterations), record each as its own event. The summary file is an event log, not a snapshot.
Note: TPDC has visibility into executeResult.usage (input/output/cache/advisor/web tokens for the execute step). Claude Code session burn for intake/plan/auto-fix-ci as skills is OUTSIDE TPDC's visibility — don't fabricate those numbers in any free-text summary you give the user.
On success:
✅ TPDC ship complete.
- PR: https://github.com/owner/repo/pull/42
- CI: ✅ green
- Local fix retries: 1 / 3
- CI fix retries: 0 / 3
- Branch: tpdc/run-ship-20260512-103045-a1b2c3
- Worktree (kept for reference): /repo/.tpdc/worktrees/ship-20260512-103045-a1b2c3
On halt:
⚠️ TPDC ship halted at stage: <stage>.
- Reason: <reason>
- PR: <url or "not opened">
- Recovery: <one-sentence next-step suggestion>
This is the user-facing entry. Sub-skills (/tpdc:intake, /tpdc:plan, /tpdc:auto-fix-ci) are intentionally invokable independently for partial workflows. If a user has already produced an intake and just wants planning, they can call /tpdc:plan directly — they don't need to go through /tpdc:ship. The MCP tools underneath are also directly callable.
/tpdc:ship is the simplest path for the happy case: "ship this for me." Everything else is opt-in.
testing
Convert a validated IntakeArtifact into a typed TPDC PlanArtifact with ordered steps, dependencies (DAG), test commands, and risk assessment. Use after intake when the user asks to "plan it", "break this down", "produce a plan", or as the second step in a /tpdc:ship workflow.
tools
Convert a vague feature request into a structured TPDC IntakeArtifact (problem statement, acceptance criteria, scope, open questions). Use when the user asks for a "TPDC intake", "structure this request", "produce an intake artifact", or as the first step in a /tpdc:ship workflow.
testing
After a TPDC PR is opened, wait for CI; if it fails, fetch logs, run execute in fix-mode, force-push the fix, and re-wait. Loops up to maxRetries times with confirmation gates. Use after /tpdc:open-pr or as the tail of /tpdc:ship.
testing
Analysis/audit mode. Evaluates security, performance, or architecture risks without producing patches. Use when the user asks to "assess", "audit", "evaluate security", "check performance", "review architecture", or "analyze risks".