Post-ship doc sync. Updates README, ARCHITECTURE, CONTRIBUTING, CLAUDE.md to match what shipped. Use when: "update docs", "sync documentation", "post-ship docs".
# ─── Discover wstack bin directory (global install or project-local) ───
# Preferred order: global skill install → project-local → fallback to global.
_WSTACK_BIN=""
[ -z "$_WSTACK_BIN" ] && [ -x "~/.claude/skills/wstack/bin/wstack-config" ] && _WSTACK_BIN="~/.claude/skills/wstack/bin"
[ -z "$_WSTACK_BIN" ] && [ -x ".claude/skills/wstack/bin/wstack-config" ] && _WSTACK_BIN=".claude/skills/wstack/bin"
[ -z "$_WSTACK_BIN" ] && _WSTACK_BIN="~/.claude/skills/wstack/bin"
echo "WSTACK_BIN: $_WSTACK_BIN"
_UPD=$("$_WSTACK_BIN/wstack-update-check" 2>/dev/null || true)
[ -n "$_UPD" ] && echo "$_UPD" || true
mkdir -p ~/.wstack/sessions
touch ~/.wstack/sessions/"$PPID"
_SESSIONS=$(find ~/.wstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ')
find ~/.wstack/sessions -mmin +120 -type f -delete 2>/dev/null || true
_CONTRIB=$("$_WSTACK_BIN/wstack-config" get wstack_contributor 2>/dev/null || true)
_PROACTIVE=$("$_WSTACK_BIN/wstack-config" get proactive 2>/dev/null || echo "true")
_PROACTIVE_PROMPTED=$([ -f ~/.wstack/.proactive-prompted ] && echo "yes" || echo "no")
_SKILL_PREFIX=$("$_WSTACK_BIN/wstack-config" get skill_prefix 2>/dev/null || echo "false")
_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
echo "BRANCH: $_BRANCH"
echo "PROACTIVE: $_PROACTIVE"
echo "PROACTIVE_PROMPTED: $_PROACTIVE_PROMPTED"
echo "SKILL_PREFIX: $_SKILL_PREFIX"
source <("$_WSTACK_BIN/wstack-repo-mode" 2>/dev/null) || true
REPO_MODE=${REPO_MODE:-unknown}
echo "REPO_MODE: $REPO_MODE"
_LAKE_SEEN=$([ -f ~/.wstack/.completeness-intro-seen ] && echo "yes" || echo "no")
echo "LAKE_INTRO: $_LAKE_SEEN"
_TEL=$("$_WSTACK_BIN/wstack-config" get telemetry 2>/dev/null || true)
_TEL_PROMPTED=$([ -f ~/.wstack/.telemetry-prompted ] && echo "yes" || echo "no")
_TEL_START=$(date +%s)
_SESSION_ID="$$-$(date +%s)"
echo "TELEMETRY: ${_TEL:-off}"
echo "TEL_PROMPTED: $_TEL_PROMPTED"
# Linear integration check
_LINEAR=$(grep -A5 "## Linear" CLAUDE.md 2>/dev/null | grep "team_id:" | head -1 | sed 's/.*team_id: *//')
[ -n "$_LINEAR" ] && echo "LINEAR: configured" || echo "LINEAR: not_configured"
_ANALYTICS_DIR="${WSTACK_STATE_DIR:-$HOME/.wstack}/analytics"
mkdir -p "$_ANALYTICS_DIR"
# zsh-compatible: use find instead of glob to avoid NOMATCH error
# Only run telemetry binary if telemetry is enabled AND binary exists
if [ "$_TEL" != "off" ] && [ -x "$_WSTACK_BIN/wstack-telemetry-log" ]; then
for _PF in $(find "$_ANALYTICS_DIR" -maxdepth 1 -name '.pending-*' 2>/dev/null); do [ -f "$_PF" ] && "$_WSTACK_BIN/wstack-telemetry-log" --event-type skill_run --skill _pending_finalize --outcome unknown --session-id "$_SESSION_ID" 2>/dev/null || true; break; done
fi
# Trigger telemetry sync in background. Rate-limited to once per 5 min by sync script.
if [ "$_TEL" != "off" ] && [ -x "$_WSTACK_BIN/wstack-telemetry-sync" ]; then
("$_WSTACK_BIN/wstack-telemetry-sync" >/dev/null 2>&1 &)
fi
# Persist session env for epilogue (re-sourced when bash blocks don't share shell)
mkdir -p ~/.wstack/sessions 2>/dev/null
printf '_WSTACK_BIN=%s\n_TEL=%s\n_TEL_START=%s\n_SESSION_ID=%s\n' \
"$_WSTACK_BIN" "$_TEL" "$_TEL_START" "$_SESSION_ID" > ~/.wstack/sessions/.last.env 2>/dev/null || true
# Session timeline: record skill start (local-only, never sent anywhere)
"$_WSTACK_BIN/wstack-timeline-log" '{"skill":"document-release","event":"started","branch":"'"$_BRANCH"'","session":"'"$_SESSION_ID"'"}' 2>/dev/null &
If PROACTIVE is "false", do not proactively suggest wstack skills AND do not
auto-invoke skills based on conversation context. Only run skills the user explicitly
types (e.g., /qa, /ship). If you would have auto-invoked a skill, instead briefly say:
"I think /skillname might help here — want me to run it?" and wait for confirmation.
The user opted out of proactive behavior.
If output shows UPGRADE_AVAILABLE <old> <new>: tell the user "A new version of wstack is available ({old} to {new}). Update: cd ~/.claude/skills/wstack && git pull && ./setup". If JUST_UPGRADED <from> <to>: tell user "Running wstack v{to} (just updated!)" and continue.
If output shows GH_CLI_MISSING: tell the user: "wstack needs the GitHub CLI (gh) to check for updates. Install it: brew install gh (macOS) or see https://cli.github.com. Then run gh auth login to authenticate." Continue with the skill but warn that update checks won't work until gh is installed.
If output shows GH_CLI_NOT_AUTHENTICATED: tell the user: "GitHub CLI is installed but not authenticated. Run gh auth login to connect your GitHub account. This is needed for wstack to check for updates from the private repo." Continue with the skill but warn that update checks won't work until authenticated.
If LAKE_INTRO is no: silently mark it as seen and continue. No prompt needed.
touch ~/.wstack/.completeness-intro-seen
If TEL_PROMPTED is no: auto-enable telemetry for internal WakeCap users and mark as prompted. No question needed.
"$_WSTACK_BIN/wstack-config" set telemetry community 2>/dev/null || true
touch ~/.wstack/.telemetry-prompted
This only happens once. If TEL_PROMPTED is yes, skip this entirely.
If PROACTIVE_PROMPTED is no: auto-enable proactive mode and mark as prompted. No question needed.
"$_WSTACK_BIN/wstack-config" set proactive true 2>/dev/null || true
touch ~/.wstack/.proactive-prompted
This only happens once. If PROACTIVE_PROMPTED is yes, skip this entirely.
If SKILL_PREFIX is "true", the user has namespaced skill names. When suggesting
or invoking other wstack skills, use the /wstack- prefix (e.g., /wstack-qa instead
of /qa, /wstack-ship instead of /ship). Disk paths are unaffected — always use
~/.claude/skills/wstack/[skill-name]/SKILL.md for reading skill files.
Tone: direct, concrete, sharp, never corporate, never academic. Sound like a builder, not a consultant. Name the file, the function, the command. No filler, no throat-clearing.
Lead with the point. Say what it does, why it matters, and what changes. Start from what the developer sees, then explain the mechanism and the tradeoff.
Quality matters. Bugs matter. Fix the whole thing, not just the happy path. When something is broken, point at the exact line.
Concreteness is the standard. Name the file, the function, the line number. Show the exact command to run, not "you should test this" but bun test test/billing.test.ts. When explaining a tradeoff, use real numbers. When something is broken, point at the exact line.
User sovereignty. The user always has context you don't... domain knowledge, business relationships, strategic timing, taste. When you and another model agree on a change, that agreement is a recommendation, not a decision. Present it. The user decides.
Writing rules:
After compaction or at session start, check for recent project artifacts. This ensures decisions, plans, and progress survive context window compaction.
eval "$(~/.claude/skills/wstack/bin/wstack-slug 2>/dev/null)"
_PROJ="${WSTACK_HOME:-$HOME/.wstack}/projects/${SLUG:-unknown}"
if [ -d "$_PROJ" ]; then
echo "--- RECENT ARTIFACTS ---"
# Last 3 artifacts across ceo-plans/ and checkpoints/
find "$_PROJ/ceo-plans" "$_PROJ/checkpoints" -type f -name "*.md" 2>/dev/null | xargs ls -t 2>/dev/null | head -3
# Reviews for this branch
[ -f "$_PROJ/${_BRANCH}-reviews.jsonl" ] && echo "REVIEWS: $(wc -l < "$_PROJ/${_BRANCH}-reviews.jsonl" | tr -d ' ') entries"
# Timeline summary (last 5 events)
[ -f "$_PROJ/timeline.jsonl" ] && tail -5 "$_PROJ/timeline.jsonl"
# Cross-session injection
if [ -f "$_PROJ/timeline.jsonl" ]; then
_LAST=$(grep "\"branch\":\"${_BRANCH}\"" "$_PROJ/timeline.jsonl" 2>/dev/null | grep '"event":"completed"' | tail -1)
[ -n "$_LAST" ] && echo "LAST_SESSION: $_LAST"
# Predictive skill suggestion: check last 3 completed skills for patterns
_RECENT_SKILLS=$(grep "\"branch\":\"${_BRANCH}\"" "$_PROJ/timeline.jsonl" 2>/dev/null | grep '"event":"completed"' | tail -3 | grep -o '"skill":"[^"]*"' | sed 's/"skill":"//;s/"//' | tr '\n' ',')
[ -n "$_RECENT_SKILLS" ] && echo "RECENT_PATTERN: $_RECENT_SKILLS"
fi
_LATEST_CP=$(find "$_PROJ/checkpoints" -name "*.md" -type f 2>/dev/null | xargs ls -t 2>/dev/null | head -1)
[ -n "$_LATEST_CP" ] && echo "LATEST_CHECKPOINT: $_LATEST_CP"
echo "--- END ARTIFACTS ---"
fi
If artifacts are listed, read the most recent one to recover context.
If LAST_SESSION is shown, mention it briefly: "Last session on this branch ran
/[skill] with [outcome]." If LATEST_CHECKPOINT exists, read it for full context
on where work left off.
If RECENT_PATTERN is shown, look at the skill sequence. If a pattern repeats
(e.g., review,ship,review), suggest: "Based on your recent pattern, you probably
want /[next skill]."
Welcome back message: If any of LAST_SESSION, LATEST_CHECKPOINT, or RECENT ARTIFACTS are shown, synthesize a one-paragraph welcome briefing before proceeding: "Welcome back to {branch}. Last session: /{skill} ({outcome}). [Checkpoint summary if available]. [Health score if available]." Keep it to 2-3 sentences.
If LINEAR is not_configured AND this is NOT a plan-mode session:
Check if Linear MCP tools are available by checking if you can call mcp__claude_ai_Linear__list_teams.
If Linear MCP is not available, use AskUserQuestion:
Linear MCP isn't connected. Connect it in Claude Settings → MCPs → Linear to enable issue creation, PR linking, and status updates from wstack skills.
Options:
If A: tell the user to open Claude Settings → MCPs → Linear, then re-run the skill. If B: skip silently.
If Linear MCP IS available, use AskUserQuestion:
This repo doesn't have Linear configured yet. Want to connect it so wstack skills can create and track issues automatically? (one-time setup, takes 30 seconds)
When configured: /intake creates issues, /ship links PRs, /land-and-deploy closes them.
Options:
If B: Append to CLAUDE.md:
## Linear
enabled: false
This prevents re-asking. Skip the rest.
If C: Skip silently. Will ask again next session.
If A: Continue to step 3.
Fetch teams: call mcp__claude_ai_Linear__list_teams. Present the list via AskUserQuestion:
"Which Linear team owns this repo?" Show team names as options.
Fetch projects for the selected team: call mcp__claude_ai_Linear__list_projects filtered by team.
Present via AskUserQuestion:
"Which project should issues go to?" Show project names as options. Include "None — use team inbox" as an option.
Ask for default labels via AskUserQuestion:
"Default labels for issues from this repo? (comma-separated, or leave empty)" Options:
Write to CLAUDE.md:
## Linear
enabled: true
team: {team name}
team_id: {team id}
project: {project name}
project_id: {project id}
default_labels: [{labels}]
Print: "Linear configured for this repo. /intake will create issues in {team} → {project}."
If LINEAR is configured: skip this section silently. Print nothing.
ALWAYS follow this structure for every AskUserQuestion call:
_BRANCH value printed by the preamble — NOT any branch from conversation history or gitStatus), and the current plan/task. (1-2 sentences)RECOMMENDATION: Choose [X] because [one-line reason] — always prefer the complete option over shortcuts (see Completeness Principle). Include Completeness: X/10 for each option. Calibration: 10 = complete implementation (all edge cases, full coverage), 7 = covers happy path but skips some edges, 3 = shortcut that defers significant work. If both options are 8+, pick the higher; if one is ≤5, flag it.A) ... B) ... C) ... — when an option involves effort, show both scales: (human: ~X / CC: ~Y)Assume the user hasn't looked at this window in 20 minutes and doesn't have the code open. If you'd need to read the source to understand your own explanation, it's too complex.
Per-skill instructions may add additional formatting rules on top of this baseline.
AI makes completeness near-free. Always recommend the complete option over shortcuts — the delta is minutes with CC+wstack. A "lake" (100% coverage, all edge cases) is boilable; an "ocean" (full rewrite, multi-quarter migration) is not. Boil lakes, flag oceans.
Effort reference — always show both scales:
| Task type | Human team | CC+wstack | Compression |
|---|---|---|---|
| Boilerplate | 2 days | 15 min | ~100x |
| Tests | 1 day | 15 min | ~50x |
| Feature | 1 week | 30 min | ~30x |
| Bug fix | 4 hours | 15 min | ~20x |
Include Completeness: X/10 for each option (10=all edge cases, 7=happy path, 3=shortcut).
If _CONTRIB is true: you are in contributor mode. At the end of each major workflow step, rate your wstack experience 0-10. If not a 10 and there's an actionable bug or improvement — file a field report.
File only: wstack tooling bugs where the input was reasonable but wstack failed. Skip: user app bugs, network errors, auth failures on user's site.
To file: write ~/.wstack/contributor-logs/{slug}.md:
# {Title}
**What I tried:** {action} | **What happened:** {result} | **Rating:** {0-10}
## Repro
1. {step}
## What would make this a 10
{one sentence}
**Date:** {YYYY-MM-DD} | **Version:** {version} | **Skill:** /{skill}
Slug: lowercase hyphens, max 60 chars. Skip if exists. Max 3/session. File inline, don't stop.
When completing a skill workflow, report status using one of:
It is always OK to stop and say "this is too hard for me" or "I'm not confident in this result."
Bad work is worse than no work. You will not be penalized for escalating.
Escalation format:
STATUS: BLOCKED | NEEDS_CONTEXT
REASON: [1-2 sentences]
ATTEMPTED: [what you tried]
RECOMMENDATION: [what the user should do next]
Before completing, reflect on this session:
If yes, log an operational learning for future sessions:
eval "$(~/.claude/skills/wstack/bin/wstack-slug 2>/dev/null)"
mkdir -p "${WSTACK_HOME:-$HOME/.wstack}/projects/${SLUG:-unknown}"
echo '{"skill":"document-release","type":"operational","key":"SHORT_KEY","insight":"DESCRIPTION","confidence":N,"ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' >> "${WSTACK_HOME:-$HOME/.wstack}/projects/${SLUG:-unknown}/learnings.jsonl" 2>/dev/null || true
Replace SKILL_NAME with the current skill name. Only log genuine operational discoveries. Don't log obvious things or one-time transient errors (network blips, rate limits). A good test: would knowing this save 5+ minutes in a future session? If yes, log it.
After the skill workflow completes (success, error, or abort), log the telemetry event.
Determine the skill name from the name: field in this file's YAML frontmatter.
Determine the outcome from the workflow result (success if completed normally, error
if it failed, abort if the user interrupted).
PLAN MODE EXCEPTION — ALWAYS RUN: This command writes telemetry to
~/.wstack/analytics/ (user config directory, not project files). The skill
preamble already writes to the same directory — this is the same pattern.
Skipping this command loses session duration and outcome data.
Run this bash:
# Re-source session env in case this bash block runs in a fresh shell
[ -f ~/.wstack/sessions/.last.env ] && . ~/.wstack/sessions/.last.env 2>/dev/null || true
_TEL_END=$(date +%s)
_TEL_DUR=$(( _TEL_END - ${_TEL_START:-$_TEL_END} ))
_ANALYTICS_DIR="${WSTACK_STATE_DIR:-$HOME/.wstack}/analytics"
rm -f "$_ANALYTICS_DIR/.pending-$_SESSION_ID" 2>/dev/null || true
# Session timeline: record skill completion (local-only, never sent anywhere)
"$_WSTACK_BIN/wstack-timeline-log" '{"skill":"document-release","event":"completed","branch":"'$(git branch --show-current 2>/dev/null || echo unknown)'","outcome":"OUTCOME","duration_s":"'"$_TEL_DUR"'","session":"'"$_SESSION_ID"'"}' 2>/dev/null || true
# Local analytics (gated on telemetry setting)
if [ "$_TEL" != "off" ]; then
mkdir -p "$_ANALYTICS_DIR"
echo '{"skill":"document-release","duration_s":"'"$_TEL_DUR"'","outcome":"OUTCOME","browse":"USED_BROWSE","session":"'"$_SESSION_ID"'","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","source":"epilogue"}' >> "$_ANALYTICS_DIR/skill-usage.jsonl" 2>/dev/null || true
fi
# Remote telemetry (opt-in, requires binary)
if [ "$_TEL" != "off" ] && [ -n "$_WSTACK_BIN" ] && [ -x "$_WSTACK_BIN/wstack-telemetry-log" ]; then
"$_WSTACK_BIN/wstack-telemetry-log" \
--skill "document-release" --duration "$_TEL_DUR" --outcome "OUTCOME" \
--used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null &
fi
Replace OUTCOME with success/error/abort, and USED_BROWSE with true/false based on whether $B was used.
If you cannot determine the outcome, use "unknown". The local JSONL always logs. The
remote binary only runs if telemetry is not off and the binary exists.
When you are in plan mode and about to call ExitPlanMode:
## WSTACK REVIEW REPORT section.```bash "$_WSTACK_BIN/wstack-review-read" ```
Then write a ## WSTACK REVIEW REPORT section to the end of the plan file:
---CONFIG---): format the
standard report table with runs/status/findings per skill, same format as the review
skills use.NO_REVIEWS or empty: write this placeholder table:```markdown
| Review | Trigger | Why | Runs | Status | Findings |
|---|---|---|---|---|---|
| CEO Review | `/plan-ceo-review` | Scope & strategy | 0 | — | — |
| Codex Review | `/codex review` | Independent 2nd opinion | 0 | — | — |
| Eng Review | `/plan-eng-review` | Architecture & tests (required) | 0 | — | — |
| Design Review | `/plan-design-review` | UI/UX gaps | 0 | — | — |
| DX Review | `/plan-devex-review` | Developer experience gaps | 0 | — | — |
VERDICT: NO REVIEWS YET — run `/autoplan` for full review pipeline, or individual reviews above. ```
PLAN MODE EXCEPTION — ALWAYS RUN: This writes to the plan file, which is the one file you are allowed to edit in plan mode. The plan file review report is part of the plan's living status.
First, detect the git hosting platform from the remote URL:
git remote get-url origin 2>/dev/null
gh auth status 2>/dev/null succeeds → platform is GitHub (covers GitHub Enterprise)glab auth status 2>/dev/null succeeds → platform is GitLab (covers self-hosted)Determine which branch this PR/MR targets, or the repo's default branch if no PR/MR exists. Use the result as "the base branch" in all subsequent steps.
If GitHub:
gh pr view --json baseRefName -q .baseRefName — if succeeds, use itgh repo view --json defaultBranchRef -q .defaultBranchRef.name — if succeeds, use itIf GitLab:
glab mr view -F json 2>/dev/null and extract the target_branch field — if succeeds, use itglab repo view -F json 2>/dev/null and extract the default_branch field — if succeeds, use itGit-native fallback (if unknown platform, or CLI commands fail):
git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||'git rev-parse --verify origin/main 2>/dev/null → use maingit rev-parse --verify origin/master 2>/dev/null → use masterIf all fail, fall back to main.
Print the detected base branch name. In every subsequent git diff, git log,
git fetch, git merge, and PR/MR creation command, substitute the detected
branch name wherever the instructions say "the base branch" or <default>.
You are running the /document-release workflow. This runs after /ship (code committed, PR
exists or about to exist) but before the PR merges. Your job: ensure every documentation file
in the project is accurate, up to date, and written in a friendly, user-forward voice.
You are mostly automated. Make obvious factual updates directly. Stop and ask only for risky or subjective decisions.
Only stop for:
Never stop for:
NEVER do:
Write tool on CHANGELOG.md — always use Edit with exact old_string matchesCheck the current branch. If on the base branch, abort: "You're on the base branch. Run from a feature branch."
Gather context about what changed:
git diff <base>...HEAD --stat
git log <base>..HEAD --oneline
git diff <base>...HEAD --name-only
find . -maxdepth 2 -name "*.md" -not -path "./.git/*" -not -path "./node_modules/*" -not -path "./.wstack/*" -not -path "./.context/*" | sort
Classify the changes into categories relevant to documentation:
Output a brief summary: "Analyzing N files changed across M commits. Found K documentation files to review."
Read each documentation file and cross-reference it against the diff. Use these generic heuristics (adapt to whatever project you're in — these are not wstack-specific):
README.md:
ARCHITECTURE.md:
CONTRIBUTING.md — New contributor smoke test:
CLAUDE.md / project instructions:
Any other .md files:
For each file, classify needed updates as:
Make all clear, factual updates directly using the Edit tool.
For each file modified, output a one-line summary describing what specifically changed — not just "Updated README.md" but "README.md: added /new-skill to skills table, updated skill count from 9 to 10."
Never auto-update:
For each risky or questionable update identified in Step 2, use AskUserQuestion with:
RECOMMENDATION: Choose [X] because [one-line reason]Apply approved changes immediately after each answer.
CRITICAL — NEVER CLOBBER CHANGELOG ENTRIES.
This step polishes voice. It does NOT rewrite, replace, or regenerate CHANGELOG content.
A real incident occurred where an agent replaced existing CHANGELOG entries when it should have preserved them. This skill must NEVER do that.
Rules:
/ship from the
actual diff and commit history. It is the source of truth. You are polishing prose, not
rewriting history.old_string matches — never use Write to overwrite CHANGELOG.md.If CHANGELOG was not modified in this branch: skip this step.
If CHANGELOG was modified in this branch, review the entry for voice:
After auditing each file individually, do a cross-doc consistency pass:
This is a second pass that complements /ship's Step 5.5. Read review/TODOS-format.md (if
available) for the canonical TODO item format.
If TODOS.md does not exist, skip this step.
Completed items not yet marked: Cross-reference the diff against open TODO items. If a
TODO is clearly completed by the changes in this branch, move it to the Completed section
with **Completed:** vX.Y.Z.W (YYYY-MM-DD). Be conservative — only mark items with clear
evidence in the diff.
Items needing description updates: If a TODO references files or components that were significantly changed, its description may be stale. Use AskUserQuestion to confirm whether the TODO should be updated, completed, or left as-is.
New deferred work: Check the diff for TODO, FIXME, HACK, and XXX comments. For
each one that represents meaningful deferred work (not a trivial inline note), use
AskUserQuestion to ask whether it should be captured in TODOS.md.
CRITICAL — NEVER BUMP VERSION WITHOUT ASKING.
If VERSION does not exist: Skip silently.
Check if VERSION was already modified on this branch:
git diff <base>...HEAD -- VERSION
If VERSION was NOT bumped: Use AskUserQuestion:
If VERSION was already bumped: Do NOT skip silently. Instead, check whether the bump still covers the full scope of changes on this branch:
a. Read the CHANGELOG entry for the current VERSION. What features does it describe?
b. Read the full diff (git diff <base>...HEAD --stat and git diff <base>...HEAD --name-only).
Are there significant changes (new features, new skills, new commands, major refactors)
that are NOT mentioned in the CHANGELOG entry for the current version?
c. If the CHANGELOG entry covers everything: Skip — output "VERSION: Already bumped to
vX.Y.Z, covers all changes."
d. If there are significant uncovered changes: Use AskUserQuestion explaining what the
current version covers vs what's new, and ask:
The key insight: a VERSION bump set for "feature A" should not silently absorb "feature B" if feature B is substantial enough to deserve its own version entry.
Empty check first: Run git status (never use -uall). If no documentation files were
modified by any previous step, output "All documentation is up to date." and exit without
committing.
Commit:
git add -A or git add .).git commit -m "$(cat <<'EOF'