Skip to content
Back to skills

Phase Doc Sync

ASecurity

Applies sprint implementation results to docs/phases/ phase plan files. Used by phase-builder as a sub-agent after each implementation wave — updates task Status columns from structured SPRINT RESULT payloads in batched edits. Orchestrator must never edit phase files directly during a phase run; spawn this instead. Also use when the user asks to sync phase docs from sprint results without re-implementing code.

  • 18 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 16, 2026
ai-agentsgoshellbashgit

Security analysis

A100/100

Scanned October 16, 2026

npx -y skills add AyeJK/phase-runner --skill phase-doc-sync --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Phase Doc Sync?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Phase Doc Sync
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/ayejk-phase-doc-sync/badge)](https://www.skillsdirectory.com/skills/ayejk-phase-doc-sync)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: phase-doc-sync
description: "Applies sprint implementation results to docs/phases/ phase plan files. Used by phase-builder as a sub-agent after each implementation wave — updates task Status columns from structured SPRINT RESULT payloads in batched edits. Orchestrator must never edit phase files directly during a phase run; spawn this instead. Also use when the user asks to sync phase docs from sprint results without re-implementing code."
---

# Phase Doc Sync

Updates `docs/phases/Phase-*.md` task tables from structured sprint results. **Read-only for implementation code** — only touches phase plan markdown, plus the run log when the payload has `run_log`.

The **phase-builder orchestrator** spawns you as a sub-agent after each implementation wave. The orchestrator parses `SPRINT RESULT` blocks and passes a structured payload; you apply edits using **phase-planner** rules.

---

## Orchestrator contract (phase-builder)

The orchestrator MUST:

1. Parse each implementation sub-agent's `SPRINT RESULT:` block into structured data
2. Spawn **one** doc-sync call per wave (never edit `docs/phases/*.md` itself)
3. Wait for your `DOC SYNC RESULT:` block before the next wave's verify (the next wave's implementation may already be running alongside you)
4. Log only a one-line summary per sprint (no direct edits to phase files in the orchestrator thread)

The orchestrator MUST NOT edit `docs/phases/*.md` during an active phase run.

**Model (optional):** this role is mechanical — flip Status cells from a structured payload — a good candidate for a cheaper/faster model. If `runtime-adapter.md` resolved a `gate_model`, spawn this call with it. Otherwise use the session default; this is a cost optimization, never a blocker.

---

## Input payload (from orchestrator)

The orchestrator includes this JSON in your prompt:

```json
{
  "phase_file": "docs/phases/Phase-11-Example-Feature.md",
  "project_root": "/path/to/workspace",
  "app_root": "/path/to/app-root",
  "sprints": [
    {
      "id": "11.1",
      "title": "Example sprint title",
      "completed": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
      "blocked": [],
      "blocked_reasons": {},
      "manual": [],
      "deferred": [],
      "cut": [],
      "notes": "optional string from SPRINT RESULT NOTES"
    }
  ],
  "user_overrides": [],
  "run_log": {
    "path": "/path/to/workspace/docs/phases/.runs/phase-11.jsonl", "phase": 11, "wave": 1, "attempt": 1, "max": 1,
    "diff_base": "git tree sha the wave started from, or null",
    "wave_end": "git tree sha of the code that passed the wave's last verify, or null"
  }
}
```

`run_log` is optional. When present, append `doc_sync` events after your edits (see Run log); when absent, write nothing.

**You may be running alongside the next wave's implementation agents.** They edit app code, never the phase file, so there is nothing to coordinate — but don't read or diff the live working tree for this wave's changes. Use the two shas above.

**Field rules:**

| Field | Maps to Status |
|-------|----------------|
| `completed` | `x` |
| `blocked` | `BLOCKED` |
| `manual` | `MANUAL` |
| `deferred` | `DEFERRED` |
| `cut` | `CUT` |
| `user_overrides` | After user says skip/defer/cut, or that a task is theirs to do — e.g. `[{ "id": "11.3", "task": 3, "status": "DEFERRED" }]`. `status` is `DEFERRED`, `CUT` or `MANUAL` |

