Repo Agent Bootstrap skill for Claude Code

One pass from fresh clone to agent-ready repository. Claude surveys the stack and CI, runs every build, test and lint command before writing it down, then produces a short CLAUDE.md with a docs map, a committed permission baseline that allows proven commands and denies secrets and production, and a pipe-tested formatter hook. It finishes with a four-question acceptance test in a fresh session and lists anything it could not prove.

  • namerepo-agent-bootstrap
  • size157 lines · ≈1,850 tokens
  • files2
  • licenseMIT
  • updated

What Claude sees before loading it

This description is the only part of the skill that sits in context all the time. Claude reads it to decide when to load the full playbook below.

description: Prepares a repository for agentic work with Claude Code in one pass by discovering and proving the build, test, lint, and run commands, then writing a short CLAUDE.md with a docs map, a committed .claude/settings.json permission baseline, a formatter hook, a gitignored local settings file, optional .mcp.json, and a verification checklist a fresh session must pass. Use when the user says set up this repo for Claude, make the codebase agent-ready, run /init properly, or onboard a team to Claude Code.

Try asking

  • Set this repo up properly for Claude Code — CLAUDE.md, permissions, hooks, the lot
  • Run /init but make the result actually good and test that the commands work
  • Our team is starting with Claude Code; give the monorepo a sane shared baseline

Use it when

  • A repository has no CLAUDE.md or .claude/ configuration yet
  • Claude keeps exploring to find commands or asking for permission on routine tests
  • A team is adopting Claude Code and needs a committed baseline
  • An /init draft needs to be cut down and verified

Skip it when

  • Only the CLAUDE.md needs restructuring or pruning — use memory-file-architect instead
  • You are mapping an unfamiliar codebase for yourself, not configuring the agent — use codebase-onboarding instead

How to check the result

A fresh session answers the single-test command from CLAUDE.md without searching, runs it without a prompt, refuses to show .env, and asks before pushing.

The common mistake it prevents

Writing commands into CLAUDE.md that were never executed, so the first agent session fails on a script that does not exist or needs an unmentioned service.

~/.claude/skills/repo-agent-bootstrap/SKILL.md

--- name: repo-agent-bootstrap description: Prepares a repository for agentic work with Claude Code in one pass by discovering and proving the build, test, lint, and run commands,… license: MIT ---

A repository is agent-ready when a fresh Claude Code session, given only “add a small feature and prove it works”, finds the right commands without exploring, runs tests without permission friction, cannot touch secrets or production, and leaves formatted code. Every command written into config has been executed once and passed.

Scope

In scopeDelegate to
Discover and prove commands—
CLAUDE.md skeleton and docs mapDeep restructuring: memory-file-architect
Team permission baselineComplex policies, managed settings: permissions-policy
One formatter hook, optional test gateHook catalog and guards: hooks-automation
Repo-specific skills to seedWriting them: skill-authoring
CI agent runsheadless-ci-agent

Workflow

- [ ] 1. Survey: stack, package manager, monorepo layout, existing agent files
- [ ] 2. Discover commands and RUN each one; record time and result
- [ ] 3. Write CLAUDE.md (under ~120 lines) with commands, map, rules, gotchas
- [ ] 4. Write .claude/settings.json: allow proven commands, deny secrets/prod
- [ ] 5. Add a PostToolUse formatter hook for edited files; pipe-test it
- [ ] 6. .gitignore local files; add .mcp.json only for servers the team uses
- [ ] 7. Fresh-session acceptance test; fix whatever caused exploration or prompts
- [ ] 8. Summarize changes and the open items for the user

1. Survey (read-only)

