Install
$ agentstack add skill-thettwe-nyann-bootstrap-project ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
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
- Run
bin/detect-stack.sh --pathand capture the JSON to a temp file
(e.g. bin/detect-stack.sh --path > "${TMPDIR:-/tmp}/nyann-stack.json") so step 2 can pass it via --stack. Never proceed without it.
- If
confidence. 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 --stack
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
defaultwith 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 "` 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
doctorskill 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)
- Pipe the StackDescriptor into
bin/recommend-branch.sh. - If
needs_user_confirmis true, show the three top reasoning strings and ask the user to
confirm before writing the strategy into the plan.
- 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:
{
"questions": [{
"question": "Detected 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 --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:
{
"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
- Run
bin/detect-mcp-docs.sh --project-pathto discover Obsidian / Notion connectors
and local vaults. Capture the JSON.
- If
available[]is empty ANDdiscoverable_vaults[]is empty, run `bin/route-docs.sh
--profile ` with no MCP flags — plan is local-only. Pass the archetype flags from 4a if the user opted in.
- If
available[]is empty butdiscoverable_vaults[]is non-empty, offer the user:
> "Found Obsidian vault(s) on disk: ` (`). > 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 and proceed with MCP routing flow.
- If user declines: fall back to local-only routing.
- If any MCP connector is available, load
references/mcp-routing.mdand 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:
- Run
bin/detect-doc-conformance.sh --target --archetype. - If the output array is non-empty, present the proposals to the user via
AskUserQuestion:
{
"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 --moves --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:
{
"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— whenprofile.extras.editorconfig == trueCLAUDE.md— whenprofile.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 \
--target \
--profile \
--doc-plan \
--stack \
--templates-csv "" \
--output
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 from this point on.
5b. Preview
Pipe the rendered plan through bin/preview.sh --plan --target . 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 , re-invoke with --skip and reshow. If no, stop and exit.
6. Execute
Capture the plan SHA-256 first — bin/preview.sh --plan --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 --emit-sha256)
bin/bootstrap.sh --plan --plan-sha256 "$sha" \
--target --profile --doc-plan --stack
bootstrap.sh handles:
git initif needed.- Creating base branches per the strategy.
- Writing files in the plan.
- Running install commands (declared in the plan, never inferred).
- Calling
bin/install-hooks.shwith 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).
- Calling
bin/scaffold-docs.shwith the DocumentationPlan. - Calling
bin/gen-claudemd.shwith 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:
- "Save this as a profile for reuse?" → if yes, ask for a profile name,
then call bin/learn-profile.sh --target --name . Both --target and --name are required flags — never pass the name as a positional argument.
- "Run
/nyann:doctornow 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.
- "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.shdeclined → 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.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: thettwe
- Source: thettwe/nyann
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.