Process sprints in **ascending ID order** (`X.Y` numeric) even if the payload order differs.

If a task number appears in multiple lists, precedence: `blocked` > `manual` > `deferred` > `cut` > `completed`. A `user_overrides` entry beats all of them.

---

## Execution steps

1. Load the **phase-planner** skill (per runtime-adapter.md in the phase-builder skill) only if a table needs migrating or its format is unclear. A table that already has a Status column doesn't need it.
2. **Don't read the whole phase file.** Grep it for the sprint headers (`^# Sprint`) and the task rows (`^\| .* \| \d+ \|`) with line numbers, then read only the `### Tasks` table of each sprint in the payload (offset/limit).
3. For each sprint in the payload (ascending `id`):
   - Locate section `# Sprint {id} — {title}`
   - Find the `### Tasks` table
   - Migrate table (add Status column) if missing — per phase-planner
   - Update Status cells for listed task numbers only
   - Leave task text, Module, Reference, acceptance criteria, dependencies unchanged
4. **Write discipline:**
   - **One edit per sprint section** when possible (replace the entire `### Tasks` table block)
   - If tables are too large for one match, **at most one edit per sprint** by matching from `### Tasks` through the row before `### Acceptance`
   - **Never** one edit per task row
   - **One write pass per phase file** for the whole payload (batch all sprint edits before writing, or sequential edits on the same file in one session — still no per-row spam)
5. Verify with the same grep: every listed task shows the expected status. Don't re-read the file.
6. **Log the sync** — once STATUS is decided, if `run_log` is present, append one `doc_sync` line per sprint in the payload, with the wave's `files` (see [Run log](#run-log))
7. End with `DOC SYNC RESULT:` (required)

---

## Status column values

| Value | Meaning |
|-------|---------|
| `x` | Completed |
| `BLOCKED` | Blocked |
| `MANUAL` | Only the user can do it; they mark it `x` themselves |
| `DEFERRED` | Deferred |
| `CUT` | Cut from scope |
| `—` | Not started (do not change unless explicitly in payload as reset) |
| `~` | In progress (only set if orchestrator requests `mark_active`) |

Do not change tasks not mentioned in the payload unless the orchestrator sends `mark_sprint_done: true` for a sprint with empty lists — then set **all** `—` and `~` rows in that sprint to `x` (whole sprint complete). Leave `MANUAL` rows as they are.

---

## Output block (required)

```
DOC SYNC RESULT:
STATUS: SUCCESS | PARTIAL | FAILED
FILE: {path relative to project root}
SPRINTS_SYNCED: {comma-separated sprint ids, or NONE}
TASKS_UPDATED: {total count}
FAILURES: [sprint id + reason per line, or NONE]
NOTES: [formatting issues, ambiguous rows, anything orchestrator should know]
```

- **SUCCESS** — every requested status applied and verified
- **PARTIAL** — some sprints updated; list in FAILURES
- **FAILED** — file not found, no matching sprint section, or could not apply without guessing

---

## Run log

Only when the payload has `run_log`. The spec is phase-builder's `run-log.md`; this is the part you need. Never write the log with a file-edit tool.

**1. The wave's changed files.** Skip this line when `run_log.diff_base` or `run_log.wave_end` is null; the events then carry no `files`. Otherwise run it first, in the same command as the appends, with `{app_root}` = APP ROOT, `{diff_base}` = `run_log.diff_base` and `{snapshot}` = `run_log.wave_end`:

```sh
RL_FILES=$(cd '{app_root}' && git -c core.quotePath=false diff --relative --name-only {diff_base} {snapshot} -- ':(exclude)docs/phases') && RL_FILES=',"files":['"$(printf '%s' "$RL_FILES" | tr '\042\134' "'/" | sed 's/.*/"&"/' | paste -sd, -)"']' || RL_FILES=''
```