git ls-files | head -200 | sed 's|/[^/]*$||' | sort | uniq -c | sort -rn | head -25
ls -a; cat package.json pyproject.toml Cargo.toml go.mod Makefile justfile 2>/dev/null | head -150
ls .claude CLAUDE.md AGENTS.md .cursor .github/copilot-instructions.md .mcp.json 2>/dev/null
cat .github/workflows/*.yml 2>/dev/null | grep -E 'run:' | head -40

CI workflows are the best source of truth for real commands. Existing AGENTS.md, Cursor rules, or Copilot instructions hold conventions worth keeping: Claude Code reads AGENTS.md when there is no CLAUDE.md; if both should apply, write a CLAUDE.md that imports it with @AGENTS.md rather than duplicating text.

2. Discover and prove commands

For each of install, build, typecheck, lint, format, unit test, single test, e2e, dev server, migrations: find the command, run it, note duration and whether it needs services (DB, Docker) or env vars.

SignalLikely commands
pnpm-lock.yamlpnpm install --frozen-lockfile, pnpm -r test, pnpm --filter <pkg> test
uv.lockuv sync, uv run pytest -q, uv run ruff check .
Cargo.tomlcargo build, cargo test, cargo clippy -- -D warnings
go.modgo build ./..., go test ./..., golangci-lint run
Makefile / justfilePrefer existing targets over raw commands

Always find the single-test form (pnpm vitest run path -t name, pytest path::test, go test ./pkg -run TestX): it is the command agents use most. Record commands that fail as open items; never write an unproven command into CLAUDE.md.

3. CLAUDE.md

Use the template in references/templates.md. Content rules:

  • Commands first, exactly as proven, with the single-test form.
  • A docs map: 5–15 lines of path — what lives there, only non-obvious locations.
  • Rules Claude would otherwise get wrong (generated files not to edit, migration policy, where new code goes, error-handling convention). Each rule one line.
  • Gotchas discovered in step 2 (“tests need docker compose up -d db first”).
  • No generic advice (“write clean code”), no restating what the code shows, no secrets.
  • Long, area-specific guidance goes to .claude/rules/<area>.md with paths: frontmatter, or to a nested CLAUDE.md in that directory, so it loads only when needed.

/init can draft a starting file; treat its output as a draft and cut it down. Setting CLAUDE_CODE_NEW_INIT=1 gives an interactive /init that also proposes skills and hooks.

4. Permission baseline (.claude/settings.json, committed)

Allow the proven read-only and test commands so routine work needs no prompts; deny secrets and anything that touches shared or production systems. Template in the reference file. Principles:

  • Allow narrowly by prefix: Bash(pnpm test *), not Bash(pnpm *) (which includes pnpm publish).
  • Deny reads of .env*, key files, and cloud credentials, and pair it with the sandbox or a Bash guard hook because a Read deny does not stop cat .env through Bash.
  • Leave git push, deploys, migrations against shared DBs, and package publishing in the ask path (no allow rule) or deny them.
  • Personal preferences go in .claude/settings.local.json; make sure .gitignore covers it even if Claude Code already set up an ignore for it.

5. Formatter hook

One PostToolUse hook on Edit|Write|MultiEdit that formats only the edited file. Pipe-test it with sample JSON before registering (see the template). A Stop-hook test gate is optional; add it only when the suite runs in under ~60 s.

6. Ignore files and MCP

.claude/settings.local.json
CLAUDE.local.md

Add .mcp.json only for servers the whole team uses, with ${VAR} references for tokens, never literal secrets. Prefer CLIs already installed (gh, aws) over MCP servers that duplicate them.

7. Fresh-session acceptance test

Start a new session in the repo (no prior context) and ask, in order:

  1. “What command runs a single test for <file>?” — answered from CLAUDE.md, no search.
  2. “Add <tiny change> and prove it works.” — runs the single-test command without a permission prompt; formatter hook fires; no edits to generated files.
  3. “Show me the contents of .env.” — refused by permissions or hook.
  4. “Push this branch.” — prompts or is denied, never silent.

Every exploration step or unexpected prompt points to a missing line in CLAUDE.md or a missing allow rule. Fix and rerun. Run /doctor for config validation, /context to check the CLAUDE.md token cost, and /permissions to review the merged rules.

Gotchas

  • Committing settings.json with defaultMode: bypassPermissions or broad Bash(*) allows. Never; that is a per-person decision, ideally inside a container.
  • Duplicating the same rules in CLAUDE.md, AGENTS.md, and Cursor files; they drift. Pick one source and import it.
  • Writing aspirational commands (“run make test”) that the repo does not have.
  • Hooks that call tools not installed on teammates’ machines (jq, prettier globally). Use project-local binaries (pnpm exec prettier) or Python stdlib.
  • A huge CLAUDE.md costs tokens on every request and lowers adherence; aim under 120 lines, hard cap 200.
  • Monorepos: root CLAUDE.md for shared commands, nested CLAUDE.md per package for local ones; use claudeMdExcludes for other teams’ files.

Output

**Agent bootstrap for <repo>**
| File | Status | Notes |
|---|---|---|
| CLAUDE.md | new, 84 lines | commands, docs map (11 entries), 7 rules, 3 gotchas |
| .claude/settings.json | new | 14 allow, 9 deny; push/deploy left on ask |
| .claude/hooks/format.sh | new | prettier/ruff on edited file, 120 ms |
| .gitignore | updated | settings.local.json, CLAUDE.local.md |
**Commands proven:** install 41 s, typecheck 9 s, unit 22 s, single test 2 s, lint 6 s
**Open items:** e2e needs Docker (not run); `make seed` fails on clean checkout (issue filed)
**Acceptance test:** 4/4 passed in a fresh session

Bundled files

Loaded only when a step in the skill needs them. Review them here before installing.

references/templates.md 139 lines · 3.8 KB
# Bootstrap templates

Adapt every line to the repository. Delete sections that do not apply rather than
leaving placeholders.

## CLAUDE.md

```markdown
# <Project name>

<One sentence: what this service/app does and who uses it.>

## Commands
- Install: `pnpm install --frozen-lockfile`
- Dev server: `pnpm dev` (http://localhost:3000; needs `docker compose up -d db`)
- Typecheck: `pnpm typecheck`
- Lint / format: `pnpm lint` / `pnpm format`
- All tests: `pnpm test`
- Single test: `pnpm vitest run src/path/file.test.ts -t "name"`
- E2E: `pnpm e2e` (slow, ~4 min; run only when touching routes)
- DB migration (local only): `pnpm db:migrate`

## Map
- `src/server/` — API routes; one file per resource
- `src/lib/db/schema.ts` — Drizzle schema; migrations generated into `drizzle/`
- `src/components/ui/` — shared primitives; do not fork, extend
- `docs/adr/` — architecture decisions; read before changing auth or billing

## Rules
- Never edit `drizzle/*.sql` or `src/gen/**` by hand; regenerate.
- New endpoints validate input with the zod schemas in `src/server/schemas/`.
- Money is integer cents everywhere.
- Before saying a task is done: typecheck + single relevant test file pass.

## Gotchas
- Tests share one DB; run `pnpm test:reset` if you see unique-constraint failures.
- `NEXT_PUBLIC_*` vars are inlined at build time; changing them needs a rebuild.

@docs/agent-notes.md
```

## .claude/settings.json (committed baseline)

```json
{
  "permissions": {
    "allow": [
      "Bash(pnpm test *)",
      "Bash(pnpm vitest run *)",
      "Bash(pnpm typecheck)",
      "Bash(pnpm lint *)",
      "Bash(pnpm format *)",
      "Bash(git status *)",
      "Bash(git diff *)",
      "Bash(git log *)",
      "Bash(git switch -c *)"
    ],
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./**/*.pem)",
      "Read(~/.aws/**)",
      "Read(~/.ssh/**)",
      "Bash(pnpm publish *)",
      "Bash(git push --force *)",
      "Bash(terraform apply *)",
      "Bash(kubectl * --context prod*)"
    ]
  },
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/format.sh", "timeout": 30 }
        ]
      }
    ]
  }
}
```

Leave `git push`, deploy, and shared-DB commands without allow rules so they prompt.

## .claude/hooks/format.sh

```bash
#!/usr/bin/env bash
# Format only the file Claude just edited. Never fail the tool call.
set -u
file=$(python3 -c 'import json,sys; d=json.load(sys.stdin); print(d.get("tool_input",{}).get("file_path",""))' 2>/dev/null)
[ -z "$file" ] || [ ! -f "$file" ] && exit 0
cd "$CLAUDE_PROJECT_DIR" || exit 0
case "$file" in
  *.ts|*.tsx|*.js|*.jsx|*.json|*.css|*.md) pnpm exec prettier --write "$file" >/dev/null 2>&1 ;;
  *.py) uv run ruff format "$file" >/dev/null 2>&1 && uv run ruff check --fix "$file" >/dev/null 2>&1 ;;
  *.go) gofmt -w "$file" ;;
  *.rs) rustfmt "$file" 2>/dev/null ;;
esac
exit 0
```

Pipe test before registering:

```bash
chmod +x .claude/hooks/format.sh
echo '{"tool_name":"Edit","tool_input":{"file_path":"'"$PWD"'/src/index.ts"}}' \
  | CLAUDE_PROJECT_DIR="$PWD" .claude/hooks/format.sh; echo "exit=$?"
```

## Path-scoped rule (`.claude/rules/frontend.md`)

```markdown
---
paths:
  - "src/components/**"
  - "src/app/**"
---
- Server Components by default; add "use client" only for state, effects, or handlers.
- Tailwind only; no new CSS files.
```

## .mcp.json (team-shared, no secrets)

```json
{
  "mcpServers": {
    "sentry": {
      "type": "http",
      "url": "https://mcp.sentry.dev/mcp"
    },
    "postgres-local": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres", "${LOCAL_DATABASE_URL:-postgresql://localhost:5432/app_dev}"]
    }
  }
}
```

About this skill

Written and maintained by the Claude Skills editors to the same editorial standard as every skill in the directory: a selective trigger, a real workflow, known pitfalls and a verification step. First published , last updated . MIT licensed.

esc