Repo Bootstrap
The release-branch composites (/pr-to-release, /release-cut, /hotfix,
/dep-sweep, /first-pr, /branch-hygiene) all assume the repo is already
configured for the model — a release branch on origin, a [Unreleased]
changelog section, sensible defaults at .claude/*-config.json. Without that,
the first composite invocation fails or makes uninformed defaults stick.
This composite does the setup once, idempotently.
When this fires
- User says "bootstrap this repo", "set up release branch", "new repo setup", "configure release workflow", "make this repo work with /pr-to-release"
- Auto-suggest on the first session in a repo where:
git ls-remote --heads origin releasereturns empty AND.claude/directory is missing OR has no config files
- Queued by
/first-prPhase 0 if the repo is not yet bootstrapped - After
git init+ first push to origin
If the repo is not a git repo: exit with
repo-bootstrap skipped: not a git repository.
If the repo has no origin remote: surface as a blocker and refuse — the
release branch must exist on a remote to be useful.
Workflow
Phase 1 — Detect state (always)
Probe without writing:
git remote get-url origin # must succeed
git symbolic-ref refs/remotes/origin/HEAD --short # default branch (e.g. origin/main)
git ls-remote --heads origin release # release branch presence
test -f CHANGELOG.md && echo has-changelog
test -d .claude && echo has-claude-dir
test -f .claude/dep-sweep-config.json && echo has-dep-sweep
test -f .claude/branch-hygiene-config.json && echo has-branch-hygiene
test -f .claude/standards/release-cadence.md && echo has-release-cadence
Record into a detection summary. Every later phase reads this and skips if its artifact already exists — idempotency is the contract.
Phase 2 — Create release branch on origin (skip if exists)
git fetch origin
git push origin "origin/$(default_branch):refs/heads/release"
Where default_branch is main or whatever Phase 1 detected. Refuse if the
default branch has zero commits (empty repo) — surface as
(blocked: default branch has no commits yet — push initial commit first).
Do NOT check out the release branch locally. The model is push-only from the
local default branch via /pr-to-release.
Phase 3 — Seed CHANGELOG.md (skip if exists)
Create at repo root:
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
### Changed
### Fixed
### Removed
### Security
If CHANGELOG.md exists but has no [Unreleased] section, do NOT rewrite it —
flag as (skipped: CHANGELOG.md exists but lacks [Unreleased] — manual review needed). /pr-to-release requires the section; this is the user's call.
Phase 4 — Seed .claude/dep-sweep-config.json (skip if exists)
Create .claude/ if missing. Then:
{
"base_branch": "release",
"sensitive": [],
"always_hold": ["react", "next", "vue", "svelte", "@types/node"],
"auto_merge_minor": false,
"auto_merge_dev_deps": true
}
sensitive defaults to empty — the user fills it per-repo (e.g.,
["stripe", "@aws-sdk/*"]). The pattern is conservative: dev-deps auto-merge,
minors hold for review, framework packages always hold.
Phase 5 — Seed .claude/branch-hygiene-config.json (skip if exists)
{
"worktree_root": "$HOME/.worktrees",
"stale_pr_threshold_days": 7,
"protect_branches": ["main", "master", "release", "develop", "staging"],
"skip_phases": []
}
The worktree_root reflects the user's storage policy. If the user is on a
machine without External HD mounted, the path is still recorded — /branch-hygiene
will skip the orphan-sweep phase at runtime.
Phase 6 — Stub .claude/standards/release-cadence.md (skip if exists)
# Release Cadence — <repo>
How this repo ships.
## Model
Long-lived `release` branch on origin. New work lands on `release` via
`/pr-to-release`. Versions are NOT cut per-PR — they are batched by
`/release-cut` when enough has accumulated.
## Cadence triggers
- Manual: user invokes `/release-cut`
- Nudge: when `git rev-list --count main..release` ≥ 5 commits
- Hotfix exception: `/hotfix` bypasses the release branch and cuts a patch
immediately, then cherry-picks back to release
## What goes in each version
- Patch: bug fixes, dependency patches, no behavior change
- Minor: new features, backward-compatible changes
- Major: breaking changes — requires migration notes in the CHANGELOG entry
## Bot PRs
`/dep-sweep` handles Dependabot/Renovate/pre-commit-ci. See
`.claude/dep-sweep-config.json` for the rules.
## Hotfix policy
Only acceptable bypass of `release` is `/hotfix`. Criteria documented in
~/.claude/skills/hotfix/SKILL.md. Routine "small fix" work belongs on the
release branch.
Replace <repo> with the directory name from basename $(git rev-parse --show-toplevel).
Phase 7 — Open chore/repo-bootstrap PR (always, if any artifact was created)
If at least one phase 2–6 produced a change:
git switch -c chore/repo-bootstrap
git add CHANGELOG.md .claude/
git commit -m "chore: bootstrap release-branch workflow
Adds CHANGELOG.md, dep-sweep + branch-hygiene config, release-cadence standard.
Release branch was pushed to origin separately (does not require this PR to merge)."
git push -u origin chore/repo-bootstrap
gh pr create --base "$(default_branch)" --title "chore: bootstrap release-branch workflow" \
--body "$(bootstrap_pr_body)"
PR body must list every artifact created (or skipped + reason). This is the audit trail for the bootstrap.
If gh is unavailable: push the branch and emit the gh pr create command in
the reconciliation block for the user to run manually.
Phase 8 — Verify (always)
After Phase 7 (or after a fully-idempotent no-op run), re-probe:
git ls-remote --heads origin releasemust return a SHACHANGELOG.mdmust contain a literal## [Unreleased]line- Each config file must parse as valid JSON
Record verification results in the reconciliation block. A failed verification on a fresh bootstrap is a hard error — surface and stop.
Reconciliation block (mandatory output)
REPO-BOOTSTRAP — <repo>
Detection: default-branch=<name>, release=<exists|missing>, changelog=<exists|missing>, .claude/=<state>
Release branch: created | (skipped: already exists) | (blocked: <reason>)
CHANGELOG.md: created | (skipped: exists with [Unreleased]) | (skipped: exists, lacks [Unreleased] — manual review)
dep-sweep config: created | (skipped: exists)
hygiene config: created | (skipped: exists)
release-cadence: created | (skipped: exists)
PR: <url> | (skipped: no changes) | (manual: run `gh pr create ...`)
Verify: release-on-origin ✓, [Unreleased] ✓, configs-parse ✓
Snapshot: (none — bootstrap is terminal)
Open watch: (none) | <follow-up if Phase 3 flagged manual changelog review>
Stop conditions
- Not a git repo → exit immediately
- No
originremote → refuse with explicit message - Default branch has zero commits → block Phase 2; surface remediation
- Verification (Phase 8) fails after a write phase succeeded → hard error,
rollback the local branch (
git switch -+git branch -D chore/repo-bootstrap) if the PR push didn't happen yet; if the PR push did happen, leave it open and flag for manual fix
Idempotency contract
Running /repo-bootstrap twice on the same repo must:
- Not duplicate any file
- Not error on existing artifacts
- Produce a reconciliation block showing every phase as
(skipped: exists) - Exit clean with no PR opened (Phase 7 sees zero changes)
This property is what makes the composite safe to auto-suggest at session start — false positives cost nothing.
Negative rules
- Do NOT overwrite an existing CHANGELOG, config, or standard. Skip and flag instead. The user's existing content is canonical.
- Do NOT auto-merge the bootstrap PR. It's a setup-time change that benefits from human review even when mechanical.
- Do NOT check out
releaselocally. The model is push-only. - Do NOT touch
.gitignore, package.json, or any source code. Bootstrap is workflow configuration only — it never modifies the project itself. - Do NOT auto-queue another composite. Bootstrap is a one-shot setup; cascading from it would surprise the user.