Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 26 additions & 18 deletions claude-skills/publish-release/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: publish-release
description: Publish a new versioned release. Opens a version bump PR to develop, merges it, promotes develop to main via PR, tags main, and triggers the release pipeline.
description: Publish a new versioned release. Opens a version bump PR to develop, merges it, promotes develop to main via CLI --no-ff merge (never a GitHub PR), tags main, and triggers the release pipeline.
---

Publish a new release based on the user's request: $ARGUMENTS
Expand Down Expand Up @@ -41,35 +41,43 @@ gh pr create \
--base develop \
--head chore/release-v<version> \
--title "chore: release v<version>" \
--body "Version bump to v<version>. Merge to proceed with the develop→main release PR."
--body "Version bump to v<version>. Merge to proceed with the develop→main CLI release merge."
```

Show the user the PR URL. Wait for CI to pass, then ask them to approve and merge it.

## Step 2 — Promote develop → main
## Step 2 — Promote develop → main via CLI merge

After the version bump PR is merged, open the developmain release PR:
After the version bump PR is merged, promote develop to main with a non-fast-forward merge from the command line.

```bash
git checkout develop && git pull

gh pr create \
--base main \
--head develop \
--title "chore: release v<version>" \
--body "Promotes develop to main for release v<version>.
> **Do NOT use a GitHub PR for this step.** GitHub's merge button squash-merges by default, which flattens every commit on develop into a single new commit on main with no ancestry relationship. On the next release, main and develop have diverged at every commit and every subsequent release hits merge conflicts. A `--no-ff` CLI merge preserves the commit graph so main remains a strict ancestor of develop.

After merging, the tag will be pushed to trigger the release pipeline."
```bash
git fetch origin
git checkout main && git pull
git merge --no-ff origin/develop -m "chore: release v<version>"
git push origin main
```

Show the user the PR URL and ask them to approve and merge it.
Confirm the push succeeded before moving to Step 3.

## Step 3 — Tag main after merge
> **Branch protection note:** if `main` has `enforce_admins: true` and required-PR review, the CLI push will be rejected. Toggle protection around the push:
>
> ```bash
> # Disable bypass-prevention temporarily
> gh api -X DELETE repos/<owner/repo>/branches/main/protection/enforce_admins
>
> # ...do the merge and push above...
>
> # Re-enable
> gh api -X POST repos/<owner/repo>/branches/main/protection/enforce_admins
> ```
>
> The `amcheste-ai-agent` GitHub App needs `Administration: Read & Write` permission on the install for these toggles. The same dance applies to the `v*` tag ruleset in Step 3 if tag creation is restricted — toggle the ruleset's enforcement to `disabled` around the tag push, then back to `active`.

After the user confirms the develop→main PR is merged:
## Step 3 — Tag main

```bash
git checkout main && git pull
git tag -a "v<version>" -m "Release v<version>"
git push origin "v<version>"
```
Expand All @@ -89,5 +97,5 @@ Show the user the release pipeline URL and confirm the tag was pushed. Let them
Tell the user:
- What version was tagged on `main`
- That the pipeline is running: validate → VM acceptance → publish
- Where to watch it: `https://github.com/amcheste/mac-dev-setup/actions`
- Where to watch it: `https://github.com/amcheste/<repo>/actions`
- That `main` now equals the new release and `develop` is ready for the next cycle
44 changes: 41 additions & 3 deletions claude-skills/setup-repo/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: setup-repo
description: Apply standard branch model, protection rules, and settings to a GitHub repository. Creates develop branch, sets it as default, protects develop and main, and adds tag protection.
description: Apply standard branch model, protection rules, and settings to a GitHub repository. Creates develop branch, sets it as default, protects develop and main, adds tag protection, and verifies CODEOWNERS routing.
---

Configure a GitHub repository with the standard branch model and protection rules: $ARGUMENTS
Expand All @@ -13,7 +13,17 @@ Extract from the user's message:
## Pre-flight

1. Verify the repo exists: `gh repo view <owner/repo>`
2. Show the user what you're about to do and confirm before making any changes
2. **Refuse forks.** `setup-repo` configures the conventions of the *owner* of the repo. A fork is owned by upstream's conventions, not yours — applying your branching model, protections, and CODEOWNERS to it is wrong:

```bash
if [ "$(gh repo view <owner/repo> --json isFork --jq .isFork)" = "true" ]; then
echo "ERROR: <owner/repo> is a fork. setup-repo follows your conventions; forks follow upstream's. Aborting."
exit 1
fi
```

This also applies to audit scripts that survey "all my repos" — use `gh repo list --source` (filters out forks) instead of plain `gh repo list` so forks don't surface in the report.
3. Show the user what you're about to do and confirm before making any changes

## Step 1 — Ensure develop branch exists

Expand Down Expand Up @@ -126,19 +136,47 @@ gh api repos/<owner/repo>/rulesets \
EOF
```

## Step 6 — Verify CODEOWNERS routing

Bot-authored PRs (via the `amcheste-ai-agent` GitHub App) need
`.github/CODEOWNERS` to auto-route review requests to a human reviewer.
Without this file, App-authored PRs don't appear in any reviewer's
queue (Graphite, GitHub's review-requested filter, etc.) and get lost.

```bash
gh api repos/<owner/repo>/contents/.github/CODEOWNERS >/dev/null 2>&1 \
&& echo "✓ CODEOWNERS exists" \
|| echo "⚠ CODEOWNERS missing"
```

If the file is missing, **do not write it directly** — `setup-repo` only
configures settings/rulesets, never commits to the repo. Instead, surface
the gap in the summary so the user can add it via a PR. The canonical
default content is:

```
# See https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
* @amcheste
```

This pairs with the bot-account model documented in the
[engineering handbook](https://github.com/amcheste/engineering-handbook/blob/main/docs/design/claude-bot-account.md).

## Summary

Report what was configured:
Report what was configured (and any gaps that need a follow-up PR):

```
✓ develop branch created (or already existed)
✓ develop set as default branch
✓ develop protected — require PR + [checks]
✓ main protected — require PR + [checks]
✓ Tag ruleset active — v* tags protected
✓/⚠ CODEOWNERS verified (or: CODEOWNERS missing — see follow-ups)

Next steps:
- If using repo-template: copy .github/ files into this repo
- Add project-specific lint/test steps to .github/workflows/validate.yml
- Update required status check names to match your workflow job names
- If CODEOWNERS was missing, open a PR adding `.github/CODEOWNERS` with `* @amcheste`
```
Loading