microsoft/build-repo
Get an unseen (possibly old or abandoned) TypeScript/JavaScript GitHub repo building in a disposable sandbox. Detects the era-appropriate toolchain, runs the documented setup, then drives Setup/Compile/Test/Runtime to green with a progress-based convergence loop. Use when you need to bring up a repo you've never seen and honestly report what it took. Scope is TS/JS (Node + package manager + tsc) only.
npx skills add https://github.com/microsoft/TypeScript-Maintainer-Skills --skill build-repo
Bring an unseen TS/JS repository up from nothing: clone it, install the right
era-appropriate toolchain, run its documented setup, and drive each phase to green —
honestly. The repo may be old, abandoned, large, or under-documented. Your job is to make
it build *and* tell the truth about what that took.
Environment assumption: you run in a disposable sandbox (a throwaway machine or
container). You may install system packages (apt), switch Node versions, and start
backing services freely — but you MUST record every tool and version you install (see
extended-plan-schema.md) so the result is reproducible.
Scope: TS/JS only — Node, a JS package manager (npm/pnpm/yarn), and tsc. Other
languages are out of scope.
When you finish, produce:
extended with a tools manifest and a convergence log. Schema and example are in
extended-plan-schema.md. Write it to your session/output
folder; do not commit it into the target repo.
The build uses four canonical phases:
| Phase | Meaning | Default verification |
|-------|---------|----------------------|
| Setup | Install dependencies + run the project's build pipeline (turbo/webpack/etc.) | exit code 0 |
| Compile | Typecheck only, via the project's own tsc (its typecheck script, or npx tsc --noEmit) | exit code 0, parse error count |
| Test | The project's real test command | exit code 0, parse failure count |
| Runtime | Verify it actually runs — module loads, CLI runs, server responds | per-step (output-contains, http-status, etc.) |
Each phase ends in one of four terminal states:
evidence — never as a shortcut for "I couldn't find it."
provide. Reported honestly; not a failure.
Definition of done: the loop has plateaued (or hit the cap) on every phase, every
terminal state is justified, and at least one of Compile/Test/Runtime is PASS. A repo
where nothing can be compiled, tested, or run is a failed build, not a pass.
out, so don't pick a branch or commit yourself. Note the **commit date of the ref
you're building** (git show -s --format=%cI HEAD) — you'll need it for toolchain
selection, and it may be far older than the repo's latest commit.
README.md, then CONTRIBUTING.md, thendocs/. Well-maintained repos put setup in CONTRIBUTING.md; smaller repos use
README.md. Extract the documented setup, build, test, and run commands verbatim.
You are partly here to audit whether these documented instructions actually work,
so start from them rather than from CI.
truth: .github/workflows/*.yml, Dockerfile, .devcontainer/, docker-compose.yml,
Makefile/justfile, and the scripts section of every package.json.
package.json to populate packages (monorepos have many).Pick the Node version from these sources, in priority order:
engines.node in the root package.json.nvmrc.node-version.tool-versions (asdf) / Volta config in package.jsonDockerfile / .devcontainer/ base imagenode-versionchecked-out ref's commit date** — *not* the latest. Abandoned repos build with
era-appropriate
tools. (This is where naïvely defaulting to "latest" breaks old repos.)
Obtain it via a version manager (nvm/fnm). For the package manager, respect the
packageManager field / lockfile and install the matching version (corepack). Record
every install in the tools manifest.
Reproduce the original dependency graph: npm ci / pnpm i --frozen-lockfile /
yarn install --frozen-lockfile. If the frozen install fails, you may fall back to a
non-frozen install (npm install) or regenerate the lockfile — but only as a **recorded
fidelity compromise** in the manifest, because you've now changed which code you're
building. A frozen-install failure is itself a meaningful signal that the repo may be
broken as published (yanked packages, integrity mismatches).
Infer undocumented system tools and services as you go:
node-gyp→python/make/gcc (build-essential), sharp→libvips, canvas→cairo/pango,
puppeteer/playwright→browser binaries, node-sass→python, etc.
docker-compose services, alocal Postgres/Redis/sqlite — and synthesize a dev environment from .env.example or
sensible defaults. Never fabricate real third-party credentials. If a phase truly
needs a real secret or external service, mark it BLOCKED-ON-EXTERNAL.
For each phase, run its command(s), then:
{ passed, errorCount, messageSet }(pass/fail + failure count + the set of distinct error messages). Append it to the
convergence log.
tool to install, a service to start, a config to set) and re-run.
signature already seen this run (a plateau or an A→B→A cycle), or when you reach the
hard cap of 10 total fix attempts across all phases. Otherwise keep looping — a
changed signature (status flip, count move, or a different error set) is progress, even
if it's still failing.
The point of progress-based termination (vs. a fixed retry count) is to keep unblocking
error-after-error until you genuinely can't make the result move — so you don't quit early
and accept a broken setup as if it were merely unlucky.
A downstream failure may be caused upstream: a Compile or Test failure can legitimately
send you back to fix Setup (e.g. a missing dependency). Fixes are not confined to the
phase that failed.
Never game a phase to green. These are inherited from discovery and are non-negotiable:
|| true, || :, || exit 0, || echo ...,; true, or ; exit 0. Commands must report their real exit code. A non-green result
is a valid outcome to report.
(its typecheck script, or npx tsc/tsc resolving the project's installed version).
Never substitute a different pinned version (e.g. [email protected]) to force success.
shrink the test command to one trivial suite, and don't reduce Runtime to a trivial
check like --version.
Record dependency drift and any non-frozen install as a fidelity compromise in the
manifest rather than hiding it.
Write the EvalPlan JSON (working commands per phase + tools manifest +
convergence log + per-phase terminal states) to your output folder, and summarize for the
user: what built, what's ABSENT or BLOCKED-ON-EXTERNAL and why, every tool you had to
install, any fidelity compromises, and — if the build ultimately failed — your diagnosis
of whether the repo is broken as published or simply needs something the sandbox lacks.
Take microsoft/build-repo from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference npm, npx.
Without those the skill loads but fails at the first command.