Bootstrap Skill
SkillAI & modelsUse this skill when scaffolding the minimum repository structure required by session-orchestrator. Invoked automatically by the Bootstrap Gate when CLAUDE.md, Session Config, or bootstrap.lock is missing. Also available as /bootstrap for manual invocation. Three intensity tiers: fast (demos/spikes), standard (MVPs), deep (production/team).
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Bootstrap Skill skill
What this skill tells your AI
The instructions your AI receives, as published by kanevry/session-orchestrator in skills/bootstrap/SKILL.md and read by ahel’s review.
Overview
This skill runs when the Bootstrap Gate is closed (missing CLAUDE.md, Session Config, or .orchestrator/bootstrap.lock) or when the user invokes /bootstrap directly. It scaffolds the minimum structure required by all session-orchestrator skills, commits it, and writes the lock file that opens the gate for all future invocations.
Anti-bureaucracy contract: On a first-time full bootstrap (no tier flags, no --no-interview), expect 7–9 AskUserQuestion prompts in three fixed blocks — not an open-ended wizard. (1) Tier/stack (Phase 2): one tier-confirmation question, plus an optional second archetype question when PATH_TYPE = public and archetype confidence is low (Standard/Deep only). (2) Owner persona (Phase 3.5): five questions from scripts/lib/owner-interview.mjs (first-run only). (3) Dispatcher autonomy (Phase 3.5.1): one question from scripts/lib/config/dispatcher-autonomy-capture.mjs. Flagged flows (--upgrade, --retroactive, --sync-rules, --ecosystem-health) and --no-interview skip some or all of these blocks.
Invocation Context
Before starting, determine how this skill was invoked:
- Transitive (gate-closed): Invoked from another skill's Phase 0. The user's original intent (their first prompt) is available in context. After bootstrap completes, execution must return to the original skill's Phase 1.
- Direct (
/bootstrap): User invoked manually. Parse$ARGUMENTSfor flags:--fast,--standard,--deep,--upgrade <tier>,--retroactive. Seecommands/bootstrap.mdfor flag semantics.
Store INVOCATION_MODE = transitive | direct.
Mode dispatch (direct invocation only):
- If
--upgrade <tier>is present in$ARGUMENTS: jump to Upgrade Flow section. Do not proceed to Phase 1. - If
--retroactiveis present in$ARGUMENTS: jump to Retroactive Flow section. Do not proceed to Phase 1. - If
--refresh-lockis present in$ARGUMENTS: jump to Refresh-Lock Flow section. Do not proceed to Phase 1. - If
--sync-rulesis present in$ARGUMENTS: jump to Sync-Rules Flow section. Do not proceed to Phase 1. - If
--ecosystem-healthis present in$ARGUMENTS: jump to Ecosystem-Health Flow section. Do not proceed to Phase 1. - Otherwise: continue to Phase 1 below.
Phase 0.5: Determine Private vs. Public Path
Before dispatching to any tier template, read skills/bootstrap/public-fallback.md and execute Step 1 (PATH_TYPE detection). Store the result as PATH_TYPE = private | public. This detection is silent — no user interaction.
private: the existing host-local config resolution found a baseline directory and its reduced contract validated. Useprivate-contract.mdfor selection, templates, commands, CI and rules.public: the resolved baseline is absent, empty, or points to a missing directory. Use plugin-bundled templates.- Existing but invalid configured baseline: abort before dispatch; report the reader's sanitized error reason.
Pass PATH_TYPE into Phase 1 and all subsequent phases. All tier templates (fast-template.md, standard-template.md, deep-template.md) must consult public-fallback.md for CLAUDE.md generation and archetype file sourcing when PATH_TYPE = public.
Phase 1: Detect Tier + Archetype
Read skills/bootstrap/intensity-heuristic.md and execute the tier + archetype recommendation algorithm.
Inputs to the heuristic:
- User's first prompt — the message that triggered this skill (most important signal)
- Repo name —
basename $(git rev-parse --show-toplevel)(secondary signal) - Existing files —
ls -laof repo root (presence ofpackage.json,pyproject.toml, etc. shifts archetype) - $ARGUMENTS flags — if
--fast,--standard, or--deepis present, skip heuristic and use the specified tier directly
Output from Phase 1:
RECOMMENDED_TIER=fast|standard|deepRECOMMENDED_ARCHETYPE= validated private contract ID, public ID, ornullHEURISTIC_REASON= one-sentence explanation of why this tier was chosen (shown to user)PATH_TYPE=private(plan-baseline-path configured and path exists) |public(no baseline)
Detecting PATH_TYPE: Already determined in Phase 0.5 — use the stored PATH_TYPE value. Do not re-run detection.
Fast tier: RECOMMENDED_ARCHETYPE is always null. No stack selection needed.
Phase 2: Present Tier Confirmation (One Question)
Present exactly one AskUserQuestion unless:
$ARGUMENTSincludes--fast,--standard, or--deep(tier pre-selected, skip question)--retroactiveflag (no scaffolding at all, skip to Phase 4)
AskUserQuestion({
questions: [{
question: "Leeres Repo erkannt. Basierend auf '<HEURISTIC_REASON>' empfehle ich **<RECOMMENDED_TIER>**. Passt das?",
header: "Bootstrap",
options: [
{ label: "fast", description: "Nur CLAUDE.md + .gitignore + README. Für Demos, Spikes, Playgrounds." },
{ label: "standard", description: "Fast + package.json/Manifest + TypeScript + Linting + Tests. Für MVPs und echte Produkte." },
{ label: "deep", description: "Standard + CI + CODEOWNERS + CHANGELOG. Für Production, Team, Langlebige Repos." },
{ label: "Abbrechen", description: "Bootstrap abbrechen. Das ursprüngliche Kommando wird ebenfalls abgebrochen." }
],
multiSelect: false
}]
})
Before rendering: append (Empfohlen) to whichever of the three tier labels equals <RECOMMENDED_TIER>, and move that option to position 1. The recommended tier is one of the three — listing it a fourth time as its own option made five options, one more than AskUserQuestion accepts, and repeated the same choice twice.
If user selects "Abbrechen": stop. Report "Bootstrap abgebrochen. Kein Kommando wird ausgeführt." Do not continue.
Store confirmed tier as CONFIRMED_TIER.
Optional Second Question (Public Path + Standard/Deep + Ambiguous Archetype Only)
If ALL of the following are true:
PATH_TYPE = publicCONFIRMED_TIERisstandardordeepintensity-heuristic.mdreturnedARCHETYPE_CONFIDENCE = low(truly ambiguous)
Then ask one more question — and only then:
AskUserQuestion({
questions: [{
question: "Welchen Tech-Stack soll ich für das Grundgerüst verwenden?",
header: "Archetype",
options: [
{ label: "node-minimal", description: "package.json + TypeScript + Vitest. Für CLIs, Tools, Libraries." },
{ label: "nextjs-minimal", description: "Next.js bare setup. Für Web Apps, SaaS, Fullstack." },
{ label: "static-html", description: "HTML/CSS/JS, kein Build-Step. Für Animationen, Landingpages, Visualisierungen." },
{ label: "python-uv", description: "pyproject.toml + uv + pytest. Für Python Scripts, APIs, ML." }
],
multiSelect: false
}]
})
Store as CONFIRMED_ARCHETYPE.
For PATH_TYPE = private and Standard/Deep, execute private-contract.md's
Select section now. Reuse a valid detected or explicit ID; when evidence is
insufficient, select from the returned catalog before scaffolding. Tier flags
skip tier confirmation, not required private archetype selection. Never pass a
null private ID into the public default. On upgrades, validate the lock's ID
against the currently configured contract before generating any files.
The tier/stack block contributes 1–2 questions; a first-run full bootstrap adds 6 more from the owner interview (Phase 3.5, five questions) and dispatcher-autonomy capture (Phase 3.5.1, one question) — 7–9 total.
Upgrade Flow (--upgrade <tier>)
Entered when $ARGUMENTS contains --upgrade <tier>. No scaffolding questions are asked.
Steps:
-
Read existing lock. Read
.orchestrator/bootstrap.lock. If missing, abort with:Error: No bootstrap.lock found. Run /bootstrap first to bootstrap this repo. -
Parse current and target tier.
CURRENT_TIER= value oftier:field in the lock file.TARGET_TIER= the<tier>argument supplied after--upgrade.- Valid values for both:
fast|standard|deep.
-
Refuse downgrade. Tier order:
fast < standard < deep. IfTARGET_TIERranks lower than or equal toCURRENT_TIER, abort with:Error: Cannot downgrade from <CURRENT_TIER> to <TARGET_TIER>. Upgrade path is one-directional (fast → standard → deep).Exit non-zero. -
Resolve source and compute delta. Run Phase 0.5's read-only source detection before dispatching any template. For a private contract, validate the lock's archetype with
--archetype; if the Fast lock has no archetype, select from the returned catalog usingprivate-contract.md. Use its staged, additive scaffold and CI expectations; do not apply the public file matrix. For the public path, determine which files the target tier adds:fast → standard: all Standard-tier files (package.json/pyproject.toml,tsconfig.json,eslint.config.mjs,.prettierrc,.editorconfig,tests/,src/)standard → deep: all Deep-tier files (CI pipeline,CODEOWNERS,CHANGELOG.md, issue templates, MR/PR template, branch protection)fast → deep: union of both deltas (apply Standard first, then Deep)
-
Check idempotency. For each file in the delta, skip if it already exists on disk. Only write files that are absent. This makes the operation safe to run twice.
-
Apply delta files. Execute only the relevant template steps for the missing files. Read the appropriate template (
standard-template.mdand/ordeep-template.md) and execute ONLY the steps that produce the delta files. Do NOT re-run already-completed steps. -
Update bootstrap.lock atomically. Overwrite
.orchestrator/bootstrap.lockwithtier: <TARGET_TIER>. Preserve a validated existingarchetype; when upgrading a null Fast archetype, record the newly confirmed ID and scaffold source. Updatetimestampto now. Preserve the priorsourceotherwise. Writeplugin-versionfrom$PLUGIN_ROOT/package.json(current plugin version at upgrade time). -
Commit. Stage only the delta files that were just written and commit:
# DELTA_FILES must be populated with the explicit list of files written in step 6 for _f in "${DELTA_FILES[@]}"; do [[ -e "$_f" ]] && git add -- "$_f" done git commit -m "chore: bootstrap upgrade to <TARGET_TIER>" -
Report. Print a one-line summary:
Bootstrap upgraded from <CURRENT_TIER> to <TARGET_TIER>. <N> files added.
Retroactive Flow (--retroactive)
Entered when $ARGUMENTS contains --retroactive. Writes the lock file and, per #182, optionally patches missing mandatory Session Config fields with defaults.
Purpose: Adopt an existing repo that already has CLAUDE.md + ## Session Config but was bootstrapped manually (no bootstrap.lock). Writes the lock so the gate passes on all future invocations, and ensures the Session Config block satisfies the validated schema defined in scripts/lib/config-schema.mjs.
Steps:
-
Verify preconditions. Confirm
CLAUDE.md(orAGENTS.md) exists and contains## Session Config. If not, abort:Error: CLAUDE.md with Session Config required for retroactive bootstrap. -
Check lock not already present. If
.orchestrator/bootstrap.lockalready exists and has validversion+tierfields, report:bootstrap.lock already present (tier: <tier>). Nothing to do.and exit 0 (idempotent). -
Infer tier from file inventory. Examine the repo root:
Condition (evaluated in order) Inferred Tier CI file present ( .gitlab-ci.ymlOR.github/workflows/) ANDCHANGELOG.mdpresentdeepPackage manifest present ( package.jsonORpyproject.toml)standardNeither of the above fastStore as
INFERRED_TIER. -
Infer archetype. Run Phase 0.5's read-only source detection. For a private contract, use its detected
selected.id; retainnullwith an explicitinsufficient-evidencereport if no markers match. An invalid configured contract aborts. Do not scaffold or apply rules in this retroactive flow. For the public path, use best-effort detection from existing files:pyproject.tomlpresent →python-uvpackage.jsonwithnextin dependencies →nextjs-minimalpackage.jsonwithoutnext→node-minimal- No manifest →
null
Store as
INFERRED_ARCHETYPE. -
Write bootstrap.lock. Create
.orchestrator/if needed, then write:# .orchestrator/bootstrap.lock version: 1 tier: <INFERRED_TIER> archetype: <INFERRED_ARCHETYPE or null> timestamp: <current ISO 8601 UTC> source: retroactive plugin-version: <current plugin version from $PLUGIN_ROOT/package.json> -
Patch Session Config (#182). Run the validator against the current
## Session Configblock; append any missing mandatory fields with defaults. The 7 mandatory fields (perscripts/lib/config-schema.mjs) are:test-command,typecheck-command,lint-command,agents-per-wave,waves,persistence,enforcement.CONFIG_OUT="$(node "$PLUGIN_ROOT/scripts/parse-config.mjs" 2>&1 >/dev/null)" # parse-config.mjs emits validation warnings to stderr when enforcement=warn. # Grep for 'must be' lines (issued by validate-config.mjs) to detect missing fields. MISSING_FIELDS="$(echo "$CONFIG_OUT" | grep -oE '(test-command|typecheck-command|lint-command|agents-per-wave|waves|persistence|enforcement)' | sort -u || true)" if [[ -n "$MISSING_FIELDS" ]]; then # Detect package manager to pick sensible defaults for commands. PM_DEFAULTS="$(node --input-type=module -e " import {detectPackageManager, defaultQualityGateCommands} from '$PLUGIN_ROOT/scripts/lib/package-manager.mjs'; const pm = detectPackageManager(process.cwd()); const cmds = defaultQualityGateCommands(pm); console.log('test-command: ' + cmds.test.command); console.log('typecheck-command: ' + cmds.typecheck.command); console.log('lint-command: ' + cmds.lint.command); " 2>/dev/null)" CONFIG_FILE="CLAUDE.md" [[ -f "AGENTS.md" ]] && CONFIG_FILE="AGENTS.md" # Append each missing field under the ## Session Config block. for field in $MISSING_FIELDS; do case "$field" in test-command|typecheck-command|lint-command) default_line="$(echo "$PM_DEFAULTS" | grep "^$field:")" ;; agents-per-wave) default_line="agents-per-wave: 6" ;; waves) default_line="waves: 5" ;; persistence) default_line="persistence: true" ;; enforcement) default_line="enforcement: warn" ;; esac # Insert after `## Session Config` line if not already present. grep -q "^$field:" "$CONFIG_FILE" \ || awk -v insert="$default_line" '/^## Session Config/ && !done { print; print ""; print insert; done=1; next } { print }' "$CONFIG_FILE" > "$CONFIG_FILE.tmp" \ && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE" done echo "Patched $CONFIG_FILE with defaults for: $MISSING_FIELDS" fiThis patch is best-effort: existing fields are never overwritten. If no fields are missing, this step is a no-op.
-
Commit. Stage the lock file (and the patched config file, if it changed) and commit:
mkdir -p .orchestrator git add .orchestrator/bootstrap.lock # Also stage CLAUDE.md/AGENTS.md if step 6 patched it. git diff --name-only --cached CLAUDE.md AGENTS.md 2>/dev/null | head -1 >/dev/null || { [[ -f CLAUDE.md ]] && git diff --quiet CLAUDE.md || git add CLAUDE.md [[ -f AGENTS.md ]] && git diff --quiet AGENTS.md || git add AGENTS.md } git commit -m "chore: bootstrap lock (retroactive)" -
Report. Print:
Retroactive bootstrap complete. Lock written (tier: <INFERRED_TIER>, source: retroactive).Include a second linePatched Session Config: <fields>when step 6 applied any patches, otherwiseNo config changes..
Refresh-Lock Flow (--refresh-lock)
Entered when $ARGUMENTS contains --refresh-lock. No scaffolding questions are asked, and — unlike the Retroactive Flow above — this is NOT a no-op once the lock already has valid version/tier fields: refreshing is the load-bearing action.
Purpose (#57): Acknowledge the current plugin version and reset the freshness clock on an existing, already-valid bootstrap.lock without disturbing its original bootstrap provenance. This closes the gap left by the Retroactive Flow: once a lock already has version + tier, re-running /bootstrap --retroactive reports "bootstrap.lock already present ... Nothing to do." and changes nothing — exactly the no-op the bootstrap-lock-freshness probe (#186/#290) was recommending as its remediation. --refresh-lock is the actual remediation for a present-but-stale or version-drifted lock.
Steps:
-
Precondition check. Read
.orchestrator/bootstrap.lock. If missing, or present but missing a non-emptyversionortierfield, abort with:Error: No valid bootstrap.lock found. Run /bootstrap or /bootstrap --retroactive first.Do not fabricate a lock — this flow only refreshes an existing one. -
Resolve the current plugin version. Read
plugin-versionfrom$PLUGIN_ROOT/package.json(same source Phase 4 uses). -
Call the refresh writer.
import { refreshBootstrapLock } from '$PLUGIN_ROOT/scripts/lib/bootstrap-lock-refresh.mjs'; const result = refreshBootstrapLock({ repoRoot: REPO_ROOT, currentPluginVersion: PLUGIN_VERSION, });refreshBootstrapLockwrites (or replaces, if already present) exactly two lines —refreshed-at: <ISO 8601 UTC>andrefreshed-plugin-version: <current plugin version>— via the same atomic tmp-file + rename pattern used by the Retroactive Flow's lock write: write to a sibling tmp file, then rename over the target so the lock is never observed half-written. Every other line of the lock —bootstrapped-at,timestamp,plugin-version,tier,archetype,source, … — is left byte-identical. This is the provenance-honesty guarantee: a refresh is an acknowledgement, not a re-bootstrap. On failure (result.ok === false), surfaceresult.messageand stop — do not retry with a fabricated lock. -
No auto-commit. Unlike the Retroactive Flow,
--refresh-lockdoes not stage or commit. The refreshed lock is a small, reviewable diff (two changed/added lines); the user commits it alongside their own work at their own cadence. -
Report. Print:
Lock refreshed (refreshed-at: <now>, plugin-version: <current>). Original bootstrap provenance unchanged.
Idempotency. Running /bootstrap --refresh-lock twice in a row replaces the same two lines in place — it never duplicates them.
Sync-Rules Flow (--sync-rules)
Entered when $ARGUMENTS contains --sync-rules. This standalone flow skips tier
selection, scaffolding and initial commit. Rule selection may read the lock ID.
Purpose: Vendor canonical rules from the plugin's rules/ library (rules/always-on/*.md, and in the future rules/opt-in-stack/*.md and rules/opt-in-domain/*.md) into the consumer repo's .claude/rules/. Plugin-sourced files (identified by a <!-- source: session-orchestrator plugin … --> header) are overwritten on re-run; files without that header are preserved as local overrides. See rules/_index.md for the canonical manifest and scripts/lib/rules-sync.mjs for the implementation.
Steps:
-
Resolve plugin root. The plugin's
rules/_index.mdlives next toSKILL.md's plugin directory. Use the plugin root inferred by the harness (PLUGIN_ROOT). -
Invoke the bootstrap rule action. It reloads a configured private contract and supplies required plugin basenames to
scripts/lib/rules-sync.mjs. With no baseline, the writer's public/default behavior is unchanged. Map an explicit--archetype IDtoCONFIRMED_ARCHETYPE,--dry-runtoDRY_RUN=true, and optional category selections to comma-separatedRULES_CATEGORIES; otherwise leave those variables unset. Run from the repo:export PLUGIN_ROOT CONFIRMED_ARCHETYPE DRY_RUN RULES_CATEGORIES node --input-type=module <<'NODE' import { pathToFileURL } from 'node:url'; const { syncBootstrapRules } = await import(pathToFileURL(`${process.env.PLUGIN_ROOT}/scripts/lib/baseline-archetypes.mjs`)); const categories = (process.env.RULES_CATEGORIES || '').split(',').map(value => value.trim()).filter(Boolean); const result = await syncBootstrapRules({ repoRoot: process.cwd(), archetype: process.env.CONFIRMED_ARCHETYPE || undefined, dryRun: process.env.DRY_RUN === 'true', categories: categories.length ? categories : null }); process.stdout.write(`${JSON.stringify(result)}\n`); if (result.status === 'error') process.exitCode = 2; NODEThe canonical writer reads all selected categories in
rules/_index.mdand writes into.claude/rules/. Required private targets remain subject to its provenance and pre-write checks. Explicit ID takes precedence over lock ID, then repository markers. Invalid private contracts abort before writes. A valid Fast lock witharchetype: nulland no matching markers retains ordinary plugin rule delivery after contract validation. Stdout includesstatus,created[],written[],skipped[],preserved[], anderrors[]. Any error exits non-zero.Add
--dry-runto preview without writing. -
Interpret the output. Report a human summary:
written: files newly created OR plugin-owned files overwritten with fresh canonical content.skipped: plugin-owned files already up-to-date (byte-identical).preserved: existing.claude/rules/*.mdfiles that do NOT carry the plugin source header — left untouched as local overrides.errors: per-file failures (missing source, read/write errors, malformed_index.md).
-
Commit (optional).
--sync-rulesdoes not auto-commit. If rules changed, prompt the user to reviewgit statusand stage/commit the updates manually. Rationale: rules are canonical artifacts and should travel with an intentional review, not land silently. -
Report. Print:
rules-sync complete. Written: <N>. Skipped: <N>. Preserved: <N>. Warnings: <N>. Errors: <N>.warnings[]carries WARN-severity validation findings (e.g. zero-match-globs, foreign-glob) surfaced byvalidateRuleContent— these do NOT block the write; they are informational only. Iferrors > 0, non-zero exit.
Local overrides. Any .claude/rules/<name>.md without the plugin source header is considered local and never overwritten. To replace a local override with the canonical version, delete it before re-running.
Idempotency. Running /bootstrap --sync-rules twice in a row with no upstream changes emits written: 0, skipped: <N>. Safe to wire into CI or scheduled maintenance.
Phase 3: Dispatch to Template
Based on CONFIRMED_TIER, read and execute the corresponding template file:
| Tier | Template File |
|---|---|
fast | skills/bootstrap/fast-template.md |
standard | skills/bootstrap/standard-template.md |
deep | skills/bootstrap/deep-template.md |
Pass the following context into the template execution:
CONFIRMED_TIERCONFIRMED_ARCHETYPEPATH_TYPEREPO_ROOT=$(git rev-parse --show-toplevel)REPO_NAME=$(basename "$REPO_ROOT")PLATFORM= detected platform fromskills/_shared/platform-tools.md
Follow the template's instructions precisely. The template is responsible for creating all files and the initial git commit.
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 50
- Forks
- 7
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
bootstrap-kanevry- Source
- github.com/kanevry/session-orchestrator