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
115 changes: 115 additions & 0 deletions docs/plans/2026-04-30-bulk-install-smartwatermelon-fleet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Bulk-install script for existing smartwatermelon repos

Adds a script to this repo that installs (or refreshes) the `claude-blocking-review` caller workflow across all eligible repos under the `smartwatermelon` user account. Closes the gap left by GitHub's workflow-templates feature being **organization-only** — `smartwatermelon` is a user account, so `smartwatermelon/.github/workflow-templates/` is decorative; the templates never appear in the "New workflow" picker for `smartwatermelon/*` repos.

## Goal

A repeatable, idempotent way to roll the current pinned version (today: `@v3.0.0`) into every `smartwatermelon/*` repo that doesn't yet have it, without per-repo manual work.

## Non-goals

- Installing into archived repos.
- Installing into repos listed in `.claude-review-ignore`.
- Force-overwriting an existing caller workflow that's already on the pinned version (idempotent skip).
- Touching `nightowlstudiollc/*` — that's covered by [the org defaults plan](2026-04-30-create-nightowlstudiollc-github-defaults.md) plus the [org-wide enforcement plan](2026-04-30-required-workflows-nightowlstudiollc.md) (Repository Rulesets).

## Preconditions

- `gh` CLI authenticated as a user with write access to all targets.
- `claude-review-audit.sh` already exists in this repo and enumerates the fleet correctly. The new script reuses its repo-discovery logic.
- A canonical caller-stub file exists somewhere we can copy from. Two options (Phase 0 chooses):
- **A:** Pull from `smartwatermelon/.github/workflow-templates/claude-blocking-review.yml` at HEAD (single source of truth — same file the workflow-template feature would have used in an org).
- **B:** Inline the stub in the script itself.

Recommend **A** so the stub-and-the-script can't drift.

## Phases

### Phase 0 — Decide caller stub source and pin policy

- Confirm the canonical stub file path (`smartwatermelon/.github/workflow-templates/claude-blocking-review.yml`).
- Confirm pin policy: specific semver from the stub (e.g. `@v3.0.0`), not floating. Matches the release-strategy convention; lets Dependabot drive future bumps.
- If the stub references a tag that doesn't have a GitHub Release yet (currently true for `v3.0.0`), publish the release first so consumers have something to reference in their UI.

### Phase 1 — Write `bulk-install-claude-review.sh`

Lives next to `claude-review-audit.sh` at the repo root. Modeled on the audit script's repo-discovery + ignore-list handling.

Behavior:

1. Discover candidate repos: all non-archived repos owned by `smartwatermelon`, minus those in `.claude-review-ignore`.
2. For each candidate, classify state:
- **MISSING** — no `claude-code-review.yml` (or any equivalent) under `.github/workflows/`.
- **STALE** — present, but pin doesn't match the current target (`@v3.0.0`).
- **CURRENT** — present and on target. Skip silently.
- **CUSTOMIZED** — present, on target, but with non-trivial caller-side modifications (e.g. `paths-ignore`, `extra_instructions`). Skip with warning; flag for human review.
3. For MISSING repos: open a PR adding `.github/workflows/claude-code-review.yml` with the canonical stub. Branch name: `claude/install-blocking-review-<short-sha>`.
4. For STALE repos: open a PR bumping the pin. Branch name: `claude/bump-blocking-review-to-<target-version>`.
5. Report: per-repo status summary at end.

Idempotency: re-running the script when nothing's changed should produce zero PRs and a clean report.

Flags:

- `--dry-run` — classify and print intended action; open no PRs. **Default**.
- `--apply` — actually open PRs.
- `--only <repo>` — single-repo mode for testing.
- `--verbose` — verbose logging (matches audit script convention).

PR body should:

- Link to `github-workflows` release notes for the target version.
- Link to this plan.
- Include `[skip-claude-review: bulk-install]` in the body so the PR doesn't recursively trigger blocking review on itself before being merged.

### Phase 2 — Bellwether

Pick 2-3 actively-developed `smartwatermelon/*` repos (non-archived, recent commits) and run with `--apply --only <repo>`. Watch each PR through CI before continuing.

Acceptance for moving to Phase 3:

- Bellwether PRs CI-green.
- Caller stub renders correctly (no schema errors).
- The `claude-review / run-review` check appears on subsequent PRs in the bellwether repos.

### Phase 3 — Fleet rollout

Run `--apply` against the full eligible set. Expect 5-15 PRs (most repos either already have it from prior `claude-review-audit.sh`-driven manual installs, or are in `.claude-review-ignore`).

Auto-merge: don't enable. Each install PR should land via the normal review path. If volume becomes a problem, this is where we'd consider scripted self-merge — but on a one-time rollout, manual review is fine.

### Phase 4 — Wire up Dependabot in newly-installed repos

Only matters for MISSING-class repos that didn't have `dependabot.yml` for `github-actions`. Defer this to a follow-up — same pattern that already shipped to existing fleet.

Two sub-options:

