NOTE: This is the canonical provider-independent contract. Both provider wrappers must load it in full.
- Resolve supporting assets and relative script paths against
.claude/skills/repo-sync/; the canonical prose lives here while implementation assets remain with the compatibility launcher. - A named skill call means the host's skill-dispatch primitive. An Agent, Explore agent, workflow, or sub-agent means an isolated task/action invocation with fresh context and the requested capability tier. Provider wrappers map these roles to their native APIs.
- Model tier names in inherited procedures describe capability roles. Resolve them through
config/model-tier-map.json; an unavailable required capability returnsrequired_tool_missingrather than weakening a gate. - Never expose hidden chain-of-thought. Preserve only decisions, evidence, commands, structured artifacts, and operator-facing rationale required by this contract.
Bidirectional sync between a plan document and GitHub issues. Creates, updates, closes, and enriches issues so GitHub mirrors the plan's structure and any fresh-context LLM picking up a step has enough context in the issue body to start work.
Issue bodies should be substantive. A fresh-context model reading
gh issue view #N should understand:
- What to build (not just a name)
- Where in the codebase (specific files)
- How to know it's done (concrete acceptance)
- What it depends on (prior issues, blocked-by relationships)
- Build-phase flags (reviewers, isolation,
--uiwhen frontend is touched) - Where the canonical design lives (build doc + section anchor)
- Whether the step can run in parallel with neighbors (declared explicitly, not left for the operator to infer)
Lean bodies (just "What to build" and a footer) tax every future session that picks up that issue. Treat enrichment as a first-class output, not optional polish. Issue count and inbox tidiness are human-experience costs the operator is fine paying — don't optimize for them at the expense of the LLM-context-effectiveness above.
This skill propagates the operator's strong workflow preference through every issue it writes. Three dials, applied to every step body:
-
Autonomous build readiness. Step bodies must contain enough acceptance detail (
Done when) for/build-stepto verify PASS without asking the operator a follow-up. Bodies that force a human ping mid-build are a regression. When enriching, prioritize concrete acceptance over prose. -
UI-bundle declaration. If a step's
Filestouchfrontend/, change a/api/...shape consumed by the dashboard, or modify WebSocket payloads, the issue body'sFlags (recommended)line MUST include--uiand theDone whenMUST reference UI evidence (Playwright screenshot, dashboard smoke, or any project-specific UI/dashboard smoke commands defined in the project'sCLAUDE.md). Code-only acceptance on frontend-touching work is the gap repo-sync is here to close — flag any existing issue that violates this and propose enrichment. -
Parallelism declared explicitly. If a step has no
Depends onand shares noFileswith another open step in the same phase, the body MUST note**Parallel-safe with:** #M(and the reciprocal noted on #M too). Sequential is fine, butnone — strictly sequentialMUST carry a one-line justification (e.g. "Step N+1 imports this module"); a bare "strictly sequential" without a reason is a defect — the parallelism choice must be visible in the issue, not hidden in the operator's head.
These dials are applied during CREATE, ENRICH, and UPDATE — not just on first write. A pre-existing rich body that lacks the UI-bundle declaration on a frontend-touching step still counts as needing ENRICH.
- Plan steps were added, removed, or reworded after issues were created
- Existing issues have lean bodies that need richer context (
--enrich) - Cutting issues for a new phase from its build doc
- User says: "sync issues", "update GitHub issues", "enrich step issues", "issues are out of date"
- Closing a single issue after a step completes — just
gh issue close N - Bulk-closing issues from a deleted plan (use
gh issue list ... | xargs gh issue close)
Run the plan pipeline in order. /repo-sync is step 4 of 5:
/plan-initor/plan-feature— produceplan.md./plan-review— gap-check before sync./plan-wrap— clean-context check before sync./repo-sync— mint or update issues from the plan./build-phase— execute the steps.
Skipping /plan-review or /plan-wrap before sync is the
N+1 rework trap: one plan edit becomes N+1 edits — the plan
file plus every step issue body that needs the same fix.
/repo-sync mints fresh-context-LLM-targeted issue bodies
straight from the plan, so plan-only ambiguities (undefined IDs,
unexplained acronyms, lingering TBDs) bake into every issue.
For an autonomous pre-flight that runs the chain unattended,
use /plan-expedite --plan <path> — it chains
plan-review --autofix → plan-wrap --autofix → repo-sync → session-wrap in one shot.
Canonical workspace-level statement of the chain lives in
dev/.claude/rules/plan-and-issue-flow.md § Order.
| Arg | Required | Default | Description |
|---|---|---|---|
--plan |
yes | -- | Path to plan/build-doc (e.g. documentation/plans/phase-d-build-plan.md) |
--phase |
no | inferred | Phase identifier (B, D, E, 6, 7, F, G, G.2, 9, etc.) — letters and numbers both supported. Inferred from filename if omitted. |
--scope |
no | both | umbrella, steps, or both |
--enrich |
no | false | Update existing-issue bodies if richer content is now in the plan |
--dry-run |
no | false | Print issue-change preview and exit without applying — for validation before commit |
--force |
no | false | Proceed despite missing evidence that the plan-review and plan-wrap prerequisite gates ran. |
Phases can be:
- Numeric:
Phase 0,Phase 1, ...,Phase 9— common for substrate/operational tracks - Letter:
Phase A,Phase B,Phase D, ...,Phase G— common for capability tracks - Sub-phase:
Phase G.1,Phase G.2,Phase G.3— for multi-step phases that fork
Numbering gaps are allowed and intentional (e.g. project skipped Phase C during a merge; project may skip Phase 8 to align with pre-existing issue titles). The skill honors the plan as-written — does NOT try to fill gaps.
Step numbering within a phase uses dot notation in the build doc
(e.g. D.1, D.2, 7.1, G.2.1) but issue titles use the friendlier
Phase X Step N: form.
Issue title patterns the skill recognizes:
- Umbrella:
Phase X — <name>(e.g.Phase D — Build-order z-statistic) - Step:
Phase X Step N: <name>(e.g.Phase D Step 1: Audit reward_rules.json) - Sub-phase umbrella:
Phase X.M: <name>(e.g.Phase G.2: Zerg bot) - Sub-phase step:
Phase X.M Step N: <name>
The skill scans the plan for any of:
### Step N: <name>— heading style### Phase X Step N: <name>— explicit phase heading#### Step N: <name>— sub-heading style- **Step N:** <name>— list style| X.N | <description> |— table row in a Scope / Build-steps section
For table-row format, the description is the step title; richer body content must be pulled from explicit per-step subsections OR the doc is flagged as lean (see "Doc richness check").
Before proceeding to issue mutation, verify plan-review and plan-wrap have each been run on the target plan. Accept evidence such as a checkpoint entry or Status: DONE on the corresponding review steps. If evidence for either gate is absent, emit a WARNING naming the missing prerequisite evidence and halt unless the operator supplied the explicit --force flag. Do not silently skip prerequisite gates.
gh resolves the target repo from cwd by walking up to the nearest
.git/. The dev/ workspace root is itself a git repo with its own
remote (aberson/coding-root), so running gh from dev/ silently
lands on aberson/coding-root instead of the intended project
subdirectory. Resolve and echo the repo before any mutating call:
cd <absolute-project-dir>
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name)
echo "Target repo: $REPO (default branch: $DEFAULT_BRANCH)"Confirm the printed Target repo: matches the intended project. If it
does not, stop — the cwd is wrong.
$DEFAULT_BRANCH is the <default-branch> placeholder every body
template below interpolates into its ../blob/<default-branch>/ doc
links. Resolve it — never assume. GitHub has defaulted new repos to
main since 2020, so a hardcoded master 404s every minted build-doc
link, and a hardcoded main merely inverts the same defect for a repo
that genuinely still uses master. When the build doc lives in a
DIFFERENT repo than the issues (a cross-repo plan), resolve that repo's
branch instead — gh repo view <owner>/<repo> --json defaultBranchRef -q .defaultBranchRef.name — because the link must resolve against the repo
that actually hosts the doc.
Wrong-directory guard: before this gh issue sync, warn if the resolved target project repo != the repo
ghresolves from cwd's remote (advisory, never blocks) — per working-directory.md § Wrong-directory guard; reference implTest-WrongDirGuard.
For every subsequent gh call in the run, pass -R <owner>/<repo>
defensively so cwd-resolution cannot drift mid-run:
gh -R aberson/Alpha4Gate issue create ...
gh -R aberson/Alpha4Gate issue list ...Equivalent fix: cd into the project subdirectory before invoking
gh (e.g., cd Alpha4Gate && gh ...). The -R flag is preferred
because it survives mid-run cwd changes.
Read --plan. If --phase not specified, infer from filename
(phase-d-build-plan.md → D; phase-9-build-plan.md → 9;
improve-bot-evolve-plan.md → check # Phase X ... H1 in content).
Extract:
- Umbrella metadata: title (from
# <H1>), goal, prerequisites, effort, kill criterion, validation - Step list: every step matching one of the supported formats
For each step, capture from per-step subsections if present:
Problem/What to buildFiles/Files to modify/Files touchedExisting contextDone when/AcceptanceFlags(build-step flags like--reviewers code --isolation worktree)Depends onProduces
If steps are table-only (sparse), flag this and run the richness check (below).
For each step, count populated rich-fields out of 6: {Files, Done when, Flags, Existing context, Produces, Depends on}.
- Rich step: ≥ 3 fields populated
- Lean step: ≤ 2 fields populated
If >50% of steps are lean:
WARNING: <plan> has N of M lean steps (only title + description).
Issues created from lean steps will be lean too. Every fresh-context
LLM session that opens those issues will need to drill into the build
doc or source code for context the issue body should have.
Per the LLM-effectiveness principle (memory:
feedback_optimize_for_llm_over_human_noise.md), the recommendation is:
1. Enrich the build doc first with per-step Files / Done when /
Flags / Existing context sections.
2. Then re-run this skill (or run with --enrich for an existing
issue set).
Continuing — issue bodies will reflect the plan's current shape.
Operator can re-run /repo-sync after enriching the plan if higher-
fidelity issues are needed.
Surfacing this cost is mandatory; the warning is a printed observability
note that proceeds automatically without prompting. The operator can
re-run /repo-sync after enriching the plan when richer issues are
needed — but no halt mid-sync.
# jq requires POSIX classes — no \d / \w / \s / \. (see Common mistakes § Perl-style regex escapes)
gh issue list --state all --limit 200 --json number,title,body,state \
--jq '.[] | select(.title | test("^Phase [A-Z0-9]+([.][0-9]+)?( Step [0-9]+)?:|^Phase [A-Z0-9]+([.][0-9]+)? — "))'This regex matches both umbrella titles (Phase X — ...) and step
titles (Phase X Step N: ...) across numeric, letter, and sub-phase
numbering. Falls through to the legacy (Phase \d+ )?Step \d+: if the
new pattern returns nothing (back-compat).
When a repo holds issues from multiple plans, step keys
(Phase X Step N) collide and a new plan's step may match a
stale issue belonging to an unrelated, possibly closed prior
plan.
The disambiguator is the body footer /repo-sync writes.
There are TWO footer shapes — both encode the source-plan
path and the parser must recognize both. In the rendered
issue body the plan path is a markdown link (square-bracket
label wrapping the path, parenthesis URL ../blob/<default-branch>/
plus that same path) so the path is clickable from the
GitHub issue — never a code-spanned path followed by a
parenthetical "linked to" phrase.
- Create path (see Body template — step):
*Synced fromby /repo-sync at <git-short-sha>*(with<plan>rendered as the markdown link described above). - Enrich / update path (see Update / enrich):
*Enriched by /repo-sync from <build-doc-path> @ <git-short-sha>*
Long-lived issues that have been re-synced carry the second shape; the parser must match both or every previously enriched issue falls through as "footer missing" — exactly the issues most likely to be cross-plan-colliding.
Regex shapes the parser must match:
- Create:
Synced from \[(.*?)\] - Enrich:
Enriched by /repo-sync from (.+?)( @ |$)
Algorithm: for each issue that matched a plan step in the
Step 3 fetch above, parse the footer's plan path from the
issue body — from EITHER Synced from [<plan>] OR
Enriched by /repo-sync from <build-doc-path>. If that plan
path differs from the current --plan argument's path,
classify the match as a CROSS-PLAN COLLISION (the issue
belongs to a different plan; the step key collision is
incidental).
Action: emit a WARN: cross-plan collision line in the
Step 5 preview output for each collision. No halt —
autonomous default still executes; the operator sees the
warning in the preview but the run proceeds without
prompting. Collided issues are excluded from ENRICH /
REOPEN candidate lists (treat as stale w.r.t. this plan).
Example warning line in the preview:
WARN: cross-plan collision — issue #123 "Phase D Step 3: foo"
plan footer: documentation/old-plan.md
--plan arg: docs/archived-plans/repo-sync-improvements-plan.md
classify as: stale (do not ENRICH, do not REOPEN)
Footer-absent issues (legacy or hand-authored) cannot be
classified by this check; fall through to the existing
title-prefix match behavior. Add (footer missing) to the
preview note so the operator knows the check could not run
on that issue.
Always-surface contract. The rendered Step 3.1 output MUST state the two recognized footer shapes explicitly — even when no existing issues were matched in Step 3. This makes the parser's footer-aware classification visible and auditable in every run, not only runs that exercise it.
Required Step 3.1 header line in the rendered output:
Footer shapes recognized:
Create: Synced from [<plan>](...)
Enrich: Enriched by /repo-sync from <build-doc-path> @ <sha>
When no issues were matched, follow with (no existing issues to classify). When issues exist, list each with its
footer plan path or (footer missing) per the algorithm
above. Either way, neither footer shape is omitted from the
output, so enriched-path issues are never silently treated
as footer missing.
Match plan entries to existing issues by title prefix:
- Umbrella:
Phase X — <anything>matches plan's H1 phase - Step:
Phase X Step N: <anything>matches plan stepX.NorStep Nwithin the phase
Classify into buckets:
| Bucket | Condition | Default action |
|---|---|---|
| CREATE umbrella | Plan has phase, no umbrella issue | Create with full body |
| CREATE step | Plan step has no matching issue | Create with rich body |
| ENRICH | Issue exists, body is lean (≤2 sections), plan now has richer content | Update body (auto if --enrich OR if plan has clear new fields) |
| UPDATE | Issue exists but title or body changed substantively | Update |
| CLOSE | Issue exists, plan step removed | Close with comment |
| NO-OP | Issue exists, body is rich, no plan change | Skip |
Print all proposed changes grouped by phase:
repo-sync: documentation/plans/phase-d-build-plan.md (Phase D)
Build doc richness: 3/8 steps rich, 5/8 lean
CREATE umbrella Phase D — Build-order z-statistic (reward refactor)
CREATE step Phase D Step 1: Audit reward_rules.json (rich body)
CREATE step Phase D Step 2: Define z schema (rich body)
CREATE step Phase D Step 3: build_order_reward.py (lean — Files missing)
ENRICH Phase D Step 5 (#168) — body lacks Done when + Files
UPDATE Phase D Step 7 (#170) — title changed
CLOSE (none)
NO-OP (none)
If --dry-run was specified, stop here and print:
Dry-run complete. No changes applied.
Otherwise, proceed directly to Step 6 — print Applying changes now...
and execute. Do not prompt for confirmation. The preview is the
operator's read-out, not a halt point; autonomous orchestration
(/build-phase, /plan-expedite) depends on this.
When /repo-sync --dry-run is invoked, the preview above is printed but
no changes are applied. The skill exits cleanly with the message
Dry-run complete. No changes applied. Use this to validate plan→issue
mapping before committing to a sync.
Process in this order:
- Umbrella issues first (so step issues can reference them)
- Step issue creates
- Step issue enrichments + updates
- Closes last
Each gh issue create/edit/close is its own Bash tool invocation, OR a
loop in one Bash with explicit per-iteration error handling. Do NOT
batch with && — one failure must not break the chain.
All gh issue create/edit calls in this skill MUST deliver bodies via --body-file <path>, never inline --body "$(cat <<EOF ... EOF)". The inline heredoc form silently truncates or parser-tangles bodies that contain nested quote levels (code spans, quoted text, tables) — see dev/.claude/rules/windows-shell.md § gh / jq.
Use a Windows-safe temp path:
- Bash:
$LOCALAPPDATA/Temp/(e.g.C:/Users/<user>/AppData/Local/Temp/) - PowerShell:
$env:TEMP
POSIX /tmp/ is invisible to gh.exe on Windows (different temp roots).
The Create / Update / Close templates below all assume this delivery method.
**Umbrella:** #<master-plan-umbrella-issue-if-exists>
**Blocked by:** Phase <prerequisite-phase-if-any>
**Build doc:** `<build-doc-path>` (linked to `../blob/<default-branch>/<build-doc-path>`)
**Track:** <track-from-plan>
## Goal
<goal paragraph from plan>
## Work (N steps)
- [ ] **#<step-1-issue>** Step 1: <name>
- [ ] **#<step-2-issue>** Step 2: <name>
...
(Step issue numbers populated after step creates — re-edit umbrella in Step 7.)
## Acceptance
<validation / acceptance from plan>
## Effort
<effort estimate from plan>
## Kill criterion
<kill criterion from plan>## Build step N of M — Phase <X> (umbrella #<umbrella-issue>)
**Build doc:** `<build-doc-path>` (linked to `../blob/<default-branch>/<build-doc-path>`) §<section> Step <X.N>
### What to build
<full description from plan, not abbreviated>
### Existing context
<from plan's "Existing context" section if present, scoped to this step>
<otherwise: omit (will be flagged in summary)>
### Files to modify/create
<file list from plan if present>
<otherwise: omit (flagged in summary)>
### Done when
<acceptance from plan, specific not generic>
<otherwise: "All tests green, mypy strict + ruff clean. See umbrella for phase-level gate.">
### Flags (recommended)
<build-step flags from plan if present, e.g. `--reviewers code --isolation worktree`>
<if step touches frontend/, /api/ shapes, or WebSocket payloads: ALSO include `--ui`>
### Depends on
<previous step issue # if known, or "none">
### Parallel-safe with
<list any open step issue # in the same phase that shares no Files and no
Depends-on with this step. When no such peers exist, write
`none — strictly sequential (<one-line justification>)`. The justification
is REQUIRED — bare "strictly sequential" without a reason hides the
choice from the operator. Acceptable justifications: "Step N+1 imports
this module", "shares <Files entry> with #X", "soak gate after Step N
must finish first". When the plan is lean (no Depends on, no Files
declared), default to listing peers as parallel-safe rather than
collapsing to strictly sequential.>
### Produces
<list from plan if present>
### Operator workflow notes (autonomous + UI-bundle + parallel)
- This step is intended to run end-to-end via `/build-step` without
mid-iteration check-ins; the `Done when` above is the verification gate.
- If `--ui` is in the Flags line above, UI evidence (Playwright screenshot,
or any project-specific UI/dashboard smoke commands defined in the
project's `CLAUDE.md`) is part of acceptance, not a follow-up.
- Parallel-safe pairs above can be dispatched in parallel worktrees by
`/build-phase`.
---
*Synced from `<plan>` (linked to `../blob/<default-branch>/<plan>`) by /repo-sync at <git-short-sha>*The footer with the source path + SHA helps a future LLM verify whether the issue body is current vs the build doc.
Sections without source content can be omitted, but **issues missing
2 of {Existing context, Files, Done when, Flags, Produces} are flagged in the summary** as candidates for follow-up enrichment.
# Windows-safe temp path; POSIX /tmp/ is invisible to gh.exe.
BODY_FILE="$LOCALAPPDATA/Temp/repo-sync-issue-$NUMBER.md"
cat > "$BODY_FILE" << 'BODYEOF'
<full new body following template>
---
*Enriched by /repo-sync from <build-doc-path> @ <git-short-sha>*
BODYEOF
gh issue edit <NUMBER> --title "<title>" --body-file "$BODY_FILE"
rm "$BODY_FILE"gh issue close <NUMBER> --comment "Closed by /repo-sync — step removed from plan."After step issues are created, edit each phase's umbrella issue to include the Work checklist with actual issue numbers:
## Work (N steps)
- [ ] **#164** Step 1: Audit reward_rules.json
- [ ] **#165** Step 2: Define z schema
...This creates bidirectional cross-refs that an LLM can follow either
direction. Without this, the umbrella has stale <step-1-issue>
placeholders or a generic (steps will be cut by /repo-sync) note,
which forces the LLM to do a separate gh issue list to find them.
The final line of the report MUST surface this skill's plan-pipeline
position — step 4 of 5: after /plan-review + /plan-wrap, before /build-phase — so the operator and any fresh-context downstream LLM
see at a glance what runs next. The breadcrumb is non-optional.
repo-sync complete for Phase D (umbrella #114)
Plan pipeline: /plan-review + /plan-wrap → /repo-sync (step 4 of 5) → /build-phase
Created: 1 umbrella, 8 step issues (#164–#171)
Enriched: 0
Updated: 0
Closed: 0
Body richness: 3/8 issues fully rich; 5/8 missing Files/Existing-context
Cross-refs: umbrella #114 updated with step issue links
Recommendation: build-doc step richness was lean (5/8). Consider
enriching documentation/plans/phase-d-build-plan.md with explicit
per-step Files / Done when / Existing context sections, then
re-run with --enrich to bring issues to richer state.
The /build-phase next-step runs in the project repo (the Step 0 target), so name it:
Next: /build-phase --plan <plan> — run in <absolute-project-dir>.
Next-step commands name their target directory, and the proactive project-switch message fires on a cwd≠project mismatch with no pin, per transition-directory-contract.md.
If new issues were created, the operator (or the orchestrator)
backfills the plan's **Issue:** lines so /build-phase can post
progress updates — e.g., via the pattern below. The skill itself
does not back-propagate; surfacing the pattern is enough for the
operator to run once after sync.
Copy-paste bulk-fill snippet (Python). Adapt the ISSUE_MAP from
the sync output's "Created" / "Enriched" mapping:
# Backfill **Issue:** #N lines after /repo-sync.
# Save the sync output's "Created" or "Enriched" mapping as
# {step_number: issue_number}, e.g.:
ISSUE_MAP = {
1: 164, # Step 1 -> issue #164
2: 165,
# ...
}
import re, pathlib
# REPLACE <plan-file> with your plan's actual filename,
# e.g. "documentation/phase-rs-plan.md".
plan = pathlib.Path("documentation/<plan-file>")
text = plan.read_text(encoding="utf-8")
for step_n, issue_n in ISSUE_MAP.items():
# Match Step N heading, then the immediately-following
# **Issue:** line (which may be #N, TBD, or empty).
# No re.DOTALL: `.` does not match newlines, so `.*?\n`
# stays within a single line and the bullet-eater group
# matches only consecutive single-line bullets. If a step
# is missing its **Issue:** bullet entirely, the pattern
# fails to match for that step and the script safely skips
# it (no cross-step contamination).
# The `(?:- )?` makes the list-bullet prefix OPTIONAL: plans
# use BOTH `- **Issue:**` and bare `**Issue:**` styles, and a
# bullet-only pattern silently substitutes NOTHING on a
# bare-style plan (re.subn count=0 looks like success).
pattern = (
rf"(### Step {step_n}:.*?\n(?:(?:- )?\*\*[^*]+\*\*.*?\n)*?"
rf"(?:- )?\*\*Issue:\*\* )(#\d+|TBD|)"
)
text = re.sub(pattern, rf"\g<1>#{issue_n}", text)
plan.write_text(text, encoding="utf-8")Verification — after a fully-populated backfill, the following
returns empty (no remaining TBD or blank **Issue:** values).
REPLACE <plan-file> with your plan's actual filename:
grep -nE "Issue:\*\*\s*(TBD\s*$|#\s*$|$)" documentation/<plan-file>This pattern is one instance of the broader bulk-placeholder-fill
discipline (see feedback_bulk_placeholder_fills.md). Background
and rationale in investigation
docs/investigations/skill-deep-dives/repo-sync/03-issue-blank-lines-kill-build-phase.md.
Issue matching is prefix-based on the step key. The skill normalizes:
- Whitespace
- Phase notation:
Phase D≡Phase D(no normalization across letter/digit; B != 2; D != 4) - Sub-phase:
Phase G.2 Step 1matches planG.2.1orStep 1within phase G.2
Manually renamed issue titles still match as long as the step prefix
(Phase X Step N or Phase X.M Step N) is preserved.
- Cross-plan step-key collision: Step keys collide when a
repo holds issues from multiple plans (
Phase D Step 3exists in plan A and plan B). The Step 3.1 check (see Flow) flags these via the body footer's plan path. Workaround for new plans that share step keys with closed prior plans: bypass/repo-syncfor the new plan and create issues manually with namespaced titles (<feature> — Phase X Step N: <name>); those manual issues will not be re-matched by future runs. See investigationdocs/investigations/skill-deep-dives/repo-sync/01-step-key-collision.md. - Closed issue, step still in plan: Log it as an informational note in the sync report and skip mutation (do not reopen, do not prompt). The operator can reopen manually if needed.
- Multiple issues match same step key: Warn and skip — user must resolve manually.
- Plan has no umbrella H1, just steps: Skip umbrella creation; only step issues.
- No steps found: Error:
No steps found in <path>. Expected "### Step N:", "### Phase X Step N:", or "| X.N | ... |" table row. - No GitHub repo: See Step 0 — Pre-flight. The resolve command halts early if no repo is found.
- Numbering gaps: If plan jumps from Phase 7 to Phase 9 (intentional), don't try to create Phase 8. Honor the plan as written.
- Existing umbrella, plan adds new steps: Create new step issues + re-edit umbrella to add their links.
- Step issue exists but lean, build doc still lean: ENRICH would be a no-op. Recommend doc enrichment in summary; do not edit issue.
Batching gh calls in one shell command
- Fix: One
gh issue create/edit/closeper call, separate Bash tool invocations OR a loop in one Bash with explicit per-iteration error handling.
Halting mid-sync for confirmation
- Fix: Preview-then-execute is the default; no
(y/n)prompt. Operators who want preview-only behavior pass--dry-run. Autonomous orchestrators (/build-phase,/plan-expedite) depend on this — a mid-sync halt breaks them.
Matching by issue number instead of title prefix
- Fix: Issue numbers change. Always match by the step-key prefix in the title.
Using Perl-style regex escapes in --jq filters
-
Fix: jq's regex engine does NOT accept
\d,\w,\s,\.(and most other Perl-style shorthand). It silently rejects the filter or returns empty matches — failing the classification, which then surfaces as duplicate-issue CREATEs in Step 5 preview. Use POSIX classes or literal character sets:Avoid Use \d[0-9]\w[a-zA-Z0-9_]\s[ \t\n\r](POSIX whitespace; or the named class with single-bracket pairs the engine supports)\.[.]Prefer regex-free forms when the prefix is fixed:
startswith("Phase D")beatstest("^Phase D")and sidesteps the escape limit entirely.Reference:
feedback_jq_regex_escape_limits.mdand investigationdocs/investigations/skill-deep-dives/repo-sync/13-jq-regex-escaping.md. PowerShell-specific quoting issues forgh -qare documented indev/.claude/rules/windows-shell.md§ gh / jq.
Lean bodies on creation
- Fix: Run the doc richness check first. If steps are lean, propose enriching the build doc before creating issues. Don't normalize lean issues as the steady state.
Forgetting umbrella back-references
- Fix: After creating step issues, edit the umbrella to include the Work checklist with issue numbers. Bidirectional links matter.
Ignoring sub-phase notation
- Fix: Phase G.2 is its own phase, not "Phase G". Match titles accordingly.
Skipping the doc-richness warning
- Fix: A lean issue taxes future LLM sessions every time someone opens it. Surface this cost explicitly; default to enriching the doc first.
Treating issue creation as one-shot
- Fix:
--enrichexists because issues drift behind build docs over time. Re-run the skill after each plan revision.