**2. One append per sprint**, with this exact line, replacing only the `{…}` placeholders and keeping every other character, including the summary's `tr` pipe and `"${RL_FILES:-}"`. `{path}`, `{phase}`, `{wave}`, `{attempt}` and `{max}` come from `run_log`. Every sprint in the wave gets the same `files`.

```sh
mkdir -p "$(dirname '{path}')" && printf '{"v":1,"ts":"%s","phase":%d,"wave":%d,"sprint":"%s","gate":"%s","result":"%s","attempt":%d,"max":%d,"summary":"%s"%s}\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" '{phase}' '{wave}' '{sprint}' '{gate}' '{result}' '{attempt}' '{max}' "$(printf '%s' '{summary}' | tr '\042\134\011\012\015' "'/   " | tr -d '\000-\037')" "${RL_FILES:-}" >> '{path}'
```

Run it as one call: `RL_FILES=…; {append for 11.1} && {append for 11.2}`.

| `gate` | One line per | `result` | `summary` |
|--------|--------------|----------|-----------|
| `doc_sync` | sprint in the payload, ascending `id` | `pass` if its statuses were applied; `fail` if it's in `FAILURES` | `{k} tasks updated`, or the reason from `FAILURES` |

- Summaries are one line, at most 200 characters. Write a straight apostrophe as `'\''`; type everything else as-is, including `"` and `\`. Never backslash-escape a character: inside single quotes `\"` stays two characters and lands in the log as `/'`.
- Use a POSIX shell (Git Bash on Windows).
- A git error in step 1 still writes the events, without `files`; say so in `NOTES`. An append that exits non-zero gets one line in `NOTES` (`run log: append failed — {reason}`). Neither changes STATUS.

---

## Prompt template (orchestrator fills braces)

```
You are the phase doc-sync agent. Update phase plan task statuses only.

Read and follow: the phase-doc-sync skill (loaded per runtime-adapter.md)
Read and follow: the phase-planner skill (loaded per runtime-adapter.md)

PROJECT ROOT: {project_root}
APP ROOT: {app_root}
PHASE FILE: {phase_file}

PAYLOAD:
{json payload}

RULES:
- Edit ONLY the phase file task Status columns for sprints in the payload
- Batch edits — never one edit per task row
- Do not modify acceptance criteria, dependencies, or overview prose
- Don't run git commands that change the working tree, index, stash or refs
- If the payload has run_log, append the doc_sync lines last (Execution step 6)
- End with DOC SYNC RESULT block

If SPRINT RESULT was missing for a sprint but orchestrator verified acceptance and sent mark_sprint_done, mark all incomplete tasks in that sprint as x.
```

---

## Error handling

| Situation | DOC SYNC STATUS | Action |
|-----------|-----------------|--------|
| Phase file not found | FAILED | Report path; orchestrator confirms location |
| Sprint header not found | PARTIAL or FAILED | List in FAILURES; do not edit wrong section |
| Task # not in table | PARTIAL | Note in FAILURES; continue other tasks |
| Table has no Status column | SUCCESS after migrate | Migrate atomically per phase-planner |
| Ambiguous duplicate task text | FAILED | Do not guess; list row in NOTES |

---

## Example

**Input:** Sprint 11.2, completed `[1,2,3,4,5,6,7]`, blocked `[]`

**Action:** Single edit on the `### Tasks` table under `# Sprint 11.2`, flipping `| — |` to `| x |` for tasks 1–7 only.

**Output:**

```
DOC SYNC RESULT:
STATUS: SUCCESS
FILE: docs/phases/Phase-11-Example-Feature.md
SPRINTS_SYNCED: 11.2
TASKS_UPDATED: 7
FAILURES: NONE
NOTES: none
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.