feat(scaffold): B-0424.1 — Forge + ace day-one governance templates + dry-run create-repo tool#2994
Conversation
…ate-repo tool Implements the smallest safe slice of B-0424 (three-repo split Stage 1): - tools/scaffold/forge/ — 10 day-one governance files for Forge repo (README, AGENTS, CLAUDE, GOVERNANCE, SECURITY, CODE_OF_CONDUCT, CONTRIBUTING, LICENSE, .github/copilot-instructions, docs/GITHUB-SETTINGS) - tools/scaffold/ace/ — same set scoped to the ace package manager repo - tools/scaffold/create-repo.ts — TypeScript dry-run tool (Rule 0) that shows the 7-step GitHub API plan for creating each repo with the full ADR best-practice checklist (merge settings, branch protection, secret scanning, CodeQL default-setup, Dependabot, fork to AceHack, file push) - docs/backlog/P1/B-0424 — pre-start checklist completed No GitHub repos created yet (--apply is the follow-on step; Aaron reviews the --dry-run JSON output before executing). Dry-run verified clean: 10 operations planned for each repo. Build gate: dotnet build -c Release → 0 Warning(s) 0 Error(s). operative-authorization: aaron 2026-05-13: "Cooling period: TBD. The memory file IS the durable record" Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ea871e46bd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…unction Both flagged by github-code-quality review on PR #2994. `readFileSync` was imported but never used; `execute()` was defined but never called — all step functions use inline spawnSync or the ghApiPatch/ghApiPut helpers instead. No behaviour change: dry-run output verified unchanged. Co-Authored-By: Claude <noreply@anthropic.com>
Fixes P1 review finding on PR #2994: step06 (direct push to main) was running after step02 (branch protection with enforce_admins + required reviews), which would cause GH006 rejection in --apply mode. New order: create repo → push scaffold files → apply branch protection → security → CodeQL → fork → summary. Also fixes P2 finding: add separate PUT /branches/main/protection/required_signatures call (step 02b) — GitHub enforces required signed commits via a distinct endpoint, not the main protection PUT payload. Dry-run verified: 11 operations planned in correct order. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR adds initial scaffolding for the planned Forge + ace repo split (B-0424 Stage 1): governance-file templates for both repos plus a Bun/TypeScript tool that produces (and can optionally apply) a GitHub API “create repo” plan, and updates the B-0424 backlog row to mark the pre-start gate as completed.
Changes:
- Add
tools/scaffold/{forge,ace}/day-one governance templates (README/AGENTS/CLAUDE/GOVERNANCE/SECURITY/CONTRIBUTING/CODE_OF_CONDUCT/LICENSE + Copilot instructions + declarative GitHub settings doc). - Add
tools/scaffold/create-repo.tsto emit a structured dry-run plan (and--applyexecution path) for repo creation and baseline settings. - Update the B-0424 backlog item with a completed pre-start checklist and narrowed scope for B-0424.1.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 18 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/scaffold/README.md | Documents the scaffold directory and how to run the create-repo tool. |
| tools/scaffold/create-repo.ts | Bun/TS tool to plan/apply GitHub repo creation + settings + scaffold file push. |
| tools/scaffold/forge/README.md | Forge repo README template. |
| tools/scaffold/forge/AGENTS.md | Forge agent/human collaboration template. |
| tools/scaffold/forge/CLAUDE.md | Forge Claude session bootstrap template. |
| tools/scaffold/forge/GOVERNANCE.md | Forge governance rules template. |
| tools/scaffold/forge/SECURITY.md | Forge security policy template. |
| tools/scaffold/forge/CONTRIBUTING.md | Forge contributing guide template. |
| tools/scaffold/forge/CODE_OF_CONDUCT.md | Forge code of conduct template. |
| tools/scaffold/forge/LICENSE | Forge license template (Apache 2.0 text). |
| tools/scaffold/forge/.github/copilot-instructions.md | Forge Copilot instructions template. |
| tools/scaffold/forge/docs/GITHUB-SETTINGS.md | Forge declarative GitHub settings template. |
| tools/scaffold/ace/README.md | ace repo README template. |
| tools/scaffold/ace/AGENTS.md | ace agent/human collaboration template. |
| tools/scaffold/ace/CLAUDE.md | ace Claude session bootstrap template. |
| tools/scaffold/ace/GOVERNANCE.md | ace governance rules template. |
| tools/scaffold/ace/SECURITY.md | ace security policy template. |
| tools/scaffold/ace/CONTRIBUTING.md | ace contributing guide template. |
| tools/scaffold/ace/CODE_OF_CONDUCT.md | ace code of conduct template. |
| tools/scaffold/ace/LICENSE | ace license template (Apache 2.0 text). |
| tools/scaffold/ace/.github/copilot-instructions.md | ace Copilot instructions template. |
| tools/scaffold/ace/docs/GITHUB-SETTINGS.md | ace declarative GitHub settings template. |
| docs/backlog/P1/B-0424-three-repo-split-stage1-create-forge-ace-with-scaffolding-aaron-2026-05-13.md | Marks pre-start checklist completed and scopes B-0424.1 deliverables. |
Comments suppressed due to low confidence (2)
tools/scaffold/create-repo.ts:134
- The helper
execute()is declared but never used, which will fail TypeScript withnoUnusedLocals: true. Either wire it into the execution path or remove it to avoid a build/lint break.
function ghApiPatch(
path: string,
data: Record<string, unknown>,
description: string,
step: string
): Operation {
const body = JSON.stringify(data);
const op = plan(step, description, `gh api --method PATCH ${path} --input -`, data);
if (!dryRun) {
const result = spawnSync(
"gh",
["api", "--method", "PATCH", path, "--input", "-"],
{ input: body, encoding: "utf8", maxBuffer: 8 * 1024 * 1024 }
);
op.status = result.status === 0 ? "executed" : "failed";
tools/scaffold/create-repo.ts:476
- Most tools in this repo follow the pattern
export function main(argv)+if (import.meta.main) process.exit(main(...))to make scripts importable/testable and avoid side effects on import. This file currently runs at module top-level; consider refactoring to the standardmainentrypoint + guard so it matches the codebase tooling convention.
step07_summary();
const failed = ops.filter((o) => o.status === "failed").length;
const executed = ops.filter((o) => o.status === "executed").length;
const planned = ops.filter((o) => o.status === "planned").length;
const result: RunResult = {
repo: `${config.org}/${config.name}`,
dryRun,
operations: ops,
summary: dryRun
? `DRY RUN — ${planned} operations planned for ${config.org}/${config.name}. Pass --apply to execute.`
: `${executed} executed, ${failed} failed out of ${ops.length} total operations.`,
};
console.log(JSON.stringify(result, null, 2));
if (!dryRun && failed > 0) {
process.exit(1);
}
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bcd753ed03
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Code fixes in create-repo.ts:
- fileURLToPath(import.meta.url) instead of new URL('.').pathname (Thread 13)
- sonarjs/no-os-command-from-path suppressions on all spawnSync calls (Thread 12)
- Empty REQUIRED_CHECKS at creation to avoid deadlock before CI workflows exist (Thread 14)
- Separate /required_signatures PUT already handles signed commits (Thread 15)
- git checkout -b main after cloning empty repo to set branch name (Thread 16)
- Check exit codes for git add/commit; use git push HEAD:main (Thread 16/17)
- fs-native mkdirSync + copyFileSync instead of subprocess mkdir/cp (Thread 18)
- path.dirname(dst) instead of substring/lastIndexOf (Thread 18)
- exactOptionalPropertyTypes fix for plan() via conditional spread (Thread 11 pre-existing)
- repoArg narrowing fix for module-level var in nested function (pre-existing)
Doc fixes:
- snapshot-burn.sh → snapshot-burn.ts (Rule 0 — Thread 4)
- "Aaron" → "the human maintainer" in forge README (Thread 5)
- Day-one note for Stage-2-migrated docs in forge CLAUDE.md (Thread 6)
- Remove "Copyright 2026 Zeta contributors" from forge/ace LICENSE (Threads 7, 10)
Markdown table ||→| issues already fixed in current code (Threads 1-3, 8-9).
Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 40a3d376f0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…eporting
GitHub exposes a separate endpoint for enabling private vulnerability
reporting: PUT /repos/{owner}/{repo}/private-vulnerability-reporting.
The repo PATCH field `private_vulnerability_reporting_enabled` is not
the supported API path for this feature.
Addresses Codex P1 review thread on PR #2994.
Co-Authored-By: Claude <noreply@anthropic.com>
…hor trailer Two P2 findings from Codex review on PR #2994: 1. README step table listed branch protection (02) before scaffold push (06), but the tool intentionally runs step06 first to avoid pushing to a protected branch. Table now reflects actual execution order. 2. The scaffold commit message hardcoded `Co-Authored-By: Claude` regardless of which harness runs `--apply`. Removed; callers own their own attribution. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 23 out of 23 changed files in this pull request and generated 7 comments.
Comments suppressed due to low confidence (1)
tools/scaffold/README.md:66
- The “Manual steps after --apply” section is missing the required-status-checks bootstrapping step that the tool prints (adding
bun-test,bun-lint,codeql,scorecardas required checks after workflows are wired). Adding it here would avoid readers missing that follow-up action.
## Manual steps after --apply
The tool prints these at the end, but for reference:
1. Upload SVG social-preview PNG via GitHub UI
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a6b1b57c8c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- create-repo.ts: fix header comment (remove false "budget caps" claim)
- create-repo.ts: use fs.rmSync instead of spawnSync("rm", ...) for cleanup
- create-repo.ts: apply homepage in merge-settings PATCH (was dead config)
- create-repo.ts: add ghApiPost helper; use POST (not PUT) for required-signatures
endpoint per GitHub REST docs — PUT would fail silently in --apply mode
- forge/docs/GITHUB-SETTINGS.md: add Stage-2 note for required status checks
- ace/docs/GITHUB-SETTINGS.md: add Stage-2 note for required status checks
- forge/GOVERNANCE.md: replace "Claude-owned" / "Aaron retains" with role refs
- tools/scaffold/README.md: clarify execution order wording (step numbers are
stable identifiers, not sequential labels)
Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f8e6695748
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…n create-repo.ts Thread PRRT_kwDOSF9kNM6BzKAD (P1): abort subsequent steps when repo creation fails. Added early-exit guard in main block after step01 in --apply mode; subsequent steps skipped to avoid mutating an existing or partial repository. Thread PRRT_kwDOSF9kNM6BzKAI (P2): keep dry-run output complete for merge-settings patch. Moved plan() call for 01b-merge-settings outside the if (!dryRun) block; dry-run now shows all 12 planned operations including the PATCH (previously 11 — 01b was hidden). Thread PRRT_kwDOSF9kNM6BzKAK (P2): align branch operations with repository default branch. Added module-level defaultBranch variable (default "main"); updated after repo creation by querying the repo API. step02 branch protection paths and step06 checkout/push now use defaultBranch instead of hardcoded "main". Dry-run verified: 12 planned operations in correct order. TypeScript: tsc --noEmit passes (0 errors). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… dead links Named attribution fixes (per .github/copilot-instructions.md convention): - forge/README.md: "Claude-owned" → "factory's AI agent" - forge/AGENTS.md: "Claude-owned" / "Aaron" → role references - forge/GOVERNANCE.md: "routes through Aaron" → "routes through the human maintainer"; footer ".claude/rules/ and memory/" → "Forge repo's docs/" - ace/README.md: "Aaron-owned" / "Claude" → role references - ace/AGENTS.md: "Aaron-owned" / "Claude" → role references - ace/GOVERNANCE.md: "Aaron-owned" / "routes through Aaron" → role refs Dead local-path references fixed: - ace/README.md: bare memory/ path → full Zeta repo URL - ace/AGENTS.md: bare memory/ path → full Zeta repo URL - forge/docs/GITHUB-SETTINGS.md: bare memory/ path → prose reference Code fix in create-repo.ts: - git checkout -b error handling: distinguish "branch already exists" (expected, ignore) from real failures (missing git, corrupt clone, permission denied) — surface real failures instead of always ignoring Addresses copilot-pull-request-reviewer + chatgpt-codex-connector threads on PR #2994. Co-Authored-By: Claude <noreply@anthropic.com>
…HUB-SETTINGS.md Two backtick-coded memory/ file references on lines 65 and 81 were still local-path references that would be dead links in the scaffolded Forge repo (which has no memory/ directory at day-one). - `memory/reference_github_code_scanning_ruleset_rule_requires_default_setup.md` → full Zeta repo URL - `memory/feedback_lfg_budgets_set_permits_free_experimentation.md` → full Zeta repo URL Addresses review thread PRRT_kwDOSF9kNM6BzZC2 (PR #2994). Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 23 out of 23 changed files in this pull request and generated 7 comments.
Comments suppressed due to low confidence (2)
tools/scaffold/forge/CLAUDE.md:24
bun tools/github/refresh-worldview.tsanddocs/trajectories/*/RESUME.mdare referenced as if present, but the Stage 1 file push only includes governance docs (notools/github/and nodocs/trajectories/). Consider adding to the existing day-one note that these paths arrive in Stage 2 migration (and point to Zeta equivalents in the interim), otherwise the first suggested command/path will fail in the freshly created repo.
```bash
bun tools/github/refresh-worldview.ts
Read active trajectories: docs/trajectories/*/RESUME.md.
**tools/scaffold/ace/CLAUDE.md:15**
* `bun tools/github/refresh-worldview.ts` is referenced as a standard refresh step, but the Stage 1 scaffold being pushed does not include `tools/github/` yet. Add a short day-one note (or a link to the Zeta equivalent) so a fresh repo doesn’t immediately instruct users to run a non-existent command.
2. Refresh
bun tools/github/refresh-worldview.ts</details>
| For each repo, in **execution order** (step numbers are stable identifiers, not sequential labels — step 06 runs before step 02 intentionally): | ||
|
|
||
| | Step | Description | | ||
| |------|-------------| | ||
| | 01 | Create repo (public, squash-merge only, auto-merge, delete-branch) | | ||
| | 06 | Push day-one governance files from `tools/scaffold/<name>/` — **runs before branch protection** so files can be pushed directly to `main` | | ||
| | 02 | Apply branch protection on `main` (1 review, signed commits, linear history, no force-push) | | ||
| | 03 | Enable secret scanning + push protection, Dependabot, private vulnerability reporting | |
| const args = process.argv.slice(2); | ||
| const repoArg = args.find((_, i) => args[i - 1] === "--repo"); | ||
| const dryRun = !args.includes("--apply"); | ||
|
|
||
| if (!repoArg || !REPO_CONFIGS[repoArg]) { | ||
| console.error( | ||
| `Usage: bun tools/scaffold/create-repo.ts --repo <forge|ace> [--dry-run|--apply]` | ||
| ); | ||
| console.error(`Known repos: ${Object.keys(REPO_CONFIGS).join(", ")}`); | ||
| process.exit(1); | ||
| } |
| step01_createRepo(); | ||
| // Abort in --apply mode if repo creation failed — avoid mutating an existing or partial repository. | ||
| if (!dryRun && ops.some((o) => o.step === "01-create-repo" && o.status === "failed")) { | ||
| const failedResult: RunResult = { | ||
| repo: `${config.org}/${config.name}`, | ||
| dryRun, | ||
| operations: ops, | ||
| summary: `ABORTED — step 01 (create-repo) failed; subsequent steps skipped to avoid mutating an existing repository.`, | ||
| }; | ||
| console.log(JSON.stringify(failedResult, null, 2)); | ||
| process.exit(1); | ||
| } | ||
| step06_pushScaffoldFiles(); // must run before branch protection to allow direct push to default branch | ||
| step02_branchProtection(); | ||
| step03_enableSecurity(); | ||
| step04_codeqlDefaultSetup(); | ||
| step05_forkToAcehack(); | ||
| step07_summary(); | ||
|
|
||
| const failed = ops.filter((o) => o.status === "failed").length; | ||
| const executed = ops.filter((o) => o.status === "executed").length; | ||
| const planned = ops.filter((o) => o.status === "planned").length; | ||
|
|
||
| const result: RunResult = { | ||
| repo: `${config.org}/${config.name}`, | ||
| dryRun, | ||
| operations: ops, | ||
| summary: dryRun | ||
| ? `DRY RUN — ${planned} operations planned for ${config.org}/${config.name}. Pass --apply to execute.` | ||
| : `${executed} executed, ${failed} failed out of ${ops.length} total operations.`, | ||
| }; | ||
|
|
||
| console.log(JSON.stringify(result, null, 2)); | ||
|
|
||
| if (!dryRun && failed > 0) { | ||
| process.exit(1); |
| Rules auto-load from `.claude/rules/`; skills load on demand from `.claude/skills/`. | ||
| Slash commands: `.claude/commands/`; persona agents: `.claude/agents/`. | ||
|
|
| backlog-item start gate (prior-art search + dependency check — | ||
| see `.claude/rules/backlog-item-start-gate.md`). |
| # CLAUDE.md — Claude Code session bootstrap for ace | ||
|
|
||
| Rules auto-load from `.claude/rules/`; skills load on demand from `.claude/skills/`. | ||
|
|
||
| ## 1. Orient | ||
|
|
||
| Read: [`AGENTS.md`](AGENTS.md) → [`GOVERNANCE.md`](GOVERNANCE.md). | ||
| Check [`docs/WONT-DO.md`](docs/WONT-DO.md) before proposing work. | ||
|
|
|
|
||
| --- | ||
|
|
||
| *Rationale lives in `.claude/rules/` and `memory/` in the Forge repo.* |
…tep documented (#3114) * backlog(b-0424): mark in-progress — document slices 1-8 merged; add --apply next-step All 8 scaffolding slices (PRs #2994, #2996, #3003, #3019, #3025, #3026, #3027, #3028) are merged and tests pass (30/30). Update status to in-progress and document the completed slices table, dry-run verification (12 ops planned for each repo, 2026-05-14), and the --apply execution instructions Aaron needs to review before irreversible repo creation. operative-authorization: aaron 2026-05-13: "Cooling period: TBD. The memory file IS the durable record" Co-Authored-By: Claude <noreply@anthropic.com> * fix(b-0424): add blank line before list — resolve MD032 markdownlint Co-Authored-By: Claude <noreply@anthropic.com> * fix(b-0424): valid status + route --apply through workflow - status: in-progress → open (in-progress not in schema enum) - Next-step instructions now reference scaffold-stage1-create-repos GitHub Actions workflow (actor allowlist + CONFIRM gate + PAT handling + concurrency protection) instead of raw --apply bash Resolves Copilot P1 threads on #3114. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
Summary
B-0424 (P1) — Three-repo split Stage 1. This PR is the smallest safe slice: governance file templates and an executable dry-run plan. No actual GitHub repos are created yet (that's an irreversible external action requiring Aaron's review of the
--dry-runJSON output before--apply).tools/scaffold/forge/— 10 day-one governance files forLFG/Forge(README, AGENTS, CLAUDE, GOVERNANCE, SECURITY, CODE_OF_CONDUCT, CONTRIBUTING, LICENSE,.github/copilot-instructions,docs/GITHUB-SETTINGS)tools/scaffold/ace/— same set scoped to theLFG/acepackage manager repotools/scaffold/create-repo.ts— TypeScript dry-run tool (Rule 0) that emits a 7-step GitHub API plan (merge settings, branch protection, secret scanning, CodeQL default-setup, Dependabot, AceHack fork, file push) as structured JSONdocs/backlog/P1/B-0424— pre-start checklist completed perbacklog-item-start-gate.mdDry-run output (verified)
Checks
dotnet build -c Release→ 0 Warning(s) 0 Error(s).tsrun viabunFollow-on steps (not in this PR)
Once Aaron has reviewed the dry-run output:
bun tools/scaffold/create-repo.ts --repo forge --applybun tools/scaffold/create-repo.ts --repo ace --apply--applyexecutionADR reference
docs/DECISIONS/2026-04-22-three-repo-split-zeta-forge-ace.md🤖 Generated with Claude Code