diff --git a/ship/SKILL.md b/ship/SKILL.md
index a8b6a75e..db978bd2 100644
--- a/ship/SKILL.md
+++ b/ship/SKILL.md
@@ -1099,7 +1099,13 @@ If multiple suites need to run, run them sequentially (each needs a test lane).
## Step 7: Test Coverage Audit
-100% coverage is the goal — every untested path is a path where bugs hide and vibe coding becomes yolo coding. Evaluate what was ACTUALLY coded (from the diff), not what was planned.
+**Dispatch this step as a subagent** using the Agent tool with `subagent_type: "general-purpose"`. The subagent runs the coverage audit in a fresh context window — the parent only sees the conclusion, not intermediate file reads. This is context-rot defense.
+
+**Subagent prompt:** Pass the following instructions to the subagent, with `` substituted with the base branch:
+
+> You are running a ship-workflow test coverage audit. Run `git diff ...HEAD` as needed. Do not commit or push — report only.
+>
+> 100% coverage is the goal — every untested path is a path where bugs hide and vibe coding becomes yolo coding. Evaluate what was ACTUALLY coded (from the diff), not what was planned.
### Test Framework Detection
@@ -1356,12 +1362,30 @@ Repo: {owner/repo}
## Critical Paths
- {end-to-end flow that must work}
```
+>
+> After your analysis, output a single JSON object on the LAST LINE of your response (no other text after it):
+> `{"coverage_pct":N,"gaps":N,"diagram":"","tests_added":["path",...]}`
+
+**Parent processing:**
+
+1. Read the subagent's final output. Parse the LAST line as JSON.
+2. Store `coverage_pct` (for Step 20 metrics), `gaps` (user summary), `tests_added` (for the commit).
+3. Embed `diagram` verbatim in the PR body's `## Test Coverage` section (Step 19).
+4. Print a one-line summary: `Coverage: {coverage_pct}%, {gaps} gaps. {tests_added.length} tests added.`
+
+**If the subagent fails, times out, or returns invalid JSON:** Fall back to running the audit inline in the parent. Do not block /ship on subagent failure — partial results are better than none.
---
## Step 8: Plan Completion Audit
-### Plan File Discovery
+**Dispatch this step as a subagent** using the Agent tool with `subagent_type: "general-purpose"`. The subagent reads the plan file and every referenced code file in its own fresh context. Parent gets only the conclusion.
+
+**Subagent prompt:** Pass these instructions to the subagent:
+
+> You are running a ship-workflow plan completion audit. The base branch is ``. Use `git diff ...HEAD` to see what shipped. Do not commit or push — report only.
+>
+> ### Plan File Discovery
1. **Conversation context (primary):** Check if there is an active plan file in this conversation. The host agent's system messages include plan file paths when in plan mode. If found, use it directly — this is the most reliable signal.
@@ -1477,6 +1501,18 @@ After producing the completion checklist:
**No plan file found:** Skip entirely. "No plan file detected — skipping plan completion audit."
**Include in PR body (Step 8):** Add a `## Plan Completion` section with the checklist summary.
+>
+> After your analysis, output a single JSON object on the LAST LINE of your response (no other text after it):
+> `{"total_items":N,"done":N,"changed":N,"deferred":N,"summary":""}`
+
+**Parent processing:**
+
+1. Parse the LAST line of the subagent's output as JSON.
+2. Store `done`, `deferred` for Step 20 metrics; use `summary` in PR body.
+3. If `deferred > 0` and no user override, present the deferred items via AskUserQuestion before continuing.
+4. Embed `summary` in PR body's `## Plan Completion` section (Step 19).
+
+**If the subagent fails or returns invalid JSON:** Fall back to running the audit inline. Never block /ship on subagent failure.
---
@@ -1981,17 +2017,28 @@ Save the review output — it goes into the PR body in Step 19.
## Step 10: Address Greptile review comments (if PR exists)
-Read `.claude/skills/review/greptile-triage.md` and follow the fetch, filter, classify, and **escalation detection** steps.
+**Dispatch the fetch + classification as a subagent** using the Agent tool with `subagent_type: "general-purpose"`. The subagent pulls every Greptile comment, runs the escalation detection algorithm, and classifies each comment. Parent receives a structured list and handles user interaction + file edits.
-**If no PR exists, `gh` fails, API returns an error, or there are zero Greptile comments:** Skip this step silently. Continue to Step 12.
+**Subagent prompt:**
-**If Greptile comments are found:**
+> You are classifying Greptile review comments for a /ship workflow. Read `.claude/skills/review/greptile-triage.md` and follow the fetch, filter, classify, and **escalation detection** steps. Do NOT fix code, do NOT reply to comments, do NOT commit — report only.
+>
+> For each comment, assign: `classification` (`valid_actionable`, `already_fixed`, `false_positive`, `suppressed`), `escalation_tier` (1 or 2), the file:line or [top-level] tag, body summary, and permalink URL.
+>
+> If no PR exists, `gh` fails, the API errors, or there are zero comments, output: `{"total":0,"comments":[]}` and stop.
+>
+> Otherwise, output a single JSON object on the LAST LINE of your response:
+> `{"total":N,"comments":[{"classification":"...","escalation_tier":N,"ref":"file:line","summary":"...","permalink":"url"},...]}`
-Include a Greptile summary in your output: `+ N Greptile comments (X valid, Y fixed, Z FP)`
+**Parent processing:**
-Before replying to any comment, run the **Escalation Detection** algorithm from greptile-triage.md to determine whether to use Tier 1 (friendly) or Tier 2 (firm) reply templates.
+Parse the LAST line as JSON.
-For each classified comment:
+If `total` is 0, skip this step silently. Continue to Step 12.
+
+Otherwise, print: `+ {total} Greptile comments ({valid_actionable} valid, {already_fixed} already fixed, {false_positive} FP)`.
+
+For each comment in `comments`:
**VALID & ACTIONABLE:** Use AskUserQuestion with:
- The comment (file:line or [top-level] + body summary + permalink URL)
@@ -2370,12 +2417,41 @@ echo "LOCAL: $LOCAL REMOTE: $REMOTE"
[ "$LOCAL" = "$REMOTE" ] && echo "ALREADY_PUSHED" || echo "PUSH_NEEDED"
```
-If `ALREADY_PUSHED`, skip the push but continue to Step 19. Otherwise push with upstream tracking:
+If `ALREADY_PUSHED`, skip the push but continue to Step 18. Otherwise push with upstream tracking:
```bash
git push -u origin
```
+**You are NOT done.** The code is pushed but documentation sync and PR creation are mandatory final steps. Continue to Step 18.
+
+---
+
+## Step 18: Documentation sync (via subagent, before PR creation)
+
+**Dispatch /document-release as a subagent** using the Agent tool with `subagent_type: "general-purpose"`. The subagent gets a fresh context window — zero rot from the preceding 17 steps. It also runs the **full** `/document-release` workflow (with CHANGELOG clobber protection, doc exclusions, risky-change gates, named staging, race-safe PR body editing) rather than a weaker reimplementation.
+
+**Sequencing:** This step runs AFTER Step 17 (Push) and BEFORE Step 19 (Create PR). The PR is created once from final HEAD with the `## Documentation` section baked into the initial body. No create-then-re-edit dance.
+
+**Subagent prompt:**
+
+> You are executing the /document-release workflow after a code push. Read the full skill file `${HOME}/.claude/skills/gstack/document-release/SKILL.md` and execute its complete workflow end-to-end, including CHANGELOG clobber protection, doc exclusions, risky-change gates, and named staging. Do NOT attempt to edit the PR body — no PR exists yet. Branch: ``, base: ``.
+>
+> After completing the workflow, output a single JSON object on the LAST LINE of your response (no other text after it):
+> `{"files_updated":["README.md","CLAUDE.md",...],"commit_sha":"abc1234","pushed":true,"documentation_section":""}`
+>
+> If no documentation files needed updating, output:
+> `{"files_updated":[],"commit_sha":null,"pushed":false,"documentation_section":null}`
+
+**Parent processing:**
+
+1. Parse the LAST line of the subagent's output as JSON.
+2. Store `documentation_section` — Step 19 embeds it in the PR body (or omits the section if null).
+3. If `files_updated` is non-empty, print: `Documentation synced: {files_updated.length} files updated, committed as {commit_sha}`.
+4. If `files_updated` is empty, print: `Documentation is current — no updates needed.`
+
+**If the subagent fails or returns invalid JSON:** Print a warning and proceed to Step 19 without a `## Documentation` section. Do not block /ship on subagent failure. The user can run `/document-release` manually after the PR lands.
+
---
## Step 19: Create PR/MR
@@ -2392,7 +2468,7 @@ gh pr view --json url,number,state -q 'if .state == "OPEN" then "PR #\(.number):
glab mr view -F json 2>/dev/null | jq -r 'if .state == "opened" then "MR_EXISTS" else "NO_MR" end' 2>/dev/null || echo "NO_MR"
```
-If an **open** PR/MR already exists: **update** the PR body using `gh pr edit --body "..."` (GitHub) or `glab mr update -d "..."` (GitLab). Always regenerate the PR body from scratch using this run's fresh results (test output, coverage audit, review findings, adversarial review, TODOS summary). Never reuse stale PR body content from a prior run. Print the existing URL and continue to Step 18.
+If an **open** PR/MR already exists: **update** the PR body using `gh pr edit --body "..."` (GitHub) or `glab mr update -d "..."` (GitLab). Always regenerate the PR body from scratch using this run's fresh results (test output, coverage audit, review findings, adversarial review, TODOS summary, documentation_section from Step 18). Never reuse stale PR body content from a prior run. Print the existing URL and continue to Step 20.
If no PR/MR exists: create a pull request (GitHub) or merge request (GitLab) using the platform detected in Step 0.
@@ -2446,6 +2522,10 @@ you missed it.>
+## Documentation
+