Skip to content
Back to skills

Bootstrap Project

ASecurity

Bootstrap a fresh or existing repo with nyann. TRIGGER when the user says "set up this project", "initialize git workflow", "bootstrap this repo", "scaffold this project", "ngyamm this repo", "use my <name> profile" / "apply the nextjs-prototype profile" (profile mode). ALSO trigger on "standard setup" / "usual stack" / "the usual setup" / "install all the standard hooks" / "give this repo the usual setup" / "make this repo standard" / "install nyann" — these read as opinionated bulk setup, n...

  • 6 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added May 26, 2026
developmentjavascripttypescriptpythonrustgojavabashreactnextjsnode

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned May 27, 2026

npx -y skills add thettwe/nyann --skill bootstrap-project --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Bootstrap Project?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Bootstrap Project
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/thettwe-bootstrap-project/badge)](https://www.skillsdirectory.com/skills/thettwe-bootstrap-project)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: bootstrap-project
description: >
  Bootstrap a fresh or existing repo with nyann. TRIGGER when the user says "set up this project",
  "initialize git workflow", "bootstrap this repo", "scaffold this project", "ngyamm this repo",
  "use my <name> profile" / "apply the nextjs-prototype profile" (profile mode).
  ALSO trigger on "standard setup" / "usual stack" / "the usual setup" /
  "install all the standard hooks" / "give this repo the usual setup" /
  "make this repo standard" / "install nyann" — these read as opinionated bulk setup,
  not narrow edits, even though they sound small.
  Also trigger on any phrasing that mentions wiring up git hooks + branching +
  conventions + docs as a single opinionated setup. DO NOT trigger on narrow requests
  like "add a lint hook" or "update CLAUDE.md" — those are edits, not bootstraps.
  DO NOT trigger on "audit this project" / "fix what's drifted" / "bring into compliance" —
  those are retrofit. DO NOT trigger on "check this project's health" / "is this healthy" —
  those are doctor.
  When in doubt, run the detection step and ask.
---

# bootstrap-project

You are executing nyann's main bootstrap flow. The goal is to take an empty directory, a fresh
repo, or an existing messy repo and bring it up to the conventions in a nyann profile — without
silently mutating anything.

**Work in phases.** Each phase is one or more bash scripts in `bin/`. Never run a destructive
action outside a preview-confirmed plan. If a phase emits a structured skip record
(`{"skipped": "...", "reason": "..."}`), log it in your final summary and continue with the
remaining phases.

## 0. Team profile freshness check (quick, non-blocking)

Run `bin/check-team-staleness.sh` before starting. If it produces
output, show the notification to the user (e.g. "Your team profiles
have upstream changes. Run `/nyann:sync-team-profiles` to update
before bootstrapping, or continue with the current versions.").
Do not block — let the user decide whether to sync first.

## 1. Detect

1. Run `bin/detect-stack.sh --path <target>` and capture the JSON to a temp file
   (e.g. `bin/detect-stack.sh --path <target> > "${TMPDIR:-/tmp}/nyann-stack.json"`)
   so step 2 can pass it via `--stack`. Never proceed without it.
2. If `confidence < 0.6`, tell the user what you found and ask them to confirm the stack before
   continuing. Show the top two or three reasoning entries so they can see *why* you chose what
   you chose.
3. If `is_monorepo` is true, note it — bootstrap will auto-resolve per-workspace configs
   (hooks, lint-staged entries, commit scopes) using `bin/resolve-workspace-configs.sh`.

See `references/python.md` and `references/javascript.md` for stack-specific notes Claude should
fold into its follow-ups. Only load them when the detected stack matches.

## 2. Pick a profile

Three branches:

- **User named a profile.** Load it with `bin/load-profile.sh <name>`. If the loader exits 2
  (profile not found), list the available profiles it reported and ask the user to pick one.
- **No profile named.** Run `bin/suggest-profile.sh --target <repo> --stack <stack-json-file>`
  to get a ranked list of matching profiles with confidence scores. Pass the StackDescriptor
  JSON captured in step 1 via `--stack` so the script reuses it instead of re-running
  detect-stack.sh (which would duplicate the directory walk).

  Show the user the top suggestion (or top 2-3 if scores are close):
  > "Detected: TypeScript + Next.js. Suggested profile: `nextjs-prototype` (confidence: 90).
  > Use this profile?"

  Rules:
  - If the top suggestion has confidence ≥ 70, propose it directly.
  - If the top suggestion has confidence 40-69, propose it but ask the user to confirm.
  - If no suggestion has confidence ≥ 40, fall back to `default` — **warn the user**
    because `default` means "skip all stack-specific hooks".
  - If suggestions is empty (no matches at all), use `default` with the same warning.

  **Multi-stack repos (monorepo with workspace_suggestions):** If the
  `workspace_suggestions[]` array is non-empty, each workspace has its own
  best-matching profile. Present per-workspace profile assignments to the user:

  > "This monorepo has multiple stacks. Here are the suggested profiles:
  >
  > | Workspace | Stack | Suggested profile | Confidence |
  > |-----------|-------|-------------------|------------|
  > | apps/web | TypeScript + Next.js | `nextjs-prototype` | 90 |
  > | apps/api | TypeScript + Express | `node-api` | 85 |
  > | apps/mobile | Dart + Flutter | `flutter-app` | 92 |
  >
  > Accept these assignments?"

  Rules for workspace profiles:
  - If `workspace_suggestions[].confidence >= 70`, propose it directly.
  - If confidence 40-69, include but flag for confirmation.
  - If confidence < 40 or suggestion is null, workspace inherits the root profile.
  - User can override any workspace assignment (e.g., "use `react-vite` for apps/web
    instead").
  - Confirmed workspace→profile mappings are written into the root profile's
    `workspaces` field with `"profile": "<name>"` entries. This persists the choice
    for future bootstraps.

  **Legacy secondary_suggestions:** If `workspace_suggestions` is empty but
  `secondary_suggestions` is non-empty, fall back to the legacy behaviour:
  mention the secondary stacks as informational.

- **Audit mode** ("check hygiene", "is this healthy"). Invoke the `doctor` skill instead.
- **Retrofit mode** ("fix what's drifted", "bring into compliance"). Invoke the `retrofit`
  skill instead — it handles audit + remediation for existing repos.

## 3. Recommend branching (unless the profile already pins one)

1. Pipe the StackDescriptor into `bin/recommend-branch.sh`.
2. If `needs_user_confirm` is true, show the three top reasoning strings and ask the user to
   confirm before writing the strategy into the plan.
3. Otherwise, feed the recommendation straight into the action plan.

## 4. Route docs

### 4a. Archetype prompt (v1.6.0+)

The StackDescriptor from step 1 carries an `archetype` field
(`api-service` / `cli-tool` / `library` / `web-app` / `mobile-app` /
`plugin` / `unknown`). When it's anything other than `unknown` AND
the resolved profile does not already declare
`documentation.use_archetype_scaffolds: true`, prompt the user via
`AskUserQuestion`:

```json
{
  "questions": [{
    "question": "Detected archetype: <archetype>. Enable archetype-aware Project Memory scaffolding?",
    "header": "Project Memory",
    "options": [
      {"label": "Yes (recommended)", "description": "Scaffold api-reference, runbook, deployment, glossary as appropriate for this system."},
      {"label": "No", "description": "Use the profile's flat scaffold list (pre-v1.6.0 behaviour)."}
    ],
    "multiSelect": false
  }]
}
```

If the user picks **Yes**, pass `--archetype <archetype>
--use-archetype-scaffolds` to `bin/route-docs.sh` in the next step.
If **No**, pass nothing extra (current behaviour). Skip the prompt
entirely when archetype is `unknown` or when the profile already
sets `use_archetype_scaffolds: true`.

### 4a-2. Glossary auto-population (v1.7.0+)

When the resolved scaffold set includes `glossary` (either via the
profile's `documentation.scaffold_types` OR via an enabled archetype
map for `library` / `api-service` / others), prompt the user via
`AskUserQuestion`:

```json
{
  "questions": [{
    "question": "Auto-populate `docs/glossary.md` with detected exported types from your codebase?",
    "header": "Glossary",
    "options": [
      {"label": "Yes (recommended)", "description": "Seed entries for top-level exported structs/interfaces/classes/types. Idempotent, preserves user content outside markers."},
      {"label": "No",  "description": "Keep the empty template. You can opt in later via the profile."}
    ],
    "multiSelect": false
  }]
}
```

If **Yes**, set `documentation.glossary.auto_populate: true` in the
resolved profile snapshot before passing it to `bootstrap.sh`. The
bootstrap orchestrator reads the flag and forwards
`--auto-glossary` (plus `--glossary-max-terms` /
`--glossary-languages`) to `bin/scaffold-docs.sh`. Default Yes for
the `library` and `api-service` archetypes; default No otherwise.

### 4b. Run route-docs

1. Run `bin/detect-mcp-docs.sh --project-path <target>` to discover Obsidian / Notion connectors
   and local vaults. Capture the JSON.
2. If `available[]` is empty AND `discoverable_vaults[]` is empty, run `bin/route-docs.sh
   --profile <path>` with no MCP flags — plan is local-only. Pass the archetype flags from 4a
   if the user opted in.
3. If `available[]` is empty but `discoverable_vaults[]` is non-empty, offer the user:
   > "Found Obsidian vault(s) on disk: `<vault_name>` (`<vault_path>`).
   > Would you like to route docs to Obsidian? I can connect directly to
   > the vault, or you can add the Obsidian MCP server for full integration."
   - If user says yes to direct connection: use the vault path directly with
     `--obsidian-vault <vault_name>` and proceed with MCP routing flow.
   - If user declines: fall back to local-only routing.
4. If any MCP connector is available, load `references/mcp-routing.md` and walk the user through
   local vs MCP vs split. It covers the questions to ask, how to compose the `--routing` string,
   the connector-target inputs (`--obsidian-vault`, `--obsidian-folder`, `--notion-parent`),
   and the post-route creation flow (MCP tool calls per non-local target + plan update with
   returned identifiers). Archetype flags from 4a propagate the same way.

Capture the resulting `DocumentationPlan`. `memory/` stays local by invariant regardless of
any routing choice.

### 4c. Doc conformance check (v1.9.0+)

After routing, scan for existing documentation that doesn't follow nyann conventions:

1. Run `bin/detect-doc-conformance.sh --target <repo> --archetype <archetype>`.
2. If the output array is non-empty, present the proposals to the user via `AskUserQuestion`:

```json
{
  "questions": [{
    "question": "Found existing docs that don't follow nyann conventions. Reorganize them?",
    "header": "Doc layout",
    "options": [
      {"label": "Yes, reorganize all", "description": "Move/rename all detected docs to their canonical paths (uses git mv when tracked)."},
      {"label": "Let me pick", "description": "Show the list so I can approve each move individually."},
      {"label": "No, leave as-is", "description": "Keep current paths. Scaffolding will skip those categories since files already exist."}
    ],
    "multiSelect": false
  }]
}
```

If **Yes, reorganize all**: write the full proposals JSON to a temp file and run
`bin/reorganize-docs.sh --target <repo> --moves <proposals.json> --apply`. (Without
`--apply`, the script previews and exits without mutating; pass `--apply` once the
user has approved the moves.)

If **Let me pick**: show a table of proposals (source → target, confidence, reason) and
ask the user which to approve. Filter the array to approved-only, then run reorganize-docs.

If **No**: skip. The scaffolder's idempotency means it won't create docs where
non-conforming versions already exist at other paths — but the user keeps their layout.

After reorganization, any moved files now occupy canonical paths. The subsequent scaffold
step will detect them as "exists" and skip creation — preserving user content that was moved
into place.

## 5. Build and preview the plan

Compose an ActionPlan JSON from the profile + StackDescriptor + DocumentationPlan + BranchingChoice.
The shape:

```json
{
  "writes":   [{ "path": "...", "action": "create|merge|overwrite", "bytes": 123 }],
  "commands": [{ "cmd": "git init", "cwd": "." }],
  "remote":   []
}
```

**Required writes[] entries** — include each one the profile/plan opts into; bootstrap.sh will
refuse to materialise a file that isn't in this list (preview-before-mutate):

- `.gitignore` — when gitignore templates apply
- `.editorconfig` — when `profile.extras.editorconfig == true`
- `CLAUDE.md` — when `profile.extras.claude_md == true`
- `.husky/pre-commit`, `.husky/commit-msg`, `commitlint.config.js` — for JS/TS hook phase
- `.pre-commit-config.yaml` — for Python hook phase
- `.git/hooks/commit-msg`, `.git/hooks/pre-commit` — always for core hooks
- Doc files per DocumentationPlan (`docs/architecture.md`, `docs/prd.md`,
  `docs/decisions/ADR-000-…md`, `docs/research/README.md`) — when the profile's
  `documentation.scaffold_types` declares them

### 5a. Pre-render merge previews (v1.7.0+)

Before invoking `preview.sh`, run `bin/render-plan.sh` so merge actions
on `.gitignore` and `CLAUDE.md` carry a `preview_blob` field. Preview
diffs against the current file and shows the operator the actual lines
about to be added — no more "234 B merged" surprises.

```
bin/render-plan.sh \
  --plan <plan.json> \
  --target <repo> \
  --profile <profile.json> \
  --doc-plan <doc-plan.json> \
  --stack <stack.json> \
  --templates-csv "<inferred-from-stack>" \
  --output <plan.rendered.json>
```

Determine `--templates-csv` from the StackDescriptor exactly the way
`bootstrap.sh` does (jsts / python / go / rust / generic, plus
secondary languages). Skip render-plan only when the plan has zero
merge actions for the two covered paths — render-plan is a no-op in
that case so it's safe to always call.

The rendered plan supersedes the original for both preview and execute.
Pass it as `--plan <plan.rendered.json>` from this point on.

### 5b. Preview

Pipe the rendered plan through `bin/preview.sh --plan <file> --target <repo>`.
Pass `--target` so the merge-diff renderer resolves `.path` entries
against the actual repo (not the caller's cwd). Show the stderr
preview to the user. If they respond with `skip <path>`, re-invoke
with `--skip <path>` and reshow. If `no`, stop and exit.

## 6. Execute

Capture the plan SHA-256 first — `bin/preview.sh --plan <file> --emit-sha256` prints just the
hex on stdout. Pass it as `--plan-sha256` so bootstrap can recompute and verify the bytes
haven't changed between the user's "yes" and execution. The SHA binding is required;
bootstrap refuses to run without it.

```
sha=$(bin/preview.sh --plan <confirmed-plan.json> --emit-sha256)
bin/bootstrap.sh --plan <confirmed-plan.json> --plan-sha256 "$sha" \
  --target <repo> --profile <path> --doc-plan <path> --stack <path>
```

bootstrap.sh handles:

1. `git init` if needed.
2. Creating base branches per the strategy.
3. Writing files in the plan.
4. Running install commands (declared in the plan, never inferred).
5. Calling `bin/install-hooks.sh` with the matching phase flags (`--core`, `--jsts`, `--python`).
   For monorepos, also passes `--workspace-configs` (per-workspace lint-staged entries) and
   `--commit-scopes` (workspace-derived scopes for commitlint).
6. Calling `bin/scaffold-docs.sh` with the DocumentationPlan.
7. Calling `bin/gen-claudemd.sh` with profile + plan + stack.
   For monorepos, also passes `--workspace-configs` (renders Workspaces table) and
   `--extra-scopes` (merges workspace scopes into conventions table).

Every step is idempotent. On any failure, bootstrap.sh aborts cleanly with which step failed in
its summary; surface that verbatim. Do not retry automatically.

## 7. Offer the post-bootstrap nudges

After success, ask *only these three* — in order:

1. "Save this as a profile for reuse?" → if yes, ask for a profile name,
   then call `bin/learn-profile.sh --target <repo> --name <slug>`.
   Both `--target` and `--name` are required flags — never pass the name
   as a positional argument.
2. "Run `/nyann:doctor` now to audit?" → invoke the doctor skill. Pass the
   **bare profile name** (e.g. `python-cli`), not a filesystem path, as
   `--profile`. Doctor's `GITHUB PROTECTION` section will surface whether
   branch / tag protection is in place; tell the user they can re-run
   doctor anytime to verify protection state.
3. "Set up GitHub branch protection?" → invoke `bin/gh-integration.sh`
   (apply mode). For audit-only ("is protection drift on this repo?"),
   doctor already covers it via `bin/gh-integration.sh --check` —
   no separate skill needed.

## Output summary

End with a compact report:

- Detected stack + confidence.
- Profile applied (source: user / starter).
- Files created / merged (count only; the plan has the detail).
- Hook phases run, with any skip records.
- Whether CLAUDE.md was under the soft-cap budget.
- Next steps the user can take.

## When something goes wrong

- Detection confidence low → ask before writing.
- `preview.sh` declined → stop, no cleanup needed (nothing was written).
- Any bin script exits non-zero during execute → do not proceed; show the failing step's stderr
  and exit. The user can re-run after fixing.
- A structured skip record is *not* a failure; include it in the summary but keep going.

Files in this skill

  • SKILL.md16.5 KB
  • references/javascript.md2.1 KB
  • references/mcp-routing.md7.4 KB
  • references/python.md2.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.