- **A:** Bundle Dependabot config into the install PR. Risk: makes the install PR more invasive.
- **B:** Separate "add github-actions Dependabot" PR after the install PR merges.

Recommend **B** — smaller, easier to review, and identical to the pattern used in Phase 4c of the v2 rollout playbook.

## Risks and rollback

| Risk | Mitigation |
|---|---|
| Free-tier repos silently reject parts of the install (per [github billing tier](../../../../../../Users/andrewrich/.claude/projects/-Volumes-extra-vieille-Workspaces-github-workflows/memory/github-billing-fleet.md) — not relevant for the install itself, but Phase 4 auto-merge wouldn't work) | Don't enable auto-merge on free-tier repos; surface the limitation in the report |
| Repo has bespoke caller workflow we don't recognize | CUSTOMIZED classifier flags it; human reviews |
| Repo branch protection blocks PR merge until checks pass — and `claude-review / run-review` is a required check that can't run yet because the workflow's not installed | The install PR adds the workflow; first run is on the install PR itself. Tested in bellwether. If branch protection wedge happens, temporarily relax via gh API |
| `.github/workflows/claude-code-review.yml` filename clashes with an existing unrelated workflow | Classifier checks for *any* file referencing `smartwatermelon/github-workflows/.github/workflows/claude-blocking-review.yml@`, not just the canonical filename |

Rollback: PR-based, so `gh pr close --delete-branch` per-PR if needed. No commits to main.

## Acceptance criteria

- Script lives at `bulk-install-claude-review.sh` in repo root.
- Shellcheck (`-S info`) clean, including no `# shellcheck disable` directives.
- `--dry-run` is default and produces no side effects.
- Re-running after a successful rollout produces an all-CURRENT report.
- README updated with a "Bulk install" section pointing at the new script.
- Audit script (`claude-review-audit.sh`) updated if its CURRENT-version constant moves to `@v3.0.0`. (Verify both scripts read from the same constant or comment-block to prevent drift.)

## Open questions

- Should the canonical stub source be the `.github` repo, or should we move it into this repo (e.g. `templates/claude-code-review.yml`) and have `.github` reference *this* repo as the source? Slight DX win — keeps everything about this tool in one repo. Decide in Phase 0.
- Do we want a parallel `bulk-uninstall` mode for emergencies (mass-remove the workflow if a v4 has a critical bug)? Probably not — the existing `[skip-claude-review]` escape hatch already lets individual PRs bypass without removal. Skip unless evidence demands it.
127 changes: 127 additions & 0 deletions docs/plans/2026-04-30-create-nightowlstudiollc-github-defaults.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Create `nightowlstudiollc/.github` with org-level defaults

`nightowlstudiollc` is an actual GitHub organization (team plan, 9 private repos, created 2026-01-22) — unlike `smartwatermelon`, which is a user account. This means the full `.github` community-defaults + workflow-templates feature set works, including the **workflow picker** that surfaces stub workflows in "Actions → New workflow" for every repo in the org.

## Goal

Stand up `nightowlstudiollc/.github` mirroring the structure of `smartwatermelon/.github`, so:

1. New repos in the org get FUNDING.yml, profile/README.md, and dependabot config fallbacks automatically.
2. The Claude blocking review and Dependabot auto-merge templates appear in the Actions picker for every repo in the org.
3. The `claude-review-audit.sh` script (which already audits both orgs) stays accurate as templates spread.

This addresses the "new repos automatically inherit" half of the original question for the org side. Existing repos still need bulk-install (separate plan).

## Non-goals

- Forcing the workflow on every repo (that's the [org-wide enforcement plan](2026-04-30-required-workflows-nightowlstudiollc.md) using Repository Rulesets — separate decision).
- Mirroring **everything** from `smartwatermelon/.github`. Only mirror what's still load-bearing — drop or refresh anything stale.

## Preconditions

- Org admin access to `nightowlstudiollc`.
- `CLAUDE_CODE_OAUTH_TOKEN` already provisioned at the org level, OR plan to add it during this rollout. Check before starting: `gh secret list --org nightowlstudiollc`.
- The `smartwatermelon/.github` template fix (PR currently open at `smartwatermelon/.github#7`) merged. The mirror should land at `@v3.0.0`, not stale `@v2.0.1`.

## Phases

### Phase 0 — Inventory and decisions

- Enumerate what's in `smartwatermelon/.github`:
- `.github/FUNDING.yml`
- `.github/dependabot.yml`
- `.github/workflows/claude.yml` ← only applies to the .github repo itself
- `profile/README.md`
- `workflow-templates/claude-blocking-review.yml` + `.properties.json`
- `workflow-templates/dependabot-auto-merge.yml`
- Decisions to make before creating files:
- **FUNDING.yml** — does NightOwl Studio want sponsor links visible on every public repo? Probably no for an LLC. Either omit or include with appropriate links. Default: omit.
- **profile/README.md** — yes, this becomes the org landing page at <https://github.com/nightowlstudiollc>. Worth investing 30min on a real page.
- **claude.yml** (the `@claude` mention handler) — yes, mirror it. Same security `if:` guard.
- **claude-blocking-review template** — yes. Same content as smartwatermelon's, pinned `@v3.0.0`.
- **dependabot-auto-merge template** — yes. Identical content; the workflow doesn't reference org-specific paths.
- **dependabot.yml in .github itself** — yes, same minimal config.

### Phase 1 — Create the repo

```bash
gh repo create nightowlstudiollc/.github \
--private \ # or --public if you want the profile page indexed
--description "Organization-level defaults: workflow templates, community files" \
--clone
```

Decision: **private vs public**. The org's other repos are private (9/9). `.github` repos that hold a `profile/README.md` need to be public for the profile to render publicly — but `.github` *workflow-templates* work fine in a private `.github` repo. Three sub-options:

- **All-private**: profile README won't render publicly. Internal-only org. Reasonable if NightOwl doesn't need a public landing page.
- **All-public**: profile renders, but FUNDING/SECURITY/etc become public defaults. Fine, just be deliberate.
- **Two repos**: separate `.github-private` for workflow-templates if you want the public/private split. GitHub supports both: `.github-private` is the org-internal-only equivalent, surfaced only to org members.

Recommend **all-public** unless there's an explicit reason not to. Match the `smartwatermelon/.github` pattern.

### Phase 2 — Mirror files

Copy from `smartwatermelon/.github`:

| Source | Destination | Modifications |
|---|---|---|
| `workflow-templates/claude-blocking-review.yml` | same path | none (already at `@v3.0.0` after PR #7) |
| `workflow-templates/claude-blocking-review.properties.json` | same path | none |
| `workflow-templates/dependabot-auto-merge.yml` | same path | none |
| `.github/workflows/claude.yml` | same path | none |
| `.github/dependabot.yml` | same path | none |
| `profile/README.md` | same path | rewrite for NightOwl |
| `CLAUDE.md` | same path | rewrite for the new repo's purpose |
| `README.md` | same path | rewrite |

Skip `.github/FUNDING.yml` unless decided otherwise in Phase 0.

### Phase 3 — Provision org-level secret

```bash
gh secret set CLAUDE_CODE_OAUTH_TOKEN --org nightowlstudiollc --visibility all
```

Without this, every workflow scaffolded from the template will fail on first run. Check `gh secret list --org nightowlstudiollc` before declaring done.

### Phase 4 — Bellwether

Pick one existing `nightowlstudiollc/*` repo. Use the Actions UI: New workflow → "By Night Owl Studio" section → select Claude Blocking Review. Verify:

- Template populates with `@v3.0.0` pin.
- Commit it via the UI.
- Open a test PR. The `claude-review / run-review` check fires.
- Result is sane.

If the template doesn't show up in the picker: check that the `.github` repo is the org's actual `.github` repo (not `nightowlstudiollc/dot-github` or similar), and that the `workflow-templates/` directory has the right structure (`*.yml` + `*.properties.json` pairs, not nested folders).

### Phase 5 — Document and close out

- Update this repo's README to mention NightOwl scaffolding works via the org workflow picker.
- Update `claude-review-audit.sh` if it doesn't already cover NightOwl repos. (It does — verified at script line ~30.)
- Close out: the original question's "do new repos inherit?" is now **yes for nightowlstudiollc**, **no for smartwatermelon** (and won't change without org migration).

## Risks and rollback

| Risk | Mitigation |
|---|---|
| Template appears in picker but secret missing → first run fails | Phase 3 explicit; verify with `gh secret list --org nightowlstudiollc` |
| Free-tier features (auto-merge, branch protection rules) silently no-op on the `.github` repo if it lands on the wrong tier | NightOwl is on `team` plan per `gh api orgs/nightowlstudiollc`; no concern. Cross-check anyway |
| `profile/README.md` placeholder gets indexed before real content lands | Land Phase 2 commits in one PR or one direct push, not piecemeal |
| Existing nightowl repos with bespoke claude-review configs collide with the new template at install time | The template only affects *new* installs. Existing repos are bulk-install territory and untouched by this plan |

Rollback: `gh repo delete nightowlstudiollc/.github` removes everything cleanly. No fleet-wide impact since this only adds opt-in scaffolding for new workflows.

## Acceptance criteria

- `nightowlstudiollc/.github` exists, public, with the file inventory above.
- `CLAUDE_CODE_OAUTH_TOKEN` accessible to all org repos.
- Picker test from Phase 4 produces a working PR with green `claude-review / run-review`.
- `profile/README.md` renders at <https://github.com/nightowlstudiollc>.
- README in this repo (github-workflows) mentions both org sources.

## Open questions

- Should NightOwl have a different `extra_instructions` block in its template (e.g. domain-specific guidance for the LLC's product code)? Probably yes eventually — leave as comment placeholder, fill in once a NightOwl repo accumulates feedback patterns.
- Public vs private profile decided in Phase 1.
- Once this lands, do we want to split `claude-config`-style automation (an `install.sh` for `.github` repos)? Probably not — two orgs is the entire fleet; manual sync is fine.
Loading
Loading