agentleFS
tammaitammai/bigin-skills/skills/project-scaffold/SKILL.md

project-scaffold

Skill1 starsChanged 39 days agoMITView on GitHub

Stands up a whole polyrepo project — six repos (specs, contracts, api, web, mobile, qa), the right scaffold in each, locks and workflows wired between them. Triggers: 'set up a new polyrepo project', 'scaffold the six repos'.

  • Reads credentials

18 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

2 rules. 0 are common, 0 are distinctive, and 2 are very specific to this project.

  • 0

    Common

    Most of the 14 edited versions we read keep these.

  • 0

    Distinctive

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Ask for the project slug if it wasn't given — kebab-case, and it becomes the prefix of all six repo names, which is what Phase 0a reads to …

    line 25
  2. Very specific:

    If they want remotes, confirm the owner explicitly.

    line 29

“Common” is measured: kept by at least 6 in 10 of the 14 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

project-scaffold

One command for what otherwise takes about twenty manual steps: six repos, the right scaffold in each code repo, and the connective tissue between them — which repo pairs with which, what each lock points at, which toolchain each workflow needs.

The standard it builds is described in ${CLAUDE_PLUGIN_ROOT}/docs/polyrepo/README.md.

When not to use

  • A single repo. That's bigin-harness-setup, or one of the *-scaffold skills for an empty one. Six repos for a project that has one frontend and no separate QA team is ceremony.
  • A project that already exists. This creates and adopts, but it will not migrate a working repo into the standard — that's a per-repo bigin-harness-setup run plus a contract-sync setup.
  • Just adding a repo to a project that already follows the standard. Use --repos with the one you need.

A project that has no mobile app, or no separate web frontend, is the same command with the types it does have: --repos specs,contracts,api,web,qa. Everything downstream is keyed off repo type, so the omitted one leaves no lock, no codegen workflow and no entry in the consumer list.

Step 1: Get the slug, and decide about remotes

Ask for the project slug if it wasn't given — kebab-case, and it becomes the prefix of all six repo names, which is what Phase 0a reads to decide each repo's type.

Then ask one question, because the answer is not reversible by default: create the GitHub repos now, or set up locally first? Local-only is a real mode — the pilot ran that way for hours — and remotes can be added later by re-running with --owner.

If they want remotes, confirm the owner explicitly. Never infer it from gh auth status: the accident this prevents is six repos appearing in an organisation nobody meant to touch.

Step 2: Run it

node ${CLAUDE_SKILL_DIR}/scripts/project_scaffold.mjs --project <slug> [--dir <path>]
     [--owner <login>] [--app-id <id> --app-key <path.pem>]
     [--repos specs,contracts,api,web,mobile,qa] [--no-install]
     [--web-origin <origin>] [--api-origin <origin>]

Stream its output. It creates each repo, seeds it, wires it, commits, and — with --owner — creates and pushes the remote. Every skipped step is named in the summary rather than passed over: a missing toolchain, an unreachable API, a repo it adopted rather than created.

--app-id/--app-key set CONTRACT_APP_ID and CONTRACT_APP_PRIVATE_KEY on every repo. The script reads the key only to pipe it to gh secret set on stdin; it is never logged, passed as an argument, or copied. They need --owner, since there is nothing to set them on otherwise.

STORY_CONSUMERS on the specs repo is wiring, not a credential — the story-dispatch workflow reads it whoever created the App — so --owner alone sets it. It is the project's consumer list, so a --repos run that adds one repo unions it into whatever is already there rather than replacing it, and a value it cannot read or parse is reported and left alone, since a wrong list here fails silently.

--web-origin (default http://localhost:3000) and --api-origin (default http://localhost:8090) wire the browser path in ${CLAUDE_PLUGIN_ROOT}/docs/polyrepo/SPEC-polyrepo-standard.md → "Browser and mobile paths to the API": the web origin becomes WEB_ORIGINS in <project>-api/.env.example (the API's CSRF allowlist), the API origin becomes NUXT_API_ORIGIN in <project>-web/.env.example. Only .env.example is written, never .env.

  • An origin is scheme://host[:port] and nothing else. A trailing slash, a path or * is refused with exit 2 before anything is created, because the API matches origins exactly.
  • An existing value is never overwritten. The only things replaced are an empty value and go-scaffold's own WEB_ORIGINS=http://localhost:3000 placeholder. A conflicting value is named in the summary and left alone.
  • A .env.example without the key (the scaffold was skipped or failed) is named in the summary and nothing is written.
  • A --repos run that omits api or web skips that side of the wiring.
  • The summary names both values and says what carries over to deployment: nothing does by itself. Set NUXT_API_ORIGIN on the deployed web app and WEB_ORIGINS on the API to the real origins, with no wildcard.

Step 3: Install the harness in each repo

The script writes no guard, no rule file, no settings.json and no CLAUDE.md. bigin-harness-setup owns the governance overlay, and a second implementation here would drift the day either changed.

So run it once per repo. Phase 0a reads the name suffix, confirms it, and installs that repo's profile — plus, on api/web/mobile, the consumer overlay and vendored-contract-guard.mjs.

Step 4: The first contract

The contracts repo is seeded with an empty openapi/core.v1.yaml. Write the real one there, tag it, then in each consumer:

node scripts/contract_sync.mjs bump <tag>

That records the commit and checksum, vendors the spec, and regenerates the client — in one commit, which is the invariant everything downstream depends on.

Step 5: Say what is left

Three things this cannot do, and the summary should name whichever apply:

  1. Create the GitHub App. Web UI only. Until it exists and is installed on the owner, every dispatch fails at "Mint an App token" with a 404.
  2. Fix Actions billing. A failed payment or a $0 spending limit blocks Actions across every repo an account owns, and the symptom is a job dying in about three seconds with no log. Worth checking before blaming a workflow.
  3. Seed .bmad-core. BA workflow depth is a deliberate placeholder; the specs repo gets the directory structure and story_lint.mjs, not a story template.

Everything the standard needs beyond that works without CI at all — see ${CLAUDE_PLUGIN_ROOT}/skills/bigin-harness-setup/references/ci.md → ## Running the standard without CI.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.