Core Bootstrap Skill
Trigger: /core-bootstrap
Bootstrap of the user-global Claude Code configuration. Deploys 4 user-files to ~/.claude/ and creates 4 global symlinks/junctions. Fully idempotent — running again skips anything already in place, so it is always safe to re-run after a git pull or on a new machine. To replace a deployed file, delete it manually first, then re-run.
PHASE 0: Pre-flight
Resolve CONFIG_REPO — the root of the cloned claude-config repo:
# macOS/Linux — follow symlink of ~/.claude/skills if it already exists
if [ -L "$HOME/.claude/skills" ]; then
CONFIG_REPO="$(realpath "$HOME/.claude/skills/..")"
else
# Fallback: current working directory if it is the repo
CONFIG_REPO="$(pwd)"
fi
# Windows
if (Test-Path "$env:USERPROFILE\.claude\skills" -PathType Container) {
$CONFIG_REPO = Split-Path (Resolve-Path "$env:USERPROFILE\.claude\skills") -Parent
} else {
$CONFIG_REPO = (Get-Location).Path
}
Validate that $CONFIG_REPO/local/ exists. If not:
Cannot find local/. Run /core-bootstrap from the claude-config repo directory, or ensure ~/.claude/skills already symlinks to the repo.
Stop.
Check jq availability (advisory only — does not stop execution):
command -v jq >/dev/null 2>&1 || echo "warn: jq not found — settings overlay merge will be skipped if personal/settings.overlay.json is present"
Language selection
Check whether ~/.claude/CLAUDE.md already contains a Language: setting:
grep -q "Language:" "$HOME/.claude/CLAUDE.md" 2>/dev/null && echo "found" || echo "not-found"
If Language: is found → store LANGUAGE_CHOICE=skip (language step skipped — re-runs leave existing setting alone).
If Language: is not found → ask (two sequential modals, 4-option cap per shared/SKILL-PATTERNS.md § Modal Option Cap; show modal 2 only if "More languages →" is picked):
header: "Language"
question: "Which language should Claude use for output?"
options:
- label: "English (Recommended)"
description: "Claude responds in English"
- label: "Nederlands"
description: "Claude responds in Dutch"
- label: "Deutsch"
description: "Claude antwortet auf Deutsch"
- label: "More languages →"
description: "Français, Español"
multiSelect: false
header: "Language"
question: "Which language should Claude use for output?"
options:
- label: "Français"
description: "Claude répond en français"
- label: "Español"
description: "Claude responde en español"
multiSelect: false
Store the chosen label in LANGUAGE_CHOICE (e.g. "Nederlands"). If the user selects "English (Recommended)" → LANGUAGE_CHOICE=skip (template default, no patch needed).
Explanation Level selection
Check whether ~/.claude/CLAUDE.md already contains an Explanation Level: setting:
grep -q "Explanation Level:" "$HOME/.claude/CLAUDE.md" 2>/dev/null && echo "found" || echo "not-found"
If Explanation Level: is found → store EXPLANATION_CHOICE=skip (step skipped — re-runs leave existing setting alone).
If Explanation Level: is not found → ask:
header: "Explanation Level"
question: "How should Claude calibrate jargon and explanation depth by default?"
options:
- label: "Intermediate (Recommended)"
description: "Standard depth. Jargon ok, no extra scaffolding. Good default for most stacks."
- label: "Beginner"
description: "Every non-trivial term explained. Analogies always used. Good for stacks you're learning from scratch."
- label: "Novice"
description: "Framework-specific jargon explained. Analogies when helpful. Between Beginner and standard."
- label: "Expert"
description: "Compact. Assumes full stack familiarity. No term introductions or analogies."
multiSelect: false
Store the chosen label in EXPLANATION_CHOICE (e.g. "Beginner"). If the user selects "Intermediate (Recommended)" → EXPLANATION_CHOICE=skip (template default, no patch needed).
Permission mode selection
settings.json is only copied when it does not already exist. Mirror that for this question — re-runs leave an existing permission posture alone:
[ -f "$HOME/.claude/settings.json" ] && echo "found" || echo "not-found"
If ~/.claude/settings.json is found → store PERM_CHOICE=skip (already configured — don't touch it).
If not found → ask:
header: "Permission mode"
question: "How should Claude handle tool permissions by default?"
options:
- label: "Bypass permissions (Recommended)"
description: "No permission prompts. Safe here because all skills run within guard rails (plan mode, security-reminder + format-on-save hooks, explicit handoff contracts)."
- label: "Auto mode"
description: "Claude's classifier auto-approves safe actions and prompts only on risky/irreversible ones."
multiSelect: false
Store the choice in PERM_CHOICE. If the user selects "Bypass permissions (Recommended)" → PERM_CHOICE=skip (template default: bypassPermissions + disableAutoMode + dangerous-mode dialog pre-accepted, no patch needed). If "Auto mode" → PERM_CHOICE=auto (patched in PHASE 1).
Claude plan tier
Check $CONFIG_REPO/.claude/paths.local.yaml for a persisted value first:
# macOS/Linux
PLAN_TIER=""
if [ -f "$CONFIG_REPO/.claude/paths.local.yaml" ]; then
PLAN_TIER=$(grep "claude_plan:" "$CONFIG_REPO/.claude/paths.local.yaml" | sed 's/.*claude_plan:[[:space:]]*//' | tr -d '"')
fi
# Windows
$planTier = ""
$pathsLocal = "$CONFIG_REPO\.claude\paths.local.yaml"
if (Test-Path $pathsLocal) {
$line = Select-String -Path $pathsLocal -Pattern "claude_plan:" | Select-Object -First 1
if ($line) { $planTier = ($line.Line -replace '.*claude_plan:\s*"?([^"]+)"?.*', '$1').Trim() }
}
If PLAN_TIER is non-empty → skip the question (use persisted value, note it in PHASE 3 report as <value> (saved)).
If PLAN_TIER is empty → ask:
header: "Claude plan"
question: "Which Claude plan are you on? (used to tailor the post-bootstrap tip)"
options:
- label: "Max 5x"
description: 'Tip: /model opus + effortLevel:"high" — full Opus; plan mode is an approval gate, not a routing switch'
- label: "Pro"
description: 'Tip: /model sonnet + effortLevel:"medium" — Opus quota is tight on Pro'
- label: "Max 10x+"
description: 'Tip: /model opus + effortLevel:"high" — quota headroom for full-Opus runs'
- label: "Skip"
description: "No plan-specific tip shown"
multiSelect: false
Store the choice in PLAN_TIER (one of max-5x, pro, max-10x, skip). Write to paths.local.yaml in PHASE 0.5 (see below).
PHASE 0.5: Paths setup
Write per-machine path configuration to $CONFIG_REPO/.claude/paths.local.yaml. Idempotent — skip writing if the file already exists, but validate that its projects_root still points at an existing directory and offer to correct a stale path.
# macOS/Linux
PATHS_LOCAL="$CONFIG_REPO/.claude/paths.local.yaml"
if [ -f "$PATHS_LOCAL" ]; then
PATHS_STATUS="already-exists"
# Validate the configured projects_root still points at an existing directory.
# A stale path (e.g. moved projects folder) leaves the backlog server scanning
# nothing — correct it, but don't re-prompt when the path is fine (stays idempotent).
cur=$(awk -F'"' '/^[[:space:]]*projects_root:/ {print $2; exit}' "$PATHS_LOCAL")
exp="${cur/#\~/$HOME}"; exp="${exp/#\$HOME/$HOME}"
if [ -n "$cur" ] && [ ! -d "$exp" ]; then
# AskUserQuestion (open text input): projects_root "$cur" no longer exists —
# ask for a new absolute path that must exist as a directory. Store in NEW_ROOT.
sed -i '' 's|^\([[:space:]]*projects_root:\).*|\1 "'"$NEW_ROOT"'"|' "$PATHS_LOCAL"
PATHS_STATUS="updated"
fi
else
# Ask the user via AskUserQuestion (open text input — no default, no fallback):
# header: "Projects root"
# question: "What is the absolute path to your projects root? This is where
# /project-add creates new projects.
# Example: /Users/you/projects or /Users/you/Documents/Projects"
# Validate: the path must exist as a directory. If not, re-ask.
# Store input in PROJECTS_ROOT (no fallback — the user must answer).
mkdir -p "$CONFIG_REPO/.claude"
cat > "$PATHS_LOCAL" <<EOF
paths:
projects_root: "$PROJECTS_ROOT"
config_repo: "$CONFIG_REPO"
preferences:
claude_plan: "$PLAN_TIER"
EOF
PATHS_STATUS="written"
fi
# Backfill preferences block if file existed but predates plan-tier
if [ "$PATHS_STATUS" = "already-exists" ] && ! grep -q "claude_plan:" "$PATHS_LOCAL" 2>/dev/null; then
printf '\npreferences:\n claude_plan: "%s"\n' "$PLAN_TIER" >> "$PATHS_LOCAL"
fi
# Windows
$pathsLocal = "$CONFIG_REPO\.claude\paths.local.yaml"
if (Test-Path $pathsLocal) {
$pathsStatus = "already-exists"
# Backfill preferences block if missing (old format)
$content = Get-Content $pathsLocal -Raw
if ($content -notmatch "claude_plan:") {
Add-Content $pathsLocal "`npreferences:`n claude_plan: `"$planTier`""
}
# Validate projects_root still exists; correct a stale path (don't re-prompt if fine).
if ($content -match '(?m)^\s*projects_root:\s*"?([^"\r\n]+)"?') {
$cur = $Matches[1].Trim().TrimEnd('"')
if (-not (Test-Path $cur -PathType Container)) {
# AskUserQuestion (open text input): projects_root "$cur" no longer exists —
# ask for a new absolute path that must exist. Store in $newRoot.
(Get-Content $pathsLocal -Raw) -replace '(?m)^(\s*projects_root:).*', "`$1 `"$newRoot`"" | Set-Content $pathsLocal
$pathsStatus = "updated"
}
}
} else {
# Ask the user via AskUserQuestion (open text input — no default, no fallback):
# header: "Projects root"
# question: "What is the absolute path to your projects root?
# Example: C:\Projects or C:\Users\you\Documents\Projects"
# Validate: the path must exist as a directory. If not, re-ask.
# Store as $projectsRoot (no fallback — the user must answer).
# Ask the user (optional):
# header: "Godot executable"
# question: "Where is your Godot executable? (optional — press Enter / leave empty to skip)"
# Store as $godotPath; if empty, omit from file
New-Item -ItemType Directory -Force -Path "$CONFIG_REPO\.claude" | Out-Null
$lines = @("paths:", " projects_root: `"$projectsRoot`"", " config_repo: `"$CONFIG_REPO`"")
if ($godotPath) { $lines += " godot_executable: `"$godotPath`"" }
$lines += @("preferences:", " claude_plan: `"$planTier`"")
$lines -join "`n" | Set-Content $pathsLocal
$pathsStatus = "written"
}
Note:
paths.local.yamlis read byserve-backlog.js(and other shared tools) vialib/config.jsfallback — so the backlog server finds your projects automatically after bootstrap without any env var setup. Setting env vars in your shell profile (export CLAUDE_PROJECTS_ROOT="...") remains an override option but is no longer required.
PHASE 1: Copy user-files
Copy 4 files to ~/.claude/. Skip if the destination already exists — never overwrites. Create ~/.claude/ if it is missing.
Report the outcome per file (for the PHASE 3 report):
| File | Source | Destination |
|---|---|---|
| CLAUDE.md | $CONFIG_REPO/local/CLAUDE.md.base |
~/.claude/CLAUDE.md |
| settings.json | $CONFIG_REPO/local/settings.json.template |
~/.claude/settings.json |
| keybindings.json | $CONFIG_REPO/local/keybindings.json |
~/.claude/keybindings.json |
| statusline-command.cjs | $CONFIG_REPO/local/statusline-command.cjs |
~/.claude/statusline-command.cjs |
# macOS/Linux
CLAUDE_DIR="$HOME/.claude"
mkdir -p "$CLAUDE_DIR"
LOCAL="$CONFIG_REPO/local"
declare -A FILES=(
["CLAUDE.md"]="$LOCAL/CLAUDE.md.base"
["settings.json"]="$LOCAL/settings.json.template"
["keybindings.json"]="$LOCAL/keybindings.json"
["statusline-command.cjs"]="$LOCAL/statusline-command.cjs"
)
for dest_name in "${!FILES[@]}"; do
src="${FILES[$dest_name]}"
dest="$CLAUDE_DIR/$dest_name"
if [ ! -f "$dest" ]; then
cp "$src" "$dest"
# STATUS: placed
else
: # STATUS: already-exists
fi
done
# Windows
$claudeDir = "$env:USERPROFILE\.claude"
New-Item -ItemType Directory -Force -Path $claudeDir | Out-Null
$local = "$CONFIG_REPO\local"
$files = @{
"CLAUDE.md" = "$local\CLAUDE.md.base"
"settings.json" = "$local\settings.json.template"
"keybindings.json" = "$local\keybindings.json"
"statusline-command.cjs" = "$local\statusline-command.cjs"
}
foreach ($destName in $files.Keys) {
$src = $files[$destName]
$dest = "$claudeDir\$destName"
if (-not (Test-Path $dest)) {
Copy-Item $src $dest
# STATUS: placed
} else {
# STATUS: already-exists
}
}
Language patch
After copying CLAUDE.md (only if it was actually placed, and LANGUAGE_CHOICE is not skip):
Patch the Language: line in ~/.claude/CLAUDE.md and the "language" field in ~/.claude/settings.json to keep them in sync.
# macOS/Linux — CLAUDE.md (portable sed)
sed -i.bak "s/^Language:.*$/Language: $LANGUAGE_CHOICE/" "$HOME/.claude/CLAUDE.md" && rm -f "$HOME/.claude/CLAUDE.md.bak"
# settings.json — prefer jq; fall back to sed
SETTINGS="$HOME/.claude/settings.json"
if command -v jq >/dev/null 2>&1; then
jq --arg lang "$LANGUAGE_CHOICE" '.language = $lang' "$SETTINGS" > "$SETTINGS.tmp" && mv "$SETTINGS.tmp" "$SETTINGS"
else
sed -i.bak "s/\"language\":.*$/\"language\": \"$LANGUAGE_CHOICE\",/" "$SETTINGS" && rm -f "$SETTINGS.bak"
fi
# Windows — CLAUDE.md
(Get-Content "$env:USERPROFILE\.claude\CLAUDE.md") -replace '^Language:.*$', "Language: $LANGUAGE_CHOICE" |
Set-Content "$env:USERPROFILE\.claude\CLAUDE.md"
# settings.json
$settings = "$env:USERPROFILE\.claude\settings.json"
$json = Get-Content $settings -Raw | ConvertFrom-Json
$json.language = $LANGUAGE_CHOICE
$json | ConvertTo-Json -Depth 10 | Set-Content $settings
Explanation Level patch
After copying CLAUDE.md (only if it was actually placed, and EXPLANATION_CHOICE is not skip):
Patch the Explanation Level: line in ~/.claude/CLAUDE.md.
# macOS/Linux — CLAUDE.md
sed -i.bak "s/^Explanation Level:.*$/Explanation Level: $EXPLANATION_CHOICE/" "$HOME/.claude/CLAUDE.md" && rm -f "$HOME/.claude/CLAUDE.md.bak"
# Windows — CLAUDE.md
(Get-Content "$env:USERPROFILE\.claude\CLAUDE.md") -replace '^Explanation Level:.*$', "Explanation Level: $EXPLANATION_CHOICE" |
Set-Content "$env:USERPROFILE\.claude\CLAUDE.md"
Permission mode patch
After copying settings.json (only if it was actually placed, and PERM_CHOICE=auto):
The template ships the recommended bypass posture, so the recommended choice needs no patch. The auto-mode choice flips defaultMode to auto, drops the bypass-only flags, and pre-accepts the auto-mode opt-in dialog.
# macOS/Linux — settings.json (jq preferred, sed fallback)
SETTINGS="$HOME/.claude/settings.json"
if command -v jq >/dev/null 2>&1; then
jq '.permissions.defaultMode = "auto"
| del(.disableAutoMode)
| del(.skipDangerousModePermissionPrompt)
| .skipAutoPermissionPrompt = true' \
"$SETTINGS" > "$SETTINGS.tmp" && mv "$SETTINGS.tmp" "$SETTINGS"
else
# sed fallback flips defaultMode only — it cannot reliably remove the disableAutoMode /
# skipDangerousModePermissionPrompt keys. Install jq for a clean auto-mode switch.
sed -i.bak 's/"defaultMode":[[:space:]]*"bypassPermissions"/"defaultMode": "auto"/' "$SETTINGS" && rm -f "$SETTINGS.bak"
fi
# Windows — settings.json
$settings = "$env:USERPROFILE\.claude\settings.json"
$json = Get-Content $settings -Raw | ConvertFrom-Json
$json.permissions.defaultMode = "auto"
$json.PSObject.Properties.Remove("disableAutoMode")
$json.PSObject.Properties.Remove("skipDangerousModePermissionPrompt")
$json | Add-Member -NotePropertyName skipAutoPermissionPrompt -NotePropertyValue $true -Force
$json | ConvertTo-Json -Depth 10 | Set-Content $settings
After copying: show a brief reminder:
settings.json copied — verify that hook paths are correct for your platform (see local/README.md).
Show this reminder only if settings.json was actually placed or overwritten.
PHASE 1.5: Personal overlay
Apply user-specific customisations from $CONFIG_REPO/personal/ (gitignored, optional).
# macOS/Linux
PERSONAL_DIR="$CONFIG_REPO/personal"
if [ -d "$PERSONAL_DIR" ]; then
OVERLAY_COUNT=0
# 1. CLAUDE.md overlay — append to base
if [ -f "$PERSONAL_DIR/CLAUDE.md.overlay" ]; then
cat "$PERSONAL_DIR/CLAUDE.md.overlay" >> "$HOME/.claude/CLAUDE.md"
OVERLAY_COUNT=$((OVERLAY_COUNT + 1))
fi
# 2. settings.overlay.json — deep-merge (right-wins) via jq
if [ -f "$PERSONAL_DIR/settings.overlay.json" ]; then
if command -v jq >/dev/null 2>&1; then
jq -s '.[0] * .[1]' "$HOME/.claude/settings.json" "$PERSONAL_DIR/settings.overlay.json" \
> "$HOME/.claude/settings.json.tmp" && mv "$HOME/.claude/settings.json.tmp" "$HOME/.claude/settings.json"
OVERLAY_COUNT=$((OVERLAY_COUNT + 1))
else
echo "warn: jq not found — skipping settings overlay merge"
fi
fi
# 3. styles/ — symlink to ~/.claude/styles/
if [ -d "$PERSONAL_DIR/styles" ]; then
ln -sfn "$PERSONAL_DIR/styles" "$HOME/.claude/styles"
OVERLAY_COUNT=$((OVERLAY_COUNT + 1))
fi
# STATUS: applied ($OVERLAY_COUNT items) if OVERLAY_COUNT > 0, else found-nothing
else
# STATUS: not found (optional)
fi
# Windows
$personalDir = "$CONFIG_REPO\personal"
$overlayCount = 0
if (Test-Path $personalDir) {
# 1. CLAUDE.md overlay
$overlay = "$personalDir\CLAUDE.md.overlay"
if (Test-Path $overlay) {
Get-Content $overlay | Add-Content "$env:USERPROFILE\.claude\CLAUDE.md"
$overlayCount++
}
# 2. settings.overlay.json — deep-merge via jq
$settingsOverlay = "$personalDir\settings.overlay.json"
if (Test-Path $settingsOverlay) {
if (Get-Command jq -ErrorAction SilentlyContinue) {
$merged = jq -s '.[0] * .[1]' "$env:USERPROFILE\.claude\settings.json" $settingsOverlay
$merged | Set-Content "$env:USERPROFILE\.claude\settings.json"
$overlayCount++
} else {
Write-Warning "jq not found — skipping settings overlay merge"
}
}
# 3. styles/ — junction to ~/.claude/styles/
$stylesDir = "$personalDir\styles"
$stylesTarget = "$env:USERPROFILE\.claude\styles"
if ((Test-Path $stylesDir) -and (-not (Test-Path $stylesTarget))) {
cmd /c "mklink /J `"$stylesTarget`" `"$stylesDir`""
$overlayCount++
}
# STATUS: applied ($overlayCount items) if $overlayCount > 0, else found-nothing
} else {
# STATUS: not found (optional)
}
PHASE 2: Global symlinks / junctions
Link 4 directories: agents, hooks, skills, scripts. Skip if the link already exists (-e check, no overwrite).
# macOS/Linux
for dir in agents hooks skills scripts; do
target="$HOME/.claude/$dir"
[ ! -e "$target" ] && ln -sfn "$CONFIG_REPO/$dir" "$target"
# STATUS: linked (new) or already-exists
done
# Windows
foreach ($dir in @("agents","hooks","skills","scripts")) {
$target = "$env:USERPROFILE\.claude\$dir"
if (-not (Test-Path $target)) {
cmd /c "mklink /J `"$target`" `"$CONFIG_REPO\$dir`""
# STATUS: linked (new)
} else {
# STATUS: already-exists
}
}
PHASE 2.5: Board background service
Best-effort, silent, non-blocking — sets up the /project-app board's background service
(keeps serve-backlog.js warm so the board is one click, no manual server start; see
project-app/SKILL.md). A failure here (e.g. Node.js not installed yet) must never stop the
rest of bootstrap — this is a nice-to-have, not a core-config requirement.
Todo: Read
.claude/skills/shared/APP-INSTALL-CHECK.mdand follow it.
Runs after PHASE 2 so the ~/.claude/skills/... symlinks/junctions it depends on already exist.
No AskUserQuestion here — installed silently, outcome only surfaces in the PHASE 3 report
(matches this repo owner's explicit preference: no extra prompt for this one).
Store the outcome as BOARD_SERVICE_STATUS: installed-now (from INSTALLED_NOW),
already-installed (from ALREADY_INSTALLED), or skipped: <reason> (from SKIPPED: <reason>) — for the PHASE 3 report row.
PHASE 2.6: Usage-window opener routine (optional, opt-in)
Best-effort, opt-in — asks once, defaults to Skip. Sets up a daily cloud routine (via the
RemoteTrigger harness tool, same mechanism as the /schedule skill) that pings a minimal Haiku
turn three times a day so the account's rolling 5-hour usage window opens at predictable anchors
instead of drifting with whenever the user happens to first prompt. This is per-account, not
per-machine — re-running bootstrap on a second machine must not create a duplicate routine (the
reference below dedups by name before creating).
header: "Window opener"
question: "Set up a daily cloud routine that opens your 5h usage window at fixed times (08:00 / 18:00 / 23:00 Europe/Amsterdam, Haiku model)?"
options:
- label: "Skip (Recommended)"
description: "Don't create a routine. You can set this up later via /schedule or re-run bootstrap."
- label: "Create"
description: "Creates a cloud routine now (uses account quota for 3 minimal Haiku pings/day)."
multiSelect: false
Store the choice in WINDOW_OPENER. If "Skip (Recommended)" → WINDOW_OPENER_STATUS="skipped (declined)", no further action this phase.
If "Create":
Todo: Read
.claude/skills/core-bootstrap/references/usage-window-opener.mdand follow it.
That reference is fully self-contained (tool loading, account-level dedup, environment/repo
resolution, routine creation) and sets WINDOW_OPENER_STATUS to one of: created ·
already-exists (account) · skipped (<reason>). A failure here must never block PHASE 3.
PHASE 3: Report
Show ASCII table with outcome per item:
Bootstrap complete
══════════════════════════════════════════════════════
Item Status
──────────────────────────────────────────────────────
~/.claude/CLAUDE.md placed
~/.claude/settings.json already-exists
~/.claude/keybindings.json already-exists
~/.claude/statusline-… placed
~/.claude/agents/ linked
~/.claude/hooks/ already-exists
~/.claude/skills/ already-exists
~/.claude/scripts/ already-exists
Personal overlay applied (2 items)
Language English
Explanation Level Intermediate
Permission mode Bypass permissions
Claude plan Max 5x
Paths (paths.local.yaml) written
Board background service installed
Window opener routine created
══════════════════════════════════════════════════════
Statuses: placed · already-exists · linked · error: <reason>
For the Board background service row: installed (from BOARD_SERVICE_STATUS=installed-now),
already installed (from already-installed), or skipped (<reason>) (from skipped: <reason>
— e.g. skipped (Node.js not found)). This never blocks the rest of the report or a skipped
overall bootstrap outcome — it's its own independent row.
For the Window opener routine row: show WINDOW_OPENER_STATUS verbatim (created ·
already-exists (account) · skipped (declined) · skipped (<reason>)). If created, also
show the routine link in the closing tip:
Window opener routine created: https://claude.ai/code/routines/{id} Ticks daily at 08:00 / 18:00 / 23:00 Europe/Amsterdam (fixed UTC — shifts an hour earlier in winter). Adjust anytime via /schedule or https://claude.ai/code/routines.
Show this extra tip block only when WINDOW_OPENER_STATUS="created".
For the Language row: show the chosen language, or the current value with (already set) suffix if LANGUAGE_CHOICE=skip. Read the current value via:
CURRENT_LANG=$(grep "^Language:" "$HOME/.claude/CLAUDE.md" | sed 's/^Language:[[:space:]]*//')
For the Explanation Level row: show the chosen level, or the current value with (already set) suffix if EXPLANATION_CHOICE=skip. Read the current value via:
CURRENT_EXPL=$(grep "^Explanation Level:" "$HOME/.claude/CLAUDE.md" | sed 's/^Explanation Level:[[:space:]]*//')
For the Permission mode row: show Bypass permissions or Auto mode per PERM_CHOICE, or the current defaultMode value with (already set) suffix if PERM_CHOICE=skip. Read the current value via:
CURRENT_MODE=$(jq -r '.permissions.defaultMode' "$HOME/.claude/settings.json" 2>/dev/null)
For the Claude plan row: show the PLAN_TIER label (Max 5x, Pro, Max 10x+, or skipped).
For the Paths row: show written / already-exists.
For the Personal overlay row:
personal/does not exist →not found (optional)personal/exists,OVERLAY_COUNT > 0→applied (N items)personal/exists,OVERLAY_COUNT = 0→found, nothing to apply
Closing tip (always show):
Next step: open a project and run
/core-setupfor project-internal setup. To stay current with claude-config updates later: run/core-update.
Plan-tier tip
Based on PLAN_TIER (from PHASE 0), show one of the following blocks. These settings are not auto-applied — they require a runtime /model choice and an explicit edit to ~/.claude/settings.json.
Skills don't depend on a specific model — they use plan mode (shared/PLAN-MODE.md) purely as an approval gate; the session model is opus throughout regardless of plan-mode state. For Max 5x users, /model opus spends Opus quota on the whole session, not just planning — watch usage; drop to /model sonnet if quota runs tight.
max-5x:Tip for Max 5x: • Run /model opus (Opus for the whole session; watch quota since plan mode no longer switches to Sonnet for execution) • Set "effortLevel": "high" in ~/.claude/settings.jsonpro:Tip for Pro — Opus quota is tight: • Run /model sonnet (or leave default) • Set "effortLevel": "medium" in ~/.claude/settings.json Plan mode still works under Sonnet — it's purely an approval gate, not a model-routing device, so there's no separate router to choose.max-10x:Tip for Max 10x+ — quota headroom: • Run /model opus (full Opus for everything) • Set "effortLevel": "high" in ~/.claude/settings.jsonskip: no plan-tier block shown.