new-repo — scaffold a RepoKit-standard repository
You scaffold a new repository by copying bundled templates and filling in their {{placeholders}}
(copy-and-fill — there is no separate templating engine). You stop at local review: you may
create a private GitHub repo on request, but you never push to a public remote and never publish.
Your templates live under this skill's own directory. At load you were given a line
Base directory for this skill: <ABS>. Read every template as <ABS>/templates/<...>. Do not
rely on ${CLAUDE_PLUGIN_ROOT} or a bare relative path — use the absolute base path you were given.
Two reference files (read them from the same base dir as you need them):
references/file-set-resolution.md— exactly which templates apply for a given type × tier.references/placeholders.md— the placeholder list and the post-scaffold self-check.
Inputs
Gather these from the user's arguments / message, else ask — keep it to load-bearing questions:
- name — the repo / directory name. Default kebab-case; a deliberate branding name (a camelCase product name, say) is a legitimate user choice, not a mistake — accept it without argument and record it in ADR-0001 (see the standard's Naming conventions).
- description — one line.
- type — one of:
powershell-module,docker-compose,power-platform-connectors,skill-plugin,collection,mcp-server,app-ts,app-python,script-collection. - visibility —
private(= Core tier),public(= +Public), orpublished(= +Published). - author — the identity stamped wherever an author/owner/copyright value is written. Default:
the GitHub handle of the gh-authenticated user (
gh api user --jq .login; nogh→ ask). A real personal name only when the user explicitly chooses one for this repo — that choice is a declared variance: record it in ADR-0001 and give it a START-HERE row (see the standard's Author identity). - license — default
Apache-2.0. - living-docs add-on — yes/no, default no. Ask: "Will this repo's docs track live
operational state (deployed resources, scheduled jobs, long-running migrations)?" If yes, the
add-on stamps
docs/RUNBOOK.md,docs/STATE.json,scripts/check-docs.ps1, and adocs.ymlcheck workflow (seereferences/living-docs-rules.md). - early licence — private repos only, default no. Ask: "Is a public release already
planned?" If yes, stamp
LICENSEnow from the Public-tier template, and ask one follow-up: "Will third-party licensed material be incorporated while still private?" — if so, also stampNOTICE(seereferences/file-set-resolution.md, Early licence). Record both answers in ADR-0001. No START-HERE variance row — an early licence on a promotion-planned repo follows the standard's Promotion path, it doesn't deviate from it. - For
powershell-moduleonly: ModuleName (PascalCase, e.g.MyModule).
If the chosen type is a stub (anything other than powershell-module, docker-compose, or power-platform-connectors), tell the user so: the
Core/Public/Published files get stamped, but there's no type-specific structure yet. Confirm they
want to continue.
Adopting a directory that already has content
The target directory may already contain files (a design doc written before repo genesis, a prototype script). That is supported — scaffold around the content instead of improvising:
- Inventory first. List the existing files. If the directory is already a git repo
(
.git/present), stop — that is a retrofit, not a scaffold: apply the standard by hand and add the adoption marker (see the standard, Variance declarations). - Collision rule: pre-existing content wins. Intersect the resolved file set (step 1 below) with what is on disk. Never overwrite a pre-existing file with a template — skip each colliding template, list the collisions in the final summary, and leave merging template content into the user's file (say, folding the README boilerplate into their existing README) as a follow-up the user approves.
- Two commits, pre-existing first — this replaces step 5's single stage+commit: stage
and commit the pre-existing files as-is (
chore: import pre-existing content), then stage the stamped files and make the scaffold commit on top. The scaffold commit stays a pure, reviewable RepoKit diff, and history records honestly that the content predates the scaffold. - Record it in ADR-0001: the repo was scaffolded into a pre-populated directory, plus the collision list, if any.
Steps
Resolve the file set (see
references/file-set-resolution.md).active_tiers = [core] + ([public] if visibility in {public, published}) + ([published] if visibility == published). The file set is the union, over each active tiert, of everything undertemplates/<t>/and everything undertemplates/types/<type>/<t>/— plus, for each chosen add-on, everything undertemplates/addons/<addon>/<t>/(add-ons only add files; they never collide). On a path collision pick one winner: higher tier wins (published>public>core), then within a tier the type overlay wins. Produce an explicit list of(template path → target path)pairs: drop any trailing.tmpl, and substitute filename placeholders (e.g.{{ModuleName}}.psd1.tmpl→MyModule.psd1).Stamp each file. For each pair: read the template from
<base>/templates/…, replace every placeholder (seereferences/placeholders.md), and write it to the target path under the new repo directory. Files with no.tmplsuffix are copied verbatim. Create directories as needed (docs/adr/,.github/…, any type-specific dirs).Write
docs/adr/0001-initial-decisions.mdfrom thedocs/adr/0000-template.mdyou just stamped, recording the name, type, visibility/tier, licence, author, and any notable interview choices.Generate the START-HERE map. From the resolved file set, build a short "where things live" table (rules →
AGENTS.md; decisions →docs/adr/; resume state →docs/CHECKPOINT.md(ordocs/STATE.jsonwhen the living-docs add-on takes over); conventions & checklists → therepo-standardskill; CI →.github/workflows/; tests → the type's test dir) and substitute it into the{{START_HERE_MAP}}placeholder in the stampedAGENTS.md. The resume-state row is mandatory —scripts/repokit-check.ps1fails without it. Add a one-line pointer in the README.Resolve
{{LIVING_DOCS_RULES}}in the stampedAGENTS.md: with the living-docs add-on on, substitute the verbatim rules block fromreferences/living-docs-rules.mdand append that file's## Statussnippet to the stampedREADME.md; with the add-on off, delete the placeholder line entirely. When the add-on is on, finish by runningpwsh scripts/check-docs.ps1 -Updatethenpwsh scripts/check-docs.ps1inside the new repo (both must succeed); if pwsh 7 is missing on this host, say so in the summary — running it is the user's first task.Self-check (gate — both must pass before you continue). See
references/placeholders.md: (a) no enumerated placeholder tokens remain anywhere in the output; (b) every expected target file exists and no.tmplsuffix survived. If either fails, fix and re-check. Then, when pwsh 7 is available, runpwsh scripts/repokit-check.ps1inside the new repo — the stamped compliance self-check must pass (it verifies the shim, the START-HERE paths, and the changelog / ADR / resume-state artifacts); if pwsh is missing, say so in the summary.Initialise git in the new repo directory:
- Default branch
main, nevermaster:git init -b main(-bneeds git >= 2.28; if it errors, rungit initthengit branch -m main). - Commit identity -- the handle + noreply, anonymous by default. So a repo that later goes
public never leaks a real name or a personal email, set a repo-local (not
--global) identity from the GitHub handle and the GitHub noreply address -- both fields, not just the email (a leaked file can be edited; a leaked commit identity survives until a history rewrite). Resolve them for the gh-authenticated user and apply locally:
Use a real name/email only if the user explicitly asked -- you may ask, but the default for both fields is the handle + noreply, and an explicit real identity is recorded in ADR-0001 (see the standard's Author identity). Nogh api user --jq '"\(.login)\t\(.id)+\(.login)@users.noreply.github.com"' git config user.name "<login>" git config user.email "<id>+<login>@users.noreply.github.com"ghavailable? Ask for the handle and fall back to<login>@users.noreply.github.com. - Stage + commit:
git add -A -f-- the-fforce-adds the stamped files past any global gitignore (e.g. a*private*rule that would silently drop aPrivate/dir; safe here, the tree holds only what you stamped, and the repo's own.gitignoregoverns later additions) -- then one Conventional commit:chore: scaffold <name> via RepoKit. - Confirm:
git status --shortis clean,git rev-parse --abbrev-ref HEADprintsmain, and note the commit identity you used in the final summary.
- Default branch
Offer a private remote — opt-in only. Ask whether to create a private GitHub repo. Only if the user says yes:
gh repo create <name> --private --source . --remote origin. Never public, never push to a public remote, never publish. When a remote is created, also offer the RepoKit label bootstrap (the workflow-verdict set plus any namespaces the user wants) — the commands are in therepo-standardskill'sstandard/labels.md; skip it for repos that won't run an issue board.Print the summary: the resolved tier × type, the file tree, the START-HERE map, and next steps — "review locally; you publish when ready." If the repo may ever go public, include the next step "run
pwsh scripts/install-privacy-guard.ps1(once per clone — the hook it installs stays in.git/hooks/and does not travel)".
Boundaries
- Stop at local review. Do not push to a public remote and do not publish.
- Do not invent files outside the resolved set.
- Diagrams embedded in templates are static — substitute
{{name}}inside them, but never redraw or regenerate a diagram.