소스 검색

opus version correction

bastien 1 개월 전
부모
커밋
f8811fab37
24개의 변경된 파일997개의 추가작업 그리고 1060개의 파일을 삭제
  1. 19 0
      .gitignore
  2. 31 0
      CHANGELOG.md
  3. 5 0
      CLAUDE.md
  4. 16 0
      Makefile
  5. 292 355
      README.md
  6. 0 473
      agents/git-workflow.md
  7. 1 0
      agents/plugin-advisor.md
  8. 261 0
      doctor.sh
  9. 65 29
      hooks/session-start.sh
  10. 53 57
      install-plugins.sh
  11. 64 0
      lib/detect-plugins.sh
  12. 18 6
      link.sh
  13. 24 0
      plugins.lock.json
  14. 35 5
      settings.json
  15. 3 1
      skills/analyze/SKILL.md
  16. 0 15
      skills/git-pr/SKILL.md
  17. 18 0
      skills/health/SKILL.md
  18. 4 40
      skills/init-project/SKILL.md
  19. 1 1
      skills/plugin-check/SKILL.md
  20. 1 1
      skills/readme/SKILL.md
  21. 3 1
      skills/refactor/SKILL.md
  22. 4 76
      skills/ship-feature/SKILL.md
  23. 78 0
      update-all.sh
  24. 1 0
      version.txt

+ 19 - 0
.gitignore

@@ -0,0 +1,19 @@
+# ── claude-config repo ignores ──
+
+# Symlink created by link.sh (GStack submodule target)
+skills/gstack
+
+# Install logs
+install-*.log
+
+# OS
+.DS_Store
+Thumbs.db
+desktop.ini
+
+# Editors
+*.swp
+*.swo
+*~
+.idea/
+.vscode/

+ 31 - 0
CHANGELOG.md

@@ -0,0 +1,31 @@
+# Changelog
+
+All notable changes to claude-config will be documented in this file.
+
+Format follows [Keep a Changelog](https://keepachangelog.com/).
+
+## [Unreleased]
+
+## [1.0.0] — 2025-04-03
+
+### Added
+- 6 custom agents: analyzer, interviewer, plugin-advisor, readme-updater, refactorer, scaffolder
+- 6 custom skills: analyze, init-project, plugin-check, readme, refactor, ship-feature
+- 2 orchestrators with validation gates: init-project (13 steps), ship-feature (8 steps)
+- Multi-OS install script (apt/dnf/pacman/brew)
+- GStack as git submodule at skills-external/gstack
+- Session start hook with plugin toggle status and health check
+- Global settings.json with deny/ask/allow permission tiers
+- Per-project templates: settings.json, settings.local.json, .claudeignore, project-CLAUDE.md
+- Settings reference (SETTINGS.md)
+- doctor.sh — full setup diagnostic
+- update-all.sh — one-command update for all components
+- plugins.lock.json — version pinning for non-marketplace dependencies
+- /health skill — run doctor.sh from within Claude Code
+- Makefile — unified entry point for install/link/doctor/update
+
+### Security
+- deny rules cover: destructive commands, secrets access, privilege escalation,
+  code injection (eval, bash -c, xargs), pipe-to-shell, and secrets via bash (cat .env)
+- disableBypassPermissionsMode enforced globally
+- .claudeignore template with comprehensive exclusions

+ 5 - 0
CLAUDE.md

@@ -135,6 +135,9 @@ When working on code:
 
 ## STRICT MODE
 
+These rules are always active in orchestrator skills (/init-project,
+/ship-feature) and during code review. They apply automatically.
+
 These rules override all other instructions.
 
 - Never skip workflow steps
@@ -145,6 +148,8 @@ These rules override all other instructions.
 
 ## FAIL FAST MODE
 
+These rules are always active in every interaction. They apply automatically.
+
 These rules override all other instructions.
 
 - Stop immediately if requirements are unclear

+ 16 - 0
Makefile

@@ -0,0 +1,16 @@
+.PHONY: help install link doctor update
+
+help: ## Show available commands
+	@grep -E '^[a-zA-Z_-]+:.*##' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*## "}; {printf "  make %-12s %s\n", $$1, $$2}'
+
+install: link ## Full install: symlinks + prerequisites + plugins
+	bash install-plugins.sh
+
+link: ## Create symlinks into ~/.claude/
+	bash link.sh
+
+doctor: ## Run setup diagnostic
+	bash doctor.sh
+
+update: ## Update config, submodules, plugins, and verify
+	bash update-all.sh

+ 292 - 355
README.md

@@ -10,77 +10,88 @@ This repo is your personal Claude Code setup, versioned and reproducible across
 
 ```
 claude-config/
-├── CLAUDE.md                  # Global coding preferences (style, rules, workflow)
-├── settings.json              # Global permissions + SessionStart hook
-├── install-plugins.sh         # One-shot installer: prerequisites + all plugins
-├── link.sh                    # Symlinks this repo into ~/.claude/
-├── .gitmodules                # Submodule declaration (GStack)
+├── CLAUDE.md              # Global coding preferences (style, rules, workflow)
+├── settings.json          # Global permissions (77 deny / 16 ask / 57 allow rules)
+├── install-plugins.sh     # One-shot installer: prerequisites + all plugins (reads plugins.lock.json)
+├── link.sh                # Symlinks this repo into ~/.claude/
+├── doctor.sh              # Setup diagnostic — checks symlinks, plugins, permissions, token budget
+├── update-all.sh          # One-command update for all components
+├── Makefile               # Unified entry point: make install / doctor / update
+├── plugins.lock.json      # Version pinning for non-marketplace dependencies (RTK, GSD)
+├── version.txt            # Semver version of this config
+├── CHANGELOG.md           # Release history
+├── lib/
+│   └── detect-plugins.sh  # Shared plugin detection — sourced by all scripts
 ├── hooks/
-│   └── session-start.sh       # Shows toggle plugin status at every session start
+│   └── session-start.sh   # Health check + toggle plugin status at session start
 ├── skills-external/
-│   └── gstack/                # Git submodule — garrytan/gstack
-│                                (symlinked → ~/.claude/skills/gstack)
+│   └── gstack/            # Git submodule — garrytan/gstack (symlinked to ~/.claude/skills/gstack)
+├── .gitmodules            # Submodule declaration
 ├── agents/
-│   ├── analyzer.md            # Factual codebase analysis (read-only)
-│   ├── git-workflow.md        # Branch setup, commits, PR creation, conflict resolution
-│   ├── interviewer.md         # Project questionnaire → PROJECT BRIEF
-│   ├── plugin-advisor.md      # Detect plugin mismatches, recommend actions
-│   ├── readme-updater.md      # CREATE / SYNC / AUDIT README (3 modes)
-│   ├── refactorer.md          # Surgical refactoring with norm enforcement
-│   └── scaffolder.md          # Project skeleton (CLAUDE.md, settings, structure)
+│   ├── analyzer.md        # Factual codebase analysis (read-only)
+│   ├── interviewer.md     # Project questionnaire → PROJECT BRIEF
+│   ├── plugin-advisor.md  # Plugin check: detect mismatches, block if Superpowers missing
+│   ├── readme-updater.md  # Update README from git history + codebase
+│   ├── refactorer.md      # Surgical refactoring with norm enforcement
+│   └── scaffolder.md      # Full project generation (CLAUDE.md, README, code)
 ├── skills/
-│   ├── analyze/               # /analyze        — deep factual analysis
-│   ├── git-pr/                # /git-pr          — commit, push, open draft PR/MR
-│   ├── init-project/          # /init-project    — full project initialization
-│   ├── plugin-check/          # /plugin-check    — check plugin config vs project needs
-│   ├── readme/                # /readme          — full README audit + update
-│   ├── refactor/              # /refactor        — improve code without changing behavior
-│   └── ship-feature/          # /ship-feature    — ship a feature end-to-end
+│   ├── analyze/           # /analyze — deep factual analysis
+│   ├── health/            # /health — run setup diagnostic
+│   ├── init-project/      # /init-project — full project initialization
+│   ├── plugin-check/      # /plugin-check — check plugin config vs project needs
+│   ├── readme/            # /readme — update README from current state
+│   ├── refactor/          # /refactor — improve code without changing behavior
+│   └── ship-feature/      # /ship-feature — ship a feature end-to-end
 └── templates/
-    ├── project-CLAUDE.md      # Template for per-project CLAUDE.md
+    ├── project-CLAUDE.md  # Template for per-project CLAUDE.md
     └── settings/
-        ├── home-settings.json # Template for ~/.claude/settings.json
-        ├── settings.json      # Template for project .claude/settings.json
-        ├── settings.local.json# Template for personal .claude/settings.local.json
-        ├── .claudeignore      # Template for project .claudeignore
-        └── SETTINGS.md        # Full settings reference
+        ├── settings.json         # Template for project .claude/settings.json
+        ├── settings.local.json   # Template for personal .claude/settings.local.json
+        ├── .claudeignore         # Template for project .claudeignore
+        └── SETTINGS.md           # Full settings reference
 ```
 
-**Architecture:**
+**Architecture principle:**
 - `skills/` = entry points you invoke via `/skill-name`
-- `agents/` = execution units called by skills (never invoked directly)
-- Custom skills use **Superpowers** agents for implementation phases
-- **Plugins** (Superpowers, GStack, GSD, etc.) install separately via `install-plugins.sh`
+- `agents/` = execution units called by skills (never invoked directly by user)
+- `lib/` = shared shell functions sourced by scripts (plugin detection)
+- Custom skills use **Superpowers** agents for implementation phases (required — auto-detected)
+- **Plugins** (Superpowers, GStack, GSD, etc.) install separately and complement custom skills
 
 ---
 
 ## Fresh install (new machine)
 
 ```bash
-# 1. Clone with submodules (GStack is a git submodule)
-git clone --recurse-submodules git@github.com:youruser/claude-config.git ~/claude-config
+# 1. Clone with submodules — choose any location
+git clone --recurse-submodules git@github.com:youruser/claude-config.git
+cd claude-config
 
 # 2. Symlink into ~/.claude/
-cd ~/claude-config && bash link.sh
+bash link.sh
 
-# 3. Install prerequisites + all plugins
-#    Handles: git, Node.js 22, Rust/Cargo, Python 3, gh CLI, glab CLI,
-#             RTK, GStack (submodule), GSD, all marketplace plugins
-bash ~/claude-config/install-plugins.sh
+# 3. Install prerequisites + all plugins (detects OS, reads pinned versions from plugins.lock.json)
+bash install-plugins.sh
 
-# 4. Authenticate git provider CLIs (for /git-pr)
-gh auth login        # GitHub
-glab auth login      # GitLab
-# Gogs/Gitea: see "Git setup" section below
-
-# 5. Add Context7 API key (free at context7.com)
+# 4. Add Context7 API key (free at context7.com) — manual step
 claude mcp add --scope user context7 -- npx -y @upstash/context7-mcp --api-key YOUR_KEY
 
-# 6. Restart Claude Code → /reload-plugins
+# 5. Verify setup
+bash doctor.sh
+
+# 6. Restart Claude Code then run /reload-plugins
 ```
 
-All `claude plugin install` calls use `--scope user` — always installs
-to `~/.claude/plugins/` regardless of working directory.
+All scripts use their own location to find the repo — run them from anywhere or from the repo directory.
+Symlinks point to the repo's actual path, so renaming or moving the repo requires re-running `bash link.sh`.
+
+The install script handles: git, Node.js 22, Rust/Cargo, Python 3, RTK, GStack (submodule), GSD,
+and all marketplace plugins on Linux (apt/dnf/pacman) and macOS (brew).
+
+RTK and GSD versions are pinned in `plugins.lock.json`. The install script reads those
+versions automatically. Marketplace plugins install to `~/.claude/plugins/` (user scope).
+
+Install output is logged to `install-YYYYMMDD-HHMMSS.log` in the repo directory for post-mortem debugging.
 
 ---
 
@@ -94,12 +105,15 @@ to `~/.claude/plugins/` regardless of working directory.
 | `/refactor` | Improve code quality without changing behavior (strict norms) |
 | `/readme` | Full README audit — diff vs codebase, mandatory stop, surgical updates |
 | `/plugin-check` | Check active plugins vs project needs — recommend enable/disable |
-| `/git-pr` | Commit all changes, push, open draft PR/MR (GitHub/GitLab/Gogs/Gitea) |
 | `/init-project` | Initialize a complete project from scratch (full orchestrator) |
 | `/ship-feature` | Ship a feature end-to-end with validation gates (full orchestrator) |
+| `/health` | Run setup diagnostic — check symlinks, plugins, permissions, token budget |
 
 ### Superpowers skills (auto-invoked or explicit)
 
+> **Required dependency.** Superpowers must be active for `/init-project` and `/ship-feature`.
+> The plugin-advisor (STEP 0) blocks and shows install instructions if Superpowers is missing.
+
 | Command | When it auto-activates |
 |---|---|
 | `/superpowers:brainstorm` | When you describe something to build |
@@ -109,11 +123,10 @@ to `~/.claude/plugins/` regardless of working directory.
 | `test-driven-development` | Auto — when implementing |
 | `requesting-code-review` | Auto — after a feature step |
 
-### GStack skills (full-product projects only)
+### GStack skills (Garry Tan — full-product projects only)
 
-> Submodule at `skills-external/gstack/`, symlinked to `~/.claude/skills/gstack/`.
-> **Use when:** project has UI + design + deploy + browser QA.
-> Skip for backend-only, libs, CLI, scripts.
+> Installed as a git submodule at `skills-external/gstack/`, symlinked to `~/.claude/skills/gstack/`.
+> **Use when:** project has UI + design + deploy + browser QA. Skip for backend/lib/CLI projects.
 
 | Command | Description |
 |---|---|
@@ -130,12 +143,12 @@ to `~/.claude/plugins/` regardless of working directory.
 | `/careful` | Activate safety guardrails |
 | `/freeze` | Lock edits to current directory |
 | `/retro` | Engineering retrospective |
-| `/gstack-upgrade` | Self-update GStack to latest |
+| `/gstack-upgrade` | Self-update GStack |
 
-### GSD skills (multi-session large features)
+### GSD skills (glittercowboy — multi-session large features)
 
-> Installed globally via `npx get-shit-done-cc --claude --global` (done by install-plugins.sh).
-> **Use when:** feature spans multiple days/sessions.
+> Install: `npx get-shit-done-cc --claude --global`
+> **Use when:** feature spans multiple days/sessions. Each session starts fresh with full context from previous phases.
 
 | Command | Description |
 |---|---|
@@ -159,320 +172,135 @@ to `~/.claude/plugins/` regardless of working directory.
 ### `/init-project`
 
 Same rigor as `/ship-feature`. Two validation gates. Full TDD subagent pipeline for v1 features.
-Scaffolder creates only the skeleton. readme-updater handles README in two passes (CREATE + SYNC).
-Always works on a feature branch — never on main/master.
+The Scaffolder only creates the skeleton (no features, no README).
+readme-updater handles the README in two passes: CREATE then SYNC.
+
+STEP 0 blocks if Superpowers is not installed (required for steps 3, 6, 8, 10, 11).
 
 ```
 /init-project <project idea>
-    ├── STEP 0a: BRANCH SETUP (git-workflow)          ← create feature branch from main
-    │                                                    or sync existing branch
-    ├── STEP 0b: PLUGIN CHECK (plugin-advisor)        ← blocks if wrong plugins
+    ├── STEP 0:  PLUGIN CHECK (plugin-advisor)        ← blocks if Superpowers missing or wrong plugins
     ├── STEP 1:  INTERVIEWER (custom)                 → PROJECT BRIEF
     ├── STEP 2:  ANALYZER (custom)                    → ANALYSIS REPORT
     ├── STEP 3:  superpowers:brainstorming             → VALIDATED DESIGN
     ├── STEP 4:  VALIDATION GATE #1                   → approve architecture
-    ├── STEP 5:  SCAFFOLDER (custom)                  → skeleton (CLAUDE.md + settings +
-    │                                                    structure + empty entry points,
-    │                                                    NO features, NO README)
-    ├── STEP 5b: README-UPDATER create mode           → CREATE README from CLAUDE.md
+    ├── STEP 5:  SCAFFOLDER (custom)                  → skeleton only (CLAUDE.md +
+    │                                                    settings + structure +
+    │                                                    empty entry points, NO features,
+    │                                                    NO README)
+    ├── STEP 5b: README-UPDATER create mode (custom)  → CREATE README from CLAUDE.md
     ├── STEP 6:  superpowers:writing-plans             → decompose v1 features into tasks
     ├── STEP 7:  VALIDATION GATE #2                   → approve task plan
-    ├── STEP 8:  superpowers:subagent-driven (TDD)    → implement each feature
+    ├── STEP 8:  superpowers:subagent-driven (TDD)    → implement each feature (isolated)
     ├── STEP 9:  ANALYZER (custom)                    → regression + deviation check
     ├── STEP 10: superpowers:requesting-review         → full code review
     ├── STEP 11: superpowers:finishing-branch          → cleanup + build + tests
-    └── STEP 12: README-UPDATER sync mode             → sync README with implementation
+    └── STEP 12: README-UPDATER sync mode (custom)    → sync README with implementation
 ```
 
 ### `/ship-feature`
 
-```
-/ship-feature <feature description>
-    │
-    ├── STEP 0a: BRANCH SETUP (git-workflow)          ← create/sync feature branch
-    ├── STEP 0b: PLUGIN CHECK (plugin-advisor)        ← blocks if wrong plugins
-    ├── STEP 1:  superpowers:brainstorming             → VALIDATED DESIGN
-    ├── STEP 2:  superpowers:writing-plans             → task plan
-    ├── STEP 3:  VALIDATION GATE                      → user approval required
-    ├── STEP 4:  superpowers:subagent-driven (TDD)    → implementation
-    ├── STEP 5:  ANALYZER (custom)                    → regression / deviation check
-    ├── STEP 6:  superpowers:requesting-review         → code review
-    ├── STEP 7:  superpowers:finishing-branch          → cleanup
-    ├── STEP 8:  README-UPDATER sync mode             → update README
-    └── STEP 9:  CREATE PR (optional gate)            → /git-pr if user approves
-```
-
-### `/git-pr`
-
-Works on any provider. Retroactive — `git diff <base>...HEAD` sees ALL changes since
-branch creation, regardless of session count. Creates a **draft PR** — you control the merge.
+STEP 0 blocks if Superpowers is not installed (required for steps 1, 2, 4, 6, 7).
 
 ```
-/git-pr [optional title]
+/ship-feature <feature description>
-    ├── PHASE 0: Detect provider (GitHub/GitLab/Gogs/Gitea)
-    │           Check CLI: gh / glab / API fallback
-    ├── PHASE 1: Analyze branch (retroactive)
-    │           git diff <base>...HEAD — ALL changes since branch start
-    │           Categorize: config / model / core / api / ui / test / docs / infra
-    ├── PHASE 2: Propose commit plan (conventional commits)
-    │           [VALIDATION GATE] — user approves before any commit
-    ├── PHASE 3: Execute commits (staged per logical group)
-    ├── PHASE 4: Push (with conflict-safe rebase if rejected)
-    └── PHASE 5: Create draft PR/MR
-                GitHub → gh pr create --draft  (or API)
-                GitLab → glab mr create --draft (or API)
-                Gogs   → POST /api/v1/repos/{owner}/{repo}/pulls
-                Gitea  → same API format as Gogs
+    ├── STEP 0: PLUGIN CHECK (plugin-advisor) ← blocks if Superpowers missing or wrong plugins
+    ├── STEP 1: superpowers:brainstorming     → VALIDATED DESIGN
+    ├── STEP 2: superpowers:writing-plans     → task plan
+    ├── STEP 3: VALIDATION GATE               → user approval required
+    ├── STEP 4: superpowers:subagent-driven   → implementation (TDD)
+    ├── STEP 5: ANALYZER (custom)             → regression / deviation check
+    ├── STEP 6: superpowers:requesting-review → code review
+    ├── STEP 7: superpowers:finishing-branch  → cleanup
+    └── STEP 8: README-UPDATER sync mode      → sync README with new feature
 ```
 
-**Branch → base mapping:**
-| Branch prefix | Default base | Commit type |
-|---|---|---|
-| `feature/*`, `feat/*` | `develop` or `main` | `feat:` |
-| `bugfix/*`, `fix/*` | `develop` | `fix:` |
-| `hotfix/*` | `main` | `fix:` |
-| `release/*` | `main` | `chore(release):` |
-
 ### `/plugin-check`
 
-Standalone — run before any significant work. Also auto-runs as STEP 0b
-in `/init-project` and `/ship-feature`.
+Standalone command you can run at any time to audit your plugin config
+against what you're about to do. Also embedded as STEP 0 in both orchestrators.
+
+Blocks if Superpowers is not active (required by orchestrators).
+Blocks if critical project-specific plugins are missing (frontend tools, Context7, GStack).
 
 ```
-/plugin-check "React + FastAPI SaaS with auth"
+/plugin-check "I want to build a React + FastAPI SaaS"
+
 → Detects active plugins
 → Analyzes signals: frontend? design? QA? multi-session? fast-evolving libs?
 → Produces recommendation table
-→ Blocks if critical plugins missing, or confirms "proceed"
-```
-
----
-
-## Git setup for `/git-pr`
-
-`/git-pr` auto-detects your provider from the remote URL and uses the best available
-authentication method. Here is how to set up each provider.
-
----
-
-### GitHub
-
-**Option A — gh CLI (recommended)**
-
-```bash
-# Install (done by install-plugins.sh)
-brew install gh          # macOS
-sudo apt install gh      # Linux
-
-# Authenticate (interactive — opens browser)
-gh auth login
-# Choose: GitHub.com → HTTPS → authenticate with browser
-
-# Verify
-gh auth status
-```
-
-**Option B — Personal Access Token (for CI or headless)**
-
-1. Go to **github.com → Settings → Developer settings → Personal access tokens → Tokens (classic)**
-2. Click **Generate new token**
-3. Required scopes: `repo` (full), `read:org` (if org repo)
-4. Copy the token
-
-```bash
-# Set in environment
-export GITHUB_TOKEN="ghp_xxxxxxxxxxxx"
-echo 'export GITHUB_TOKEN="ghp_xxxxxxxxxxxx"' >> ~/.zshrc  # persist
-
-# Claude Code reads GITHUB_TOKEN automatically for gh CLI fallback
-```
-
----
-
-### GitLab
-
-**Option A — glab CLI (recommended)**
-
-```bash
-# Install (done by install-plugins.sh)
-brew install glab        # macOS
-
-# Authenticate
-glab auth login
-# Choose: gitlab.com → Token or browser
-
-# For self-hosted GitLab
-glab auth login --hostname gitlab.yourcompany.com
-
-# Verify
-glab auth status
-```
-
-**Option B — Personal Access Token**
-
-1. Go to **gitlab.com → User Settings → Access Tokens** (or your instance)
-2. Click **Add new token**
-3. Required scopes: `api`, `read_repository`, `write_repository`
-4. Copy the token
-
-```bash
-export GITLAB_TOKEN="glpat-xxxxxxxxxxxx"
-echo 'export GITLAB_TOKEN="glpat-xxxxxxxxxxxx"' >> ~/.zshrc
-
-# For self-hosted
-export GITLAB_HOST="https://gitlab.yourcompany.com"
-```
-
----
-
-### Gogs
-
-Gogs has no official CLI. `/git-pr` uses the REST API directly.
-
-**Create an API token:**
-
-1. Log in to your Gogs instance
-2. Go to **User Settings (top-right avatar) → Applications**
-3. Under **Token Name**, enter `claude-code`
-4. Click **Generate Token**
-5. Copy the token (shown only once)
-
-```bash
-# Set in environment
-export GOGS_TOKEN="your-token-here"
-echo 'export GOGS_TOKEN="your-token-here"' >> ~/.zshrc
-
-# Verify the API works
-curl -H "Authorization: token $GOGS_TOKEN" \
-  https://your-gogs-server/api/v1/user
-# Should return your user JSON
-```
-
-**Required API permissions:** read/write on repos (tokens in Gogs have full API access by default).
-
----
-
-### Gitea
-
-Same API format as Gogs. Gitea is a Gogs fork.
-
-**Create an API token:**
-
-1. Log in to your Gitea instance
-2. Go to **User Settings → Applications → Manage Access Tokens**
-3. Enter token name `claude-code`
-4. Select permissions: `Issues: Read/Write`, `Repository: Read/Write`
-5. Click **Generate Token** and copy it
-
-```bash
-export GITEA_TOKEN="your-token-here"
-echo 'export GITEA_TOKEN="your-token-here"' >> ~/.zshrc
-
-# Verify
-curl -H "Authorization: token $GITEA_TOKEN" \
-  https://your-gitea-server/api/v1/user
+→ Blocks with OPTIONS if critical plugins are missing (including Superpowers)
+→ Or confirms "proceed" if config is optimal
 ```
 
 ---
 
-### Self-hosted GitHub Enterprise
+## Plugins reference
 
-```bash
-# Configure gh for your instance
-gh config set -h github.yourcompany.com git_protocol https
-gh auth login --hostname github.yourcompany.com
+All plugins below are installed by `install-plugins.sh`.
 
-# Verify
-gh auth status --hostname github.yourcompany.com
-```
-
----
+### Quick reference
 
-### Self-hosted GitLab
+The mechanism: Claude Code loads every active skill's **description** into a shared context budget
+at session start (default 8000 chars). Even if you never invoke the skill, its description
+is already consuming tokens. **Disabling a plugin prevents its descriptions from loading entirely.**
 
-```bash
-glab auth login --hostname gitlab.yourcompany.com --token glpat-xxxx
-```
+A `hooks/session-start.sh` hook shows the current toggle status at the start of every session.
+Run `/plugin-check` anytime to get a full recommendation for the current project type.
 
----
+| Plugin | Status | Passive cost | When to toggle ON | Installed by |
+|---|---|---|---|---|
+| **security-guidance** | ✅ ALWAYS ON | 0 tokens (hook only) | — | marketplace |
+| **RTK** | ✅ ALWAYS ON | 0 tokens (hook only) | — | cargo (pinned in plugins.lock.json) |
+| **Superpowers** | ✅ REQUIRED | ~600–1000 tokens | — required by orchestrators, auto-detected | marketplace |
+| **skill-creator** | ✅ ALWAYS ON | ~100 tokens | — | marketplace |
+| **pr-review-toolkit** | ✅ ALWAYS ON | ~300 tokens | — use `/pr-review-toolkit:review-pr` | marketplace |
+| **GStack** | 🔄 TOGGLE | ~2500–3000 tokens | Full-product: UI + design + deploy + browser QA | git submodule |
+| **GSD** | 🔄 TOGGLE | ~500–800 tokens | Feature spanning multiple days/sessions | npx (pinned in plugins.lock.json) |
+| **frontend-design** | 🔄 TOGGLE | ~200 tokens | Any project with a UI | marketplace |
+| **ui-ux-pro-max** | 🔄 TOGGLE | ~400 tokens | Design system, color/typography choices | marketplace |
+| **Context7 MCP** | 🔄 TOGGLE | ~200 tokens | Fast-evolving libs (Next.js, React, Prisma…) | MCP manual |
 
-### Token security
+**Rule:** toggle plugins are OFF by default. `/plugin-check` signals when to enable them.
+If you use `/init-project` or `/ship-feature`, plugin-check runs automatically as STEP 0
+and **blocks if Superpowers is not active**.
 
-- **Never commit tokens** to git — they go in `~/.zshrc`, `~/.bashrc`, or a secrets manager
-- **Rotate tokens** when they expire or are compromised
-- **Minimum scopes** — only grant what `/git-pr` needs (repo read/write)
-- Claude Code reads env vars securely — tokens are never written to disk by Claude
+### Version pinning
 
----
+RTK and GSD versions are pinned in `plugins.lock.json`:
 
-### Verify your setup
-
-```bash
-# Run inside Claude Code to verify everything
-/git-pr check-auth
-# → Detects provider from current repo remote
-# → Tests authentication
-# → Reports status per provider
+```json
+{
+  "rtk": { "version": "v0.34.3" },
+  "gsd": { "version": "1.30.0" }
+}
 ```
 
-Or manually:
-```bash
-git remote get-url origin   # see which provider
-gh auth status              # GitHub CLI status
-glab auth status            # GitLab CLI status
-curl -s -H "Authorization: token $GOGS_TOKEN" \
-  <your-gogs-url>/api/v1/user | jq .login  # Gogs/Gitea
-```
+`install-plugins.sh` reads these versions automatically.
+To update a pinned version: edit `plugins.lock.json`, then re-run `install-plugins.sh`.
+GStack is pinned via its git submodule pointer.
 
----
-
-## Plugins reference
-
-All plugins installed by `install-plugins.sh`.
-
-### At-a-glance: always on vs toggle
-
-The mechanism: Claude Code loads every active skill's **description** at session start
-into a shared budget (8000 chars). Even if never invoked, the description costs tokens.
-Disabling a plugin → descriptions never load.
-
-A `hooks/session-start.sh` hook shows toggle status at every session start.
-Run `/plugin-check` for a full recommendation for the current project type.
-
-| Plugin | Status | Cost/session | When to enable | Installed by |
-|---|---|---|---|---|
-| **security-guidance** | ✅ ALWAYS ON | 0 (hook only) | — | marketplace |
-| **RTK** | ✅ ALWAYS ON | 0 (hook only) | — | cargo + rtk init |
-| **Superpowers** | ✅ ALWAYS ON | ~600–1000 | — auto-activates | marketplace |
-| **skill-creator** | ✅ ALWAYS ON | ~100 | — | marketplace |
-| **pr-review-toolkit** | ✅ ALWAYS ON | ~300 | — `/pr-review-toolkit:review-pr` | marketplace |
-| **GStack** | 🔄 TOGGLE | ~2500–3000 | Full-product: UI + design + deploy + QA browser | submodule |
-| **GSD** | 🔄 TOGGLE | ~500–800 | Feature spanning multiple days/sessions | npx |
-| **frontend-design** | 🔄 TOGGLE | ~200 | Any project with a UI | marketplace |
-| **ui-ux-pro-max** | 🔄 TOGGLE | ~400 | Design system, color/typography | marketplace |
-| **Context7 MCP** | 🔄 TOGGLE | ~200 | Fast-evolving libs (Next.js, React, Prisma…) | MCP manual |
-
-Toggle plugins start **OFF**. `/plugin-check` signals when to enable them.
-`/init-project` and `/ship-feature` run plugin-check automatically as STEP 0b.
-
-### Disable a plugin for a specific project
+### Disabling a plugin for a specific project
 
 ```bash
-/plugin    # inside Claude Code → toggle off
+# In Claude Code
+/plugin
+# → Find the plugin → toggle off for this scope
 ```
 
-Or in `.claude/settings.json`:
+Or in the project's `.claude/settings.json`:
 ```json
 {
   "enabledPlugins": {
-    "gstack@gstack": false
+    "gstack@gstack": false,
+    "gsd@gsd": false
   }
 }
 ```
 
-### Enable a plugin for a project (share with teammates)
+### Enabling a plugin for a specific project (so teammates can install it)
 
 ```json
 {
@@ -481,7 +309,10 @@ Or in `.claude/settings.json`:
   },
   "extraKnownMarketplaces": {
     "ui-ux-pro-max-skill": {
-      "source": { "source": "github", "repo": "nextlevelbuilder/ui-ux-pro-max-skill" }
+      "source": {
+        "source": "github",
+        "repo": "nextlevelbuilder/ui-ux-pro-max-skill"
+      }
     }
   }
 }
@@ -506,81 +337,93 @@ DENY always wins over ALLOW at any level.
 .claudeignore applies independently of all permission rules.
 ```
 
-### Global `settings.json` (this repo)
-
-Contains global deny/ask/allow rules AND a SessionStart hook:
-
-```json
-"hooks": {
-  "SessionStart": [
-    { "hooks": [{ "type": "command", "command": "bash ~/.claude/hooks/session-start.sh" }] }
-  ]
-}
-```
+### Global settings (this repo's `settings.json`)
 
-The hook prints toggle plugin status at every session start — zero API calls, filesystem only.
+77 deny rules, 16 ask rules, 57 allow rules.
 
 | Section | Purpose |
 |---|---|
-| `deny` — secrets | Blocks `.env`, `.pem`, `.key`, SSH keys, cloud credentials |
+| `deny` — secrets (Read) | Blocks `Read` on `.env`, `.pem`, `.key`, SSH keys, cloud credentials |
+| `deny` — secrets (Bash) | Blocks `cat`, `head`, `tail`, `grep`, `less`, `more` on `.env` and secret files |
 | `deny` — destructive | Blocks `rm -rf`, `git push --force`, `chmod 777` |
 | `deny` — system | Blocks `sudo`, `ssh`, `scp`, `crontab`, `systemctl` |
 | `deny` — injection | Blocks `curl \| bash`, `wget \| sh` |
+| `deny` — escalation | Blocks `bash -c`, `eval`, `exec`, `find -delete`, `perl -e`, `ruby -e` |
 | `ask` — risky | Prompts before `git push`, `docker run`, package managers |
-| `allow` — safe reads | Auto-approves git read-only, `ls`, `cat`, `grep`, `find` |
+| `ask` — write tools | Prompts before `xargs`, `sed -i` (in-place file editing) |
+| `allow` — safe reads | Auto-approves git read-only, `ls`, `cat`, `grep`, `find`, `sed` (stdout only) |
 | `disableBypassPermissionsMode` | Prevents YOLO mode globally |
 
 ### Per-project setup
 
 ```bash
-cd your-project && mkdir -p .claude
+cd your-project
+mkdir -p .claude
 
-# Project settings (commit)
-cp ~/claude-config/templates/settings/settings.json .claude/settings.json
+# Find the repo from any existing symlink
+CONF="$(dirname "$(readlink ~/.claude/CLAUDE.md)")"
 
-# Personal overrides (never commit)
-cp ~/claude-config/templates/settings/settings.local.json .claude/settings.local.json
+# Project settings (commit to project git)
+cp "$CONF/templates/settings/settings.json" .claude/settings.json
+
+# Personal overrides (never commit — gitignore it)
+cp "$CONF/templates/settings/settings.local.json" .claude/settings.local.json
 echo ".claude/settings.local.json" >> .gitignore
 
-# Hard file exclusions (commit)
-cp ~/claude-config/templates/settings/.claudeignore .claudeignore
+# Hard file exclusions (commit to project git)
+cp "$CONF/templates/settings/.claudeignore" .claudeignore
 
-# Project CLAUDE.md (commit)
-cp ~/claude-config/templates/project-CLAUDE.md .claude/CLAUDE.md
+# Project CLAUDE.md (commit to project git)
+cp "$CONF/templates/project-CLAUDE.md" .claude/CLAUDE.md
 ```
 
 ---
 
 ## Updating
 
-### This repo
+### One-command update (recommended)
+
+```bash
+# From the repo directory
+bash update-all.sh
+# Pulls config, updates GStack submodule, updates RTK (pinned version), refreshes symlinks, runs doctor
+```
+
+### Manual updates
+
+#### This repo
 ```bash
-cd ~/claude-config && git pull
-# Symlinks → changes active immediately, no restart needed
+# cd into the repo (wherever you cloned it)
+git pull
+# Symlinks → changes active immediately
 ```
 
-### GStack (submodule)
+#### GStack (submodule)
 ```bash
-# Option A — from Claude Code
+# Option A — inside Claude Code (recommended)
 /gstack-upgrade
 
-# Option B — via submodule (pins version in your repo)
-cd ~/claude-config
+# Option B — via submodule (from the repo directory)
 git submodule update --remote skills-external/gstack
 cd skills-external/gstack && ./setup
 git add skills-external/gstack
-git commit -m "chore: update gstack"
+git commit -m "chore: update gstack to latest"
 ```
 
-### Marketplace plugins
+GStack is a git submodule. Its version is pinned in your config repo — reproducible on every machine.
+
+#### RTK
 ```bash
-/plugin marketplace update
+# Uses the version pinned in plugins.lock.json (from the repo directory)
+bash update-all.sh
+
+# Or manually (check latest at https://github.com/rtk-ai/rtk/releases)
+cargo install --git https://github.com/rtk-ai/rtk --tag v0.34.3 --force
 ```
 
-### RTK
+#### Marketplace plugins
 ```bash
-cargo install --git https://github.com/rtk-ai/rtk --force
-rtk init -g --auto-patch   # re-apply hook if needed
+/plugin marketplace update    # inside Claude Code
 ```
 
 ---
@@ -596,6 +439,7 @@ name: myskill
 description: What this skill does — front-load the key use case (max 250 chars)
 argument-hint: <what to pass>
 disable-model-invocation: true
+allowed-tools: Read, Write, Edit, Bash, Grep, Glob
 ---
 
 Load and follow strictly:
@@ -612,8 +456,101 @@ $ARGUMENTS
 
 ## Per-project agent overrides
 
+Override any global agent for a specific project:
+
+```bash
+CONF="$(dirname "$(readlink ~/.claude/CLAUDE.md)")"
+cp "$CONF/agents/refactorer.md" .claude/agents/refactorer.md
+# Edit .claude/agents/refactorer.md — the local version takes precedence
+```
+
+---
+
+## Maintenance
+
+### Diagnostic
+
+```bash
+# Quick check from terminal (from the repo directory)
+bash doctor.sh
+
+# Or from within Claude Code
+/health
+
+# Unified commands via Makefile (from the repo directory)
+make doctor     # diagnostic
+make update     # pull + submodules + symlinks + doctor
+make install    # link.sh + install-plugins.sh
+```
+
+`doctor.sh` checks 7 axes: symlinks, GStack submodule, prerequisites (git, Node, Cargo, Python, Claude Code),
+plugins (RTK, Superpowers, Context7), permissions, token budget estimate, and config consistency
+(frontmatter coherence, CRLF detection).
+
+`session-start.sh` runs a quick health check at every session start (filesystem only, no subprocesses)
+and displays toggle plugin status with `/plugin-check` and `/health` hints.
+
+Both scripts source `lib/detect-plugins.sh` for consistent plugin detection logic.
+
+### Updating
+
 ```bash
-# Override an agent for a specific project
-cp ~/claude-config/agents/refactorer.md .claude/agents/refactorer.md
-# Edit — the local version takes precedence over global
+# One-command update (from the repo directory)
+bash update-all.sh
+
+# Or step by step
+git pull                                                # this repo
+git submodule update --remote skills-external/gstack    # GStack
+bash link.sh                                            # refresh symlinks
+bash doctor.sh                                          # verify
 ```
+
+---
+
+## Troubleshooting
+
+### "command not found" after install
+Restart your shell or run `source ~/.bashrc` / `source ~/.zshrc`.
+
+### Orchestrator blocks at STEP 0 — Superpowers missing
+The plugin-advisor blocks `/init-project` and `/ship-feature` if Superpowers is not active.
+Install: `claude plugin marketplace add obra/superpowers-marketplace && claude plugin install --scope user superpowers@superpowers-marketplace`
+Then re-run the orchestrator.
+
+### "agent not found" or hallucinated agent content
+Symlinks are broken. `cd` into your config repo and run `bash link.sh`, then verify with `bash doctor.sh`.
+
+### GStack skills not showing up
+Run `bash link.sh` and verify: `ls -la ~/.claude/skills/gstack`.
+If missing: `cd` into your config repo and run `git submodule update --init`.
+
+### link.sh warns "is a real directory"
+If `~/.claude/agents/`, `~/.claude/skills/`, or `~/.claude/lib/` exist as real directories (not symlinks
+from a previous `link.sh` run), the script skips them to avoid data loss. Rename or remove the directory, then re-run `link.sh`.
+
+### Token budget exceeded / skills truncated at session start
+Too many plugins active. Run `/plugin-check` to optimize.
+Run `bash doctor.sh` for a token budget estimate.
+
+### settings.json not applying
+Check precedence: deny always wins over allow at any level. `.claudeignore` overrides all permission rules.
+Verify deny count: `cat ~/.claude/settings.json | python3 -c "import json,sys; print(len(json.load(sys.stdin)['permissions']['deny']))"`
+Expected: 77 deny rules.
+
+### Claude reads .env despite deny rules
+The `Read(**/.env)` deny rule blocks the Read tool. `Bash(cat .env)` and similar commands have separate
+deny rules (included in this config). For hard exclusion regardless of tool, use `.claudeignore` in the project root.
+
+### install-plugins.sh failed — where are the logs?
+Check `install-YYYYMMDD-HHMMSS.log` in your config repo directory — the script logs all output to a timestamped file.
+
+---
+
+## Known limitations
+
+- **Deny rules are pattern-based, not sandboxed.** Common bypass vectors (`bash -c`, `eval`, `xargs`, `cat .env`) are blocked, but novel indirect patterns are still possible. `.claudeignore` is the only hard file exclusion mechanism.
+- **Superpowers is a hard dependency** for `/init-project` and `/ship-feature`. The plugin-advisor (STEP 0) auto-detects and blocks if Superpowers is missing, with install instructions. There is no manual fallback mode.
+- **Marketplace plugin versions are not pinned.** They install latest. Non-marketplace tools (RTK, GSD) are pinned in `plugins.lock.json` and read by `install-plugins.sh`.
+- **Token budget is finite and not directly observable.** With all toggle plugins active, the description budget can exceed 60%. Run `/health` or `bash doctor.sh` for an estimate.
+- **Agent frontmatter fields** like `model` and `memory` are declared but their enforcement by Claude Code is not guaranteed. They serve as documentation more than strict runtime controls.
+- **`Bash(cat *)` in allow vs `Bash(cat .env)` in deny** depends on Claude Code resolving deny-wins. This is the expected behavior but cannot be tested outside the runtime.

+ 0 - 473
agents/git-workflow.md

@@ -1,473 +0,0 @@
----
-name: git-workflow
-description: Analyze all changes since branch start (retroactive, session-agnostic), create logical commits, push, and open a PR/MR on GitHub, GitLab, Gogs, or Gitea. Never merges — creates a draft PR for user validation.
-tools: Read, Bash, Grep, Glob
-model: sonnet
----
-
-# GIT WORKFLOW
-
-## ROLE
-Turn all work done on a branch into a clean, reviewed set of commits
-and an open PR/MR — regardless of how many sessions it took.
-
-## GOAL
-- Stage and commit all uncommitted changes in logical groups
-- Push the branch to the remote
-- Create a PR/MR on the right platform
-- Never merge — the user validates the PR
-
----
-
-## BRANCH SETUP (called by init-project and ship-feature)
-
-This procedure runs before any code is written.
-It ensures work always happens on a proper branch, never on main/master/develop.
-
-### 1. Check current branch
-
-```bash
-CURRENT=$(git branch --show-current)
-echo "Current branch: $CURRENT"
-```
-
-### 2. Determine protected branches
-
-Protected branches (never commit directly):
-- `main`, `master`, `develop`, `dev`, `staging`, `production`, `prod`
-
-```bash
-PROTECTED="main master develop dev staging production prod"
-```
-
-### 3. If on a protected branch → create a feature branch
-
-```bash
-# Derive branch name from context:
-# - init-project: feature/<project-slug-from-brief>
-# - ship-feature: feature/<feature-slug-from-argument>
-# Slugify: lowercase, replace spaces with hyphens, max 50 chars
-
-BRANCH_NAME="feature/<slug>"
-
-# Ensure main is up to date before branching
-git fetch origin
-git pull origin $CURRENT --ff-only 2>/dev/null || true
-
-# Create and checkout the feature branch
-git checkout -b $BRANCH_NAME
-
-echo "✅ Created branch: $BRANCH_NAME (from $CURRENT)"
-```
-
-### 4. If already on a feature/bugfix/hotfix branch → sync with base
-
-```bash
-BASE=$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD origin/master 2>/dev/null)
-
-# Check if the base branch has new commits the feature branch doesn't have
-git fetch origin
-BEHIND=$(git rev-list HEAD..origin/<base-branch> --count 2>/dev/null || echo "0")
-```
-
-If `BEHIND > 0`:
-```
-⚠️  Your branch is behind <base-branch> by $BEHIND commit(s).
-Rebasing to sync...
-```
-Run the CONFLICT-SAFE REBASE procedure below.
-
-If `BEHIND = 0`: print `✅ Branch is up to date` and continue.
-
-### 5. Branch naming conventions
-
-| Context | Branch format | Example |
-|---|---|---|
-| New project (init-project) | `feature/<project-name>` | `feature/zenquality-website` |
-| New feature (ship-feature) | `feature/<feature-name>` | `feature/user-authentication` |
-| Bug on a feature branch | `bugfix/<description>` from feature | `bugfix/fix-login-redirect` |
-| Urgent production fix | `hotfix/<description>` from main | `hotfix/patch-csrf-vulnerability` |
-| Release prep | `release/<version>` from main | `release/v1.2.0` |
-
----
-
-## CONFLICT-SAFE REBASE
-
-Use this whenever rebasing a branch against its base.
-
-```bash
-git rebase origin/<base-branch>
-```
-
-**If rebase exits cleanly:** done.
-
-**If conflicts are detected:**
-
-```bash
-# List conflicted files
-git diff --name-only --diff-filter=U
-```
-
-For each conflicted file:
-1. Read the file — identify the conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`)
-2. Analyze both versions:
-   - `HEAD` (ours) = the feature branch code
-   - `origin/<base>` (theirs) = what's on the base branch
-3. Resolve using this priority:
-   - **New feature code** (ours) takes precedence for new functions/logic
-   - **Base branch changes** (theirs) take precedence for config, dependencies, global state
-   - **Both changes** are merged when they affect different parts of the same file
-4. Write the resolved file (no conflict markers left)
-5. Stage it: `git add <file>`
-6. Continue: `git rebase --continue`
-
-**If a conflict cannot be auto-resolved** (same lines modified with incompatible logic):
-```
-⚠️  CONFLICT — manual resolution required
-File: <filename>
-Ours:   <what the feature branch has>
-Theirs: <what base branch has>
-
-How should this be resolved?
-  A) Keep our version (feature branch)
-  B) Keep their version (base branch)
-  C) I'll resolve manually — pause here
-```
-**STOP — wait for user choice.**
-
-After user responds:
-- A or B → apply, `git add <file>`, `git rebase --continue`
-- C → `git rebase --abort` and hand back control to user
-
-**After all conflicts resolved:**
-```bash
-git log --oneline <base-branch>..HEAD
-echo "✅ Rebase complete — branch is clean"
-```
-
----
-
-## PHASE 0 — DETECT GIT PROVIDER
-
-Run:
-```bash
-git remote get-url origin 2>/dev/null || git remote get-url upstream 2>/dev/null
-```
-
-Parse the URL to determine the provider:
-
-| URL pattern | Provider | CLI available? |
-|---|---|---|
-| `github.com` | GitHub | check `gh auth status` |
-| `gitlab.com` or `gitlab.*` | GitLab | check `glab auth status` |
-| anything else | Gogs / Gitea | API only (no official CLI) |
-
-Extract:
-- `REMOTE_URL` — full remote URL
-- `PROVIDER` — github / gitlab / gogs-gitea
-- `BASE_URL` — for Gogs/Gitea: `https://hostname` (strip path)
-- `OWNER` — repo owner/organization
-- `REPO` — repo name
-- `CLI_AVAILABLE` — gh / glab / none
-
-For Gogs/Gitea, check for an API token in env:
-```bash
-echo "${GOGS_TOKEN:-${GITEA_TOKEN:-not-set}}"
-```
-If not set, print:
-```
-⚠️  Gogs/Gitea detected. Set one of these env vars:
-    export GOGS_TOKEN="your-token"
-    export GITEA_TOKEN="your-token"
-    Then re-run /git-pr
-```
-And STOP.
-
----
-
-## PHASE 1 — ANALYZE BRANCH STATE
-
-### 1a. Identify current branch and base
-
-```bash
-git branch --show-current
-```
-
-Determine the base branch from the branch name:
-| Branch prefix | Default base | PR type |
-|---|---|---|
-| `feature/*` | `develop` (or `main` if no develop) | Feature |
-| `feat/*` | `develop` (or `main`) | Feature |
-| `bugfix/*` | `develop` | Bug fix |
-| `fix/*` | `develop` | Bug fix |
-| `hotfix/*` | `main` | Hotfix |
-| `release/*` | `main` | Release |
-| `chore/*` | `develop` (or `main`) | Chore |
-| anything else | `main` | General |
-
-Verify the base branch exists:
-```bash
-git rev-parse --verify <base-branch> 2>/dev/null
-```
-
-### 1b. Retroactive diff — ALL changes since branch start
-
-```bash
-# All committed changes on this branch (retroactive, session-agnostic)
-git log --oneline <base-branch>..HEAD
-
-# All uncommitted changes
-git status --short
-
-# Full diff of everything: committed + uncommitted vs base
-git diff <base-branch>...HEAD --name-status
-
-# Stats
-git diff <base-branch>...HEAD --stat
-```
-
-The `git diff <base>...HEAD` (three dots) shows everything since
-the branch diverged from base — not just since last commit.
-This is the source of truth regardless of session count.
-
-### 1c. Build the CHANGE MAP
-
-Categorize every changed file:
-- `config` — package.json, Cargo.toml, go.mod, requirements.txt, docker-compose.yml, Makefile, CI files
-- `model` — data models, schemas, migrations, types
-- `core` — business logic, services, domain
-- `api` / `routes` — endpoints, controllers, handlers
-- `ui` — components, pages, styles, assets
-- `test` — all test files
-- `docs` — README, CLAUDE.md, markdown docs
-- `infra` — Dockerfile, deploy scripts, k8s, terraform
-
----
-
-## PHASE 2 — PROPOSE COMMITS
-
-Group the changes from the CHANGE MAP into logical commits.
-Order: config → model → core → api/routes → ui → test → docs → infra
-
-For each group, propose a commit using Conventional Commits:
-```
-<type>(<scope>): <description>
-
-Types: feat, fix, chore, refactor, test, docs, style, ci, build, perf
-Scope: optional, matches the module/directory
-```
-
-Present the proposed commit plan:
-```
-================================================================
-GIT WORKFLOW — COMMIT PLAN
-================================================================
-
-BRANCH   : <current-branch>
-BASE     : <base-branch>
-PROVIDER : <github/gitlab/gogs-gitea>
-
-CHANGES SINCE BRANCH START
----------------------------
-<git diff --stat output>
-
-PROPOSED COMMITS
-----------------
-  1. chore(deps): update dependencies — [package.json, go.mod]
-  2. feat(auth): add user model and migration — [models/user.go, migrations/001_users.sql]
-  3. feat(auth): implement login and JWT handlers — [handlers/auth.go, services/auth.go]
-  4. test(auth): add unit tests for auth service — [tests/auth_test.go]
-  5. docs: update README with auth setup — [README.md]
-
-UNCOMMITTED CHANGES (will be staged in their respective commit)
----------------------------------------------------------------
-<git status --short>
-
-================================================================
-Approve this commit plan? (yes / modify / cancel)
-================================================================
-```
-
-**MANDATORY STOP — wait for user approval.**
-
-IF modify → user describes changes → adjust plan → re-present
-IF cancel → stop, no changes made
-IF yes → proceed to PHASE 3
-
----
-
-## PHASE 3 — EXECUTE COMMITS
-
-For each proposed commit, in order:
-
-```bash
-# Stage the specific files for this commit
-git add <files-for-this-commit>
-
-# Commit with the proposed message
-git commit -m "<type>(<scope>): <description>"
-```
-
-If a file has both committed and uncommitted changes:
-- Stage only the uncommitted portion
-- Include it in the appropriate commit group
-
-After all commits:
-```bash
-git log --oneline <base-branch>..HEAD
-```
-Show the final commit list for confirmation.
-
----
-
-## PHASE 4 — PUSH
-
-```bash
-# Push, setting upstream if branch is new
-git push --set-upstream origin <current-branch>
-```
-
-**If push is rejected** (remote has diverged):
-1. Run the CONFLICT-SAFE REBASE procedure:
-   ```bash
-   git fetch origin
-   git rebase origin/<current-branch>
-   ```
-2. Resolve any conflicts as described in CONFLICT-SAFE REBASE
-3. Push again: `git push origin <current-branch>`
-
-**If the push is still rejected after rebase:**
-```bash
-git log --oneline origin/<current-branch>..HEAD
-```
-Show the commits that haven't been pushed and ask the user:
-```
-⚠️  Push still rejected after rebase.
-    Local commits not on remote: <N>
-    Options:
-      A) Force push (overwrites remote — use only if remote is yours)
-      B) Investigate manually
-```
-**STOP — wait for user choice. Never force push without explicit approval.**
-
----
-
-## PHASE 5 — CREATE PR / MR
-
-Build the PR body from:
-- `git log <base-branch>..HEAD --format="- %s"` — commit list
-- Modified file categories (from CHANGE MAP)
-- CLAUDE.md project context
-
-PR body template:
-```markdown
-## Summary
-
-<2-3 sentence description derived from branch name and commit messages>
-
-## Changes
-
-<commit list from git log>
-
-## Modified areas
-
-<list of changed modules/directories>
-
-## Testing
-
-<describe test coverage based on test files changed>
-
----
-*Created by /git-pr — validate then merge*
-```
-
-### GitHub
-
-```bash
-# With gh CLI (preferred)
-gh pr create \
-  --base <base-branch> \
-  --head <current-branch> \
-  --title "<type>: <feature-name-from-branch>" \
-  --body "<pr-body>" \
-  --draft
-
-# Without gh CLI — print URL for manual creation
-echo "Create PR at: https://github.com/<owner>/<repo>/compare/<base>...<branch>"
-```
-
-### GitLab
-
-```bash
-# With glab CLI (preferred)
-glab mr create \
-  --source-branch <current-branch> \
-  --target-branch <base-branch> \
-  --title "<type>: <feature-name>" \
-  --description "<pr-body>" \
-  --draft
-
-# Without glab CLI
-echo "Create MR at: https://gitlab.com/<owner>/<repo>/-/merge_requests/new?merge_request[source_branch]=<branch>"
-```
-
-### Gogs / Gitea
-
-Use the API directly (both use GitHub API v3-compatible format):
-
-```bash
-curl -s -X POST \
-  "${BASE_URL}/api/v1/repos/${OWNER}/${REPO}/pulls" \
-  -H "Authorization: token ${GOGS_TOKEN:-$GITEA_TOKEN}" \
-  -H "Content-Type: application/json" \
-  -d "{
-    \"title\": \"<type>: <feature-name>\",
-    \"body\": \"<pr-body-escaped>\",
-    \"head\": \"<current-branch>\",
-    \"base\": \"<base-branch>\"
-  }"
-```
-
-If the API call returns an error, print the full response and suggest
-creating the PR manually via the web UI.
-
----
-
-## PHASE 6 — FINAL REPORT
-
-```
-================================================================
-PR CREATED
-================================================================
-
-BRANCH   : <current-branch> → <base-branch>
-COMMITS  : <N> commits pushed
-PLATFORM : <GitHub/GitLab/Gogs/Gitea>
-
-COMMITS
--------
-<git log --oneline output>
-
-PR / MR
--------
-URL  : <pr-url or "create manually at <url>">
-Type : Draft — awaiting your review and merge
-
-NEXT STEPS
-----------
-1. Review the PR at the URL above
-2. Request reviews if needed
-3. Merge when approved
-================================================================
-```
-
----
-
-## RULES
-
-- Never merge, never rebase main/master/develop
-- Never force push unless explicitly asked
-- Never create commits on main, master, or develop directly
-- If on main/master — STOP and ask user to checkout a feature branch first
-- Draft PR by default — user controls merge
-- If no CLI tool and no API token — print manual instructions, do not fail silently

+ 1 - 0
agents/plugin-advisor.md

@@ -123,6 +123,7 @@ ACTION REQUIRED? [YES — resolve blocking issues first] / [NO — proceed]
 ## THRESHOLDS
 
 **Block and require action if:**
+- Superpowers is not active (required by /init-project and /ship-feature orchestrators — install command: `claude plugin marketplace add obra/superpowers-marketplace && claude plugin install --scope user superpowers@superpowers-marketplace`)
 - Project has significant frontend AND frontend-design + ui-ux-pro-max are both disabled
 - Project uses Next.js/React/Prisma/Supabase AND context7 is not configured
 - Project is full-product (UI + deploy + QA) AND gstack is not installed

+ 261 - 0
doctor.sh

@@ -0,0 +1,261 @@
+#!/usr/bin/env bash
+# ============================================================
+# Claude Code — Config doctor
+# Diagnoses symlinks, prerequisites, plugins, permissions,
+# and token budget. Run after install or when something breaks.
+# ============================================================
+set -euo pipefail
+
+RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
+ERRORS=0; WARNS=0
+
+pass() { echo -e "  ${GREEN}✓${NC} $1"; }
+fail() { echo -e "  ${RED}✗${NC} $1"; ERRORS=$((ERRORS + 1)); }
+warn() { echo -e "  ${YELLOW}⚠${NC}  $1"; WARNS=$((WARNS + 1)); }
+info() { echo -e "  ${BLUE}→${NC} $1"; }
+
+REPO="$(cd "$(dirname "$0")" && pwd)"
+VERSION=$(cat "$REPO/version.txt" 2>/dev/null || echo "unknown")
+
+# Load shared detection library
+# shellcheck source=lib/detect-plugins.sh
+source "$REPO/lib/detect-plugins.sh"
+
+echo ""
+echo "═══ claude-config doctor (v${VERSION}) ═══"
+echo ""
+
+# ────────────────────────────────────────────────────────────
+# 1. Core symlinks
+# ────────────────────────────────────────────────────────────
+echo "── Symlinks ──"
+
+check_symlink() {
+  local name="$1"
+  local target="$HOME/.claude/$name"
+
+  if [ ! -e "$target" ] && [ ! -L "$target" ]; then
+    fail "~/.claude/$name — MISSING"
+    return
+  fi
+
+  if [ -L "$target" ]; then
+    local real
+    real=$(readlink -f "$target" 2>/dev/null || readlink "$target")
+    if [ ! -e "$real" ]; then
+      fail "~/.claude/$name → $real — BROKEN SYMLINK"
+    else
+      pass "~/.claude/$name"
+    fi
+  else
+    warn "~/.claude/$name exists but is NOT a symlink (expected symlink to repo)"
+  fi
+}
+
+check_symlink "CLAUDE.md"
+check_symlink "settings.json"
+check_symlink "agents"
+check_symlink "skills"
+check_symlink "hooks/session-start.sh"
+
+echo ""
+
+# ────────────────────────────────────────────────────────────
+# 2. GStack submodule
+# ────────────────────────────────────────────────────────────
+echo "── GStack submodule ──"
+
+if [ -d "$REPO/skills-external/gstack" ] || [ -f "$REPO/skills-external/gstack/.git" ]; then
+  pass "Submodule present at skills-external/gstack"
+else
+  warn "Submodule not initialized — run: git submodule update --init"
+fi
+
+if [ -L "$HOME/.claude/skills/gstack" ]; then
+  real=$(readlink -f "$HOME/.claude/skills/gstack" 2>/dev/null || readlink "$HOME/.claude/skills/gstack")
+  if [ -d "$real" ]; then
+    pass "Symlink OK → $real"
+  else
+    fail "Symlink broken → $real"
+  fi
+else
+  warn "GStack not symlinked — run: bash link.sh"
+fi
+
+echo ""
+
+# ────────────────────────────────────────────────────────────
+# 3. Prerequisites
+# ────────────────────────────────────────────────────────────
+echo "── Prerequisites ──"
+
+if command -v git &>/dev/null; then
+  pass "git $(git --version | awk '{print $3}')"
+else
+  fail "git not found"
+fi
+
+if command -v node &>/dev/null; then
+  NODE_VER=$(node --version | sed 's/v//' | cut -d. -f1)
+  if [ "$NODE_VER" -ge 18 ]; then
+    pass "Node.js $(node --version)"
+  else
+    warn "Node.js $(node --version) — need >=18"
+  fi
+else
+  fail "Node.js not found"
+fi
+
+if command -v cargo &>/dev/null; then
+  pass "Cargo $(cargo --version | awk '{print $2}')"
+else
+  warn "Cargo not found (RTK unavailable)"
+fi
+
+if command -v python3 &>/dev/null; then
+  pass "Python $(python3 --version | awk '{print $2}')"
+else
+  warn "Python3 not found"
+fi
+
+if command -v claude &>/dev/null; then
+  pass "Claude Code $(claude --version 2>/dev/null | head -1 || echo 'installed')"
+else
+  fail "Claude Code not found — install from https://code.claude.com"
+fi
+
+echo ""
+
+# ────────────────────────────────────────────────────────────
+# 4. Key plugins
+# ────────────────────────────────────────────────────────────
+echo "── Plugins ──"
+
+if detect_rtk; then
+  pass "RTK installed"
+else
+  warn "RTK not installed — run install-plugins.sh"
+fi
+
+if detect_superpowers; then
+  pass "Superpowers plugin detected"
+else
+  fail "Superpowers not detected — orchestrators (/init-project, /ship-feature) will fail"
+fi
+
+if detect_context7; then
+  pass "Context7 MCP configured"
+else
+  info "Context7 MCP not configured (optional — needed for fast-evolving libs)"
+fi
+
+echo ""
+
+# ────────────────────────────────────────────────────────────
+# 5. Permissions check
+# ────────────────────────────────────────────────────────────
+echo "── Permissions ──"
+
+SETTINGS="$HOME/.claude/settings.json"
+if [ -f "$SETTINGS" ] || [ -L "$SETTINGS" ]; then
+  if grep -q '"disableBypassPermissionsMode"' "$SETTINGS" 2>/dev/null; then
+    pass "Bypass mode disabled"
+  else
+    warn "disableBypassPermissionsMode not found in settings"
+  fi
+
+  DENY_COUNT=$(python3 -c "
+import json
+with open('$SETTINGS') as f:
+    d = json.load(f)
+print(len(d.get('permissions',{}).get('deny',[])))
+" 2>/dev/null || echo "?")
+  pass "Deny rules: $DENY_COUNT"
+else
+  fail "~/.claude/settings.json not found"
+fi
+
+echo ""
+
+# ────────────────────────────────────────────────────────────
+# 6. Token budget estimate
+# ────────────────────────────────────────────────────────────
+echo "── Token budget estimate ──"
+
+TOTAL_CHARS=0
+
+# Skill descriptions
+for f in "$HOME/.claude/skills/"*/SKILL.md; do
+  [ -f "$f" ] || continue
+  desc=$(sed -n 's/^description: //p' "$f" 2>/dev/null || true)
+  TOTAL_CHARS=$((TOTAL_CHARS + ${#desc}))
+done
+
+# Agent descriptions
+for f in "$HOME/.claude/agents/"*.md; do
+  [ -f "$f" ] || continue
+  desc=$(sed -n '/^---$/,/^---$/{ s/^description: //p }' "$f" 2>/dev/null || true)
+  TOTAL_CHARS=$((TOTAL_CHARS + ${#desc}))
+done
+
+if [ "$TOTAL_CHARS" -gt 6000 ]; then
+  warn "Custom descriptions: ~${TOTAL_CHARS} chars (budget ~8000) — risk of truncation"
+elif [ "$TOTAL_CHARS" -gt 4000 ]; then
+  info "Custom descriptions: ~${TOTAL_CHARS} chars (within budget, moderate margin)"
+else
+  pass "Custom descriptions: ~${TOTAL_CHARS} chars (comfortable)"
+fi
+
+echo ""
+
+# ────────────────────────────────────────────────────────────
+# 7. File consistency
+# ────────────────────────────────────────────────────────────
+echo "── Consistency ──"
+
+# Check all skills have disable-model-invocation
+MISSING_DMI=()
+for f in "$HOME/.claude/skills/"*/SKILL.md; do
+  [ -f "$f" ] || continue
+  name=$(basename "$(dirname "$f")")
+  if ! grep -q "disable-model-invocation" "$f" 2>/dev/null; then
+    MISSING_DMI+=("$name")
+  fi
+done
+if [ ${#MISSING_DMI[@]} -eq 0 ]; then
+  pass "All skills have disable-model-invocation"
+else
+  warn "Skills missing disable-model-invocation: ${MISSING_DMI[*]}"
+fi
+
+# Check CRLF
+CRLF_FILES=()
+for f in "$REPO"/*.md "$REPO"/agents/*.md "$REPO"/skills/*/SKILL.md; do
+  [ -f "$f" ] || continue
+  if grep -qP '\r' "$f" 2>/dev/null; then
+    CRLF_FILES+=("$(basename "$f")")
+  fi
+done
+if [ ${#CRLF_FILES[@]} -eq 0 ]; then
+  pass "No CRLF line endings detected"
+else
+  warn "CRLF detected in: ${CRLF_FILES[*]}"
+fi
+
+echo ""
+
+# ────────────────────────────────────────────────────────────
+# Summary
+# ────────────────────────────────────────────────────────────
+echo "═══════════════════════════════════════════"
+if [ "$ERRORS" -gt 0 ]; then
+  echo -e "${RED}  $ERRORS error(s)${NC}, ${YELLOW}$WARNS warning(s)${NC}"
+  echo ""
+  echo "  Fix: cd $REPO && bash link.sh && bash install-plugins.sh"
+  exit 1
+elif [ "$WARNS" -gt 0 ]; then
+  echo -e "  ${GREEN}No errors${NC}, ${YELLOW}$WARNS warning(s)${NC}"
+else
+  echo -e "  ${GREEN}All checks passed ✓${NC}"
+fi
+echo ""

+ 65 - 29
hooks/session-start.sh

@@ -4,52 +4,88 @@
 # Runs once per session. Zero API calls. Filesystem only.
 # ============================================================
 
-TOGGLE_ACTIVE=()
-TOGGLE_INACTIVE=()
+# ── Quick health check (filesystem only, no subprocesses) ──
+BROKEN=()
+for f in CLAUDE.md settings.json agents skills; do
+  [ ! -e "$HOME/.claude/$f" ] && BROKEN+=("$f")
+done
 
-# --- GStack ---
-if [ -d "$HOME/.claude/skills/gstack" ]; then
-  TOGGLE_ACTIVE+=("gstack")
-else
-  TOGGLE_INACTIVE+=("gstack")
-fi
+if [ ${#BROKEN[@]} -gt 0 ]; then
+  # Try to find the repo path from an existing symlink
+  _repo_hint=""
+  for _probe in CLAUDE.md settings.json; do
+    if [ -L "$HOME/.claude/$_probe" ]; then
+      _repo_hint="$(cd "$(dirname "$(readlink "$HOME/.claude/$_probe")")" 2>/dev/null && pwd)"
+      break
+    fi
+  done
+  _fix_cmd="${_repo_hint:+cd $_repo_hint && }bash link.sh"
 
-# --- GSD ---
-if ls "$HOME/.claude/skills/" 2>/dev/null | grep -qi "gsd"; then
-  TOGGLE_ACTIVE+=("gsd")
-else
-  TOGGLE_INACTIVE+=("gsd")
+  echo ""
+  echo "┌─ ⚠️  CONFIG ISSUES ────────────────────────────────┐"
+  for b in "${BROKEN[@]}"; do
+    printf "│  MISSING: ~/.claude/%-30s│\n" "$b"
+  done
+  printf "│  → %-47s│\n" "$_fix_cmd"
+  echo "│  → /health for full diagnostic                     │"
+  echo "└───────────────────────────────────────────────────┘"
+  unset _repo_hint _fix_cmd
 fi
 
-# --- UI/UX Pro Max ---
-if ls "$HOME/.claude/plugins/cache/" 2>/dev/null | grep -qi "ui-ux-pro-max"; then
-  TOGGLE_ACTIVE+=("ui-ux-pro-max")
+# ── Load shared detection library ──
+_lib="$(dirname "${BASH_SOURCE[0]}")/../lib/detect-plugins.sh"
+if [ -f "$_lib" ]; then
+  # shellcheck source=../lib/detect-plugins.sh
+  source "$_lib"
 else
-  TOGGLE_INACTIVE+=("ui-ux-pro-max")
+  # Fallback: inline detection if lib is missing
+  detect_gstack()          { [ -d "$HOME/.claude/skills/gstack" ]; }
+  detect_gsd()             { ls "$HOME/.claude/skills/" 2>/dev/null | grep -qi "gsd"; }
+  detect_uiux_pro_max()    { ls "$HOME/.claude/plugins/cache/" 2>/dev/null | grep -qi "ui-ux-pro-max"; }
+  detect_frontend_design() { ls "$HOME/.claude/plugins/cache/" 2>/dev/null | grep -qi "frontend-design"; }
+  detect_context7()        { claude mcp list 2>/dev/null | grep -q "context7"; }
 fi
+unset _lib
 
-# --- frontend-design ---
-if ls "$HOME/.claude/plugins/cache/" 2>/dev/null | grep -qi "frontend-design"; then
-  TOGGLE_ACTIVE+=("frontend-design")
-else
-  TOGGLE_INACTIVE+=("frontend-design")
-fi
+# ── Toggle plugin detection ──
 
-# --- Context7 MCP ---
-if claude mcp list 2>/dev/null | grep -q "context7"; then
-  TOGGLE_ACTIVE+=("context7")
-else
-  TOGGLE_INACTIVE+=("context7")
-fi
+TOGGLE_ACTIVE=()
+TOGGLE_INACTIVE=()
+
+for plugin in gstack gsd uiux_pro_max frontend_design context7; do
+  # Map function name to display name
+  case "$plugin" in
+    uiux_pro_max)    display="ui-ux-pro-max" ;;
+    frontend_design) display="frontend-design" ;;
+    *)               display="$plugin" ;;
+  esac
+
+  if "detect_$plugin" 2>/dev/null; then
+    TOGGLE_ACTIVE+=("$display")
+  else
+    TOGGLE_INACTIVE+=("$display")
+  fi
+done
 
 # --- Format output ---
 ACTIVE_STR="${TOGGLE_ACTIVE[*]:-none}"
 INACTIVE_STR="${TOGGLE_INACTIVE[*]:-none}"
 
+# Version detection: follow CLAUDE.md symlink back to repo, then read version.txt
+_claude_real="$(readlink "$HOME/.claude/CLAUDE.md" 2>/dev/null || true)"
+if [ -n "$_claude_real" ]; then
+  _repo_dir="$(cd "$(dirname "$_claude_real")" 2>/dev/null && pwd)"
+  CONFIG_VERSION=$(cat "$_repo_dir/version.txt" 2>/dev/null || echo "?")
+else
+  CONFIG_VERSION="?"
+fi
+unset _claude_real _repo_dir
+
 echo ""
 echo "┌─ Toggle plugins ──────────────────────────────────┐"
 printf "│  🟢 ON  : %-40s│\n" "$ACTIVE_STR"
 printf "│  ⚫ OFF : %-40s│\n" "$INACTIVE_STR"
 echo "│  💡 /plugin-check  before starting a new project  │"
+echo "│  🩺 /health  to run full diagnostic               │"
 echo "└───────────────────────────────────────────────────┘"
 echo ""

+ 53 - 57
install-plugins.sh

@@ -16,6 +16,31 @@ err()  { echo -e "${RED}✗${NC} $1"; }
 
 REPO="$(cd "$(dirname "$0")" && pwd)"
 
+# Log to file for post-mortem debugging (terminal output unchanged)
+LOG_FILE="$REPO/install-$(date +%Y%m%d-%H%M%S).log"
+exec > >(tee -a "$LOG_FILE") 2>&1
+
+# Load shared detection library
+# shellcheck source=lib/detect-plugins.sh
+source "$REPO/lib/detect-plugins.sh"
+
+# Read pinned version from plugins.lock.json
+# Usage: pinned_version "rtk" → prints version string or "latest"
+pinned_version() {
+  local key="$1"
+  if [ -f "$REPO/plugins.lock.json" ] && command -v python3 &>/dev/null; then
+    python3 -c "
+import json, sys
+with open('$REPO/plugins.lock.json') as f:
+    d = json.load(f)
+v = d.get('$key', {}).get('version', 'latest')
+print(v)
+" 2>/dev/null || echo "latest"
+  else
+    echo "latest"
+  fi
+}
+
 # ============================================================
 # DETECT OS
 # ============================================================
@@ -128,52 +153,9 @@ fi
 echo ""
 
 # ============================================================
-# STEP 2 — GIT CLI TOOLS (gh + glab for /git-pr)
-# ============================================================
-echo "── Step 2: Git CLI tools ────────────────────────────────────"
-echo ""
-
-# --- gh (GitHub CLI) ---
-if command -v gh &>/dev/null; then
-  ok "gh $(gh --version | head -1 | awk '{print $3}')"
-else
-  info "Installing gh (GitHub CLI)..."
-  case $OS in
-    macos)     brew install gh ;;
-    linux-apt) type -p curl > /dev/null || sudo apt-get install -y curl
-               curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
-               echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list
-               sudo apt-get update && sudo apt-get install -y gh ;;
-    linux-dnf) sudo dnf install -y gh ;;
-    linux-pacman) sudo pacman -S --noconfirm github-cli ;;
-    *) warn "Cannot auto-install gh on $OS — install from https://cli.github.com" ;;
-  esac
-  command -v gh &>/dev/null && ok "gh installed" || warn "gh not installed — GitHub PRs will use API fallback"
-fi
-
-# --- glab (GitLab CLI) ---
-if command -v glab &>/dev/null; then
-  ok "glab $(glab --version | head -1)"
-else
-  info "Installing glab (GitLab CLI)..."
-  case $OS in
-    macos)     brew install glab ;;
-    linux-apt) curl -s https://raw.githubusercontent.com/profclems/glab/trunk/scripts/install.sh | sudo bash ;;
-    linux-dnf) sudo dnf install -y glab ;;
-    linux-pacman) sudo pacman -S --noconfirm glab ;;
-    *) warn "Cannot auto-install glab on $OS — install from https://gitlab.com/gitlab-org/cli" ;;
-  esac
-  command -v glab &>/dev/null && ok "glab installed" || warn "glab not installed — GitLab MRs will use API fallback"
-fi
-
-warn "Gogs/Gitea: set GOGS_TOKEN or GITEA_TOKEN in your shell profile"
-echo "  export GOGS_TOKEN="your-token"  # add to ~/.zshrc or ~/.bashrc"
-echo ""
-
-# ============================================================
-# STEP 3 — GSTACK SUBMODULE
+# STEP 2 — GSTACK SUBMODULE
 # ============================================================
-echo "── Step 3: GStack submodule ─────────────────────────────────"
+echo "── Step 2: GStack submodule ─────────────────────────────────"
 echo ""
 # Note: GStack is managed as a git submodule in this repo.
 # It lives at skills-external/gstack/ and is symlinked to ~/.claude/skills/gstack/
@@ -198,10 +180,12 @@ fi
 if [ -d "$GSTACK_DIR" ]; then
   info "Running GStack setup..."
   cd "$GSTACK_DIR" && ./setup && cd - > /dev/null
-  # Ensure symlink from link.sh is in place
-  mkdir -p "$HOME/.claude/skills"
-  ln -sf "$GSTACK_DIR" "$HOME/.claude/skills/gstack" 2>/dev/null || true
-  ok "GStack ready at ~/.claude/skills/gstack (→ submodule)"
+  # Symlinks are handled by link.sh — verify it was run
+  if [ -L "$HOME/.claude/skills/gstack" ]; then
+    ok "GStack ready (submodule initialized, symlink OK)"
+  else
+    warn "GStack submodule ready but not symlinked — run: bash link.sh"
+  fi
 else
   warn "GStack submodule directory not found after init — check .gitmodules"
 fi
@@ -211,13 +195,19 @@ echo ""
 # ============================================================
 # STEP 3 — RTK
 # ============================================================
-echo "── Step 4: RTK — Rust Token Killer ─────────────────────────"
+echo "── Step 3: RTK — Rust Token Killer ─────────────────────────"
 echo ""
 if command -v rtk &>/dev/null; then
   ok "rtk already installed ($(rtk --version 2>/dev/null | head -1))"
 else
-  info "Installing RTK..."
-  cargo install --git https://github.com/rtk-ai/rtk
+  RTK_VER=$(pinned_version "rtk")
+  if [ "$RTK_VER" != "latest" ]; then
+    info "Installing RTK $RTK_VER (pinned in plugins.lock.json)..."
+    cargo install --git https://github.com/rtk-ai/rtk --tag "$RTK_VER"
+  else
+    info "Installing RTK (latest — consider pinning in plugins.lock.json)..."
+    cargo install --git https://github.com/rtk-ai/rtk
+  fi
 fi
 info "Configuring RTK PreToolUse hook (global)..."
 rtk init -g --auto-patch
@@ -227,10 +217,17 @@ echo ""
 # ============================================================
 # STEP 4 — GSD
 # ============================================================
-echo "── Step 5: GSD — get-shit-done ─────────────────────────────"
+echo "── Step 4: GSD — get-shit-done ─────────────────────────────"
 echo ""
 info "Installing GSD globally..."
-npx get-shit-done-cc --claude --global --auto
+GSD_VER=$(pinned_version "gsd")
+if [ "$GSD_VER" != "latest" ]; then
+  info "Version $GSD_VER (pinned in plugins.lock.json)"
+  npx "get-shit-done-cc@$GSD_VER" --claude --global --auto
+else
+  info "Version: latest (consider pinning in plugins.lock.json)"
+  npx get-shit-done-cc --claude --global --auto
+fi
 ok "GSD installed"
 echo ""
 
@@ -239,7 +236,7 @@ echo ""
 # ============================================================
 # All claude plugin install commands use --scope user to ensure
 # they install to ~/.claude/plugins/ regardless of working directory.
-echo "── Step 6: Marketplace plugins (scope: user) ────────────────"
+echo "── Step 5: Marketplace plugins (scope: user) ────────────────"
 echo ""
 
 install_plugin() {
@@ -276,7 +273,7 @@ echo ""
 # ============================================================
 # STEP 6 — CONTEXT7 MCP (manual — requires API key)
 # ============================================================
-echo "── Step 7: Context7 MCP ─────────────────────────────────────"
+echo "── Step 6: Context7 MCP ─────────────────────────────────────"
 echo ""
 if claude mcp list 2>/dev/null | grep -q "context7"; then
   ok "Context7 MCP already configured"
@@ -316,7 +313,6 @@ echo ""
 echo "  All plugins installed at: user scope (~/.claude/plugins/)"
 echo "  GStack at: ~/.claude/skills/gstack/ (symlink → submodule)"
 echo ""
-echo "  → Authenticate: gh auth login (GitHub) / glab auth login (GitLab)"
 echo "  → Restart Claude Code"
 echo "  → Run /reload-plugins"
 echo ""

+ 64 - 0
lib/detect-plugins.sh

@@ -0,0 +1,64 @@
+#!/usr/bin/env bash
+# ============================================================
+# lib/detect-plugins.sh — Single source of truth for plugin detection
+# Sourced by: session-start.sh, doctor.sh, install-plugins.sh
+#
+# Each function returns 0 (detected) or 1 (not detected).
+# No output — callers handle messaging.
+# ============================================================
+
+# --- Always-on plugins ---
+
+detect_rtk() {
+  command -v rtk &>/dev/null
+}
+
+detect_superpowers() {
+  # Fast check: filesystem (plugin cache)
+  local cache_dir="$HOME/.claude/plugins/cache"
+  if [ -d "$cache_dir" ]; then
+    ls "$cache_dir" 2>/dev/null | grep -qi "superpowers" && return 0
+  fi
+  # Slow fallback: CLI (only if fast check fails)
+  claude plugin list 2>/dev/null | grep -qi "superpowers" && return 0
+  return 1
+}
+
+detect_security_guidance() {
+  local cache_dir="$HOME/.claude/plugins/cache"
+  [ -d "$cache_dir" ] && ls "$cache_dir" 2>/dev/null | grep -qi "security-guidance"
+}
+
+detect_skill_creator() {
+  local cache_dir="$HOME/.claude/plugins/cache"
+  [ -d "$cache_dir" ] && ls "$cache_dir" 2>/dev/null | grep -qi "skill-creator"
+}
+
+detect_pr_review_toolkit() {
+  local cache_dir="$HOME/.claude/plugins/cache"
+  [ -d "$cache_dir" ] && ls "$cache_dir" 2>/dev/null | grep -qi "pr-review-toolkit"
+}
+
+# --- Toggle plugins ---
+
+detect_gstack() {
+  [ -d "$HOME/.claude/skills/gstack" ]
+}
+
+detect_gsd() {
+  ls "$HOME/.claude/skills/" 2>/dev/null | grep -qi "gsd"
+}
+
+detect_frontend_design() {
+  local cache_dir="$HOME/.claude/plugins/cache"
+  [ -d "$cache_dir" ] && ls "$cache_dir" 2>/dev/null | grep -qi "frontend-design"
+}
+
+detect_uiux_pro_max() {
+  local cache_dir="$HOME/.claude/plugins/cache"
+  [ -d "$cache_dir" ] && ls "$cache_dir" 2>/dev/null | grep -qi "ui-ux-pro-max"
+}
+
+detect_context7() {
+  claude mcp list 2>/dev/null | grep -q "context7"
+}

+ 18 - 6
link.sh

@@ -9,21 +9,33 @@ CLAUDE="$HOME/.claude"
 
 mkdir -p "$CLAUDE"
 
-# Core config files
+# Core config files (plain files — ln -sf handles these correctly)
 ln -sf "$REPO/CLAUDE.md"      "$CLAUDE/CLAUDE.md"
 ln -sf "$REPO/settings.json"  "$CLAUDE/settings.json"
 
-# Agents and skills
-ln -sf "$REPO/agents"  "$CLAUDE/agents"
-ln -sf "$REPO/skills"  "$CLAUDE/skills"
+# Agents and skills — must handle the case where target exists
+# as a real directory (ln -sf would create a link INSIDE the dir
+# instead of replacing it)
+for item in agents skills lib; do
+  target="$CLAUDE/$item"
+  if [ -L "$target" ]; then
+    # Stale symlink from a previous run — remove before recreating
+    rm -f "$target"
+  elif [ -d "$target" ]; then
+    echo "⚠️  ~/.claude/$item is a real directory (not a symlink)."
+    echo "   Rename or remove it, then re-run link.sh."
+    echo "   Skipping $item to avoid data loss."
+    continue
+  fi
+  ln -sf "$REPO/$item" "$target"
+done
 
 # Hooks
 mkdir -p "$CLAUDE/hooks"
 ln -sf "$REPO/hooks/session-start.sh" "$CLAUDE/hooks/session-start.sh"
 
-# GStack (submodule) — symlink from skills-external/ into ~/.claude/skills/
+# GStack (submodule) — symlink into ~/.claude/skills/ (which points to repo/skills/)
 # The submodule must be initialized first (done by install-plugins.sh)
-mkdir -p "$CLAUDE/skills"
 if [ -d "$REPO/skills-external/gstack" ]; then
   ln -sf "$REPO/skills-external/gstack" "$CLAUDE/skills/gstack"
   echo "✅ GStack symlinked from submodule"

+ 24 - 0
plugins.lock.json

@@ -0,0 +1,24 @@
+{
+  "_readme": "Pinned versions for reproducible installs. Update versions deliberately, then run install-plugins.sh.",
+  "rtk": {
+    "source": "https://github.com/rtk-ai/rtk",
+    "install_cmd": "cargo install --git https://github.com/rtk-ai/rtk --tag {version}",
+    "version": "v0.34.3",
+    "note": "Check latest at https://github.com/rtk-ai/rtk/releases before updating"
+  },
+  "gsd": {
+    "source": "npm:get-shit-done-cc",
+    "install_cmd": "npx get-shit-done-cc@{version} --claude --global --auto",
+    "version": "1.30.0",
+    "note": "Check latest at https://www.npmjs.com/package/get-shit-done-cc before updating"
+  },
+  "gstack": {
+    "source": "https://github.com/garrytan/gstack.git",
+    "managed_by": "git submodule",
+    "note": "Version controlled by submodule pointer in .gitmodules. Update: git submodule update --remote"
+  },
+  "node": {
+    "minimum": "18",
+    "recommended": "22"
+  }
+}

+ 35 - 5
settings.json

@@ -1,5 +1,5 @@
 {
-  "_readme": "Global user settings \u2014 place at ~/.claude/settings.json. Applies to ALL projects. Never commit this file.",
+  "_readme": "Global user settings  place at ~/.claude/settings.json. Applies to ALL projects. Never commit this file.",
   "cleanupPeriodDays": 30,
   "permissions": {
     "defaultMode": "default",
@@ -53,7 +53,35 @@
       "Write(**/.env.*)",
       "Write(**/secrets/**)",
       "Write(**/*.pem)",
-      "Write(**/*.key)"
+      "Write(**/*.key)",
+      "Bash(bash -c *)",
+      "Bash(eval *)",
+      "Bash(exec *)",
+      "Bash(find * -delete*)",
+      "Bash(find * -exec rm*)",
+      "Bash(find * -execdir rm*)",
+      "Bash(perl -e *)",
+      "Bash(ruby -e *)",
+      "Bash(cat .env)",
+      "Bash(cat .env.*)",
+      "Bash(cat */.env)",
+      "Bash(cat */.env.*)",
+      "Bash(cat */secrets/*)",
+      "Bash(cat */*.pem)",
+      "Bash(cat */*.key)",
+      "Bash(cat */id_rsa*)",
+      "Bash(cat */id_ed25519*)",
+      "Bash(cat */.aws/credentials)",
+      "Bash(head .env)",
+      "Bash(head .env.*)",
+      "Bash(tail .env)",
+      "Bash(tail .env.*)",
+      "Bash(less .env)",
+      "Bash(less .env.*)",
+      "Bash(more .env)",
+      "Bash(more .env.*)",
+      "Bash(grep * .env)",
+      "Bash(grep * .env.*)"
     ],
     "ask": [
       "Bash(git push *)",
@@ -68,7 +96,10 @@
       "Bash(dnf install *)",
       "Bash(pacman -S *)",
       "WebSearch",
-      "WebFetch"
+      "WebFetch",
+      "Bash(xargs *)",
+      "Bash(sed -i *)",
+      "Bash(sed -i'' *)"
     ],
     "allow": [
       "Bash(git status)",
@@ -112,7 +143,6 @@
       "Bash(awk *)",
       "Bash(sort *)",
       "Bash(uniq *)",
-      "Bash(xargs *)",
       "Bash(tr *)",
       "Bash(cut *)",
       "Bash(diff *)",
@@ -144,4 +174,4 @@
       }
     ]
   }
-}
+}

+ 3 - 1
skills/analyze/SKILL.md

@@ -1,7 +1,9 @@
 ---
 name: analyze
-description: Analyze code or a codebase deeply before any modification
+description: Deep factual code analysis — read-only, no solutions proposed
 argument-hint: <code, file, or area to analyze>
+disable-model-invocation: true
+allowed-tools: Read, Grep, Glob, Bash
 ---
 
 Load and follow strictly:

+ 0 - 15
skills/git-pr/SKILL.md

@@ -1,15 +0,0 @@
----
-name: git-pr
-description: Analyze all changes on the current branch since it diverged from base (retroactive across sessions), create logical commits, push, and open a draft PR/MR. Works with GitHub, GitLab, Gogs, and Gitea. Never merges — creates a draft for user validation.
-argument-hint: [PR title or leave empty for auto-detection]
-disable-model-invocation: true
-allowed-tools: Read, Bash, Grep, Glob
----
-
-Load and follow strictly:
-- .claude/agents/git-workflow.md
-
-Execute the GIT WORKFLOW on the current repository.
-
-User context (optional title or instructions):
-$ARGUMENTS

+ 18 - 0
skills/health/SKILL.md

@@ -0,0 +1,18 @@
+---
+name: health
+description: Run setup diagnostic — check symlinks, plugins, permissions, token budget
+argument-hint: (no arguments needed)
+disable-model-invocation: true
+allowed-tools: Bash
+---
+
+Run the health check script and report findings to the user:
+
+```bash
+bash ~/.claude/doctor.sh
+```
+
+After displaying the output:
+- If errors are found, suggest the specific fix commands shown in the output.
+- If only warnings, note them but confirm the setup is functional.
+- If all checks pass, confirm the setup is healthy.

+ 4 - 40
skills/init-project/SKILL.md

@@ -1,6 +1,6 @@
 ---
 name: init-project
-description: Initialize a complete project from scratch. Plugin check → interview → analyze → design → validate → scaffold skeleton → plan v1 features → validate plan → implement (TDD, subagents) → analyze → review → finish. Same implementation rigor as ship-feature.
+description: Full project init: interview → design → scaffold → implement (TDD). Two validation gates.
 argument-hint: <project idea or description>
 disable-model-invocation: true
 allowed-tools: Read, Write, Edit, Bash, Grep, Glob
@@ -35,42 +35,7 @@ $ARGUMENTS
 
 ---
 
-### STEP 0a — BRANCH SETUP
-
-Load the BRANCH SETUP section from: `.claude/agents/git-workflow.md`
-
-Before anything else, ensure we are NOT on a protected branch.
-
-```bash
-git branch --show-current
-```
-
-**If on `main`, `master`, `develop`, or any protected branch:**
-
-Derive a branch slug from the initial request:
-- Take the first 3–4 meaningful words
-- Lowercase, hyphen-separated
-- Max 50 chars
-
-```bash
-git fetch origin
-git pull origin <current> --ff-only 2>/dev/null || true
-git checkout -b feature/<project-slug>
-```
-
-Print: `✅ Working branch created: feature/<project-slug>`
-
-**If already on a feature branch:**
-Run the CONFLICT-SAFE REBASE procedure from git-workflow.md
-to sync with main before starting.
-
-Print: `✅ Branch: <current> (synced with main)`
-
-**Do not proceed until the branch is clean and ready.**
-
----
-
-### STEP 0b — PLUGIN CHECK
+### STEP 0 — PLUGIN CHECK
 
 Load and follow: `.claude/agents/plugin-advisor.md`
 
@@ -88,7 +53,7 @@ B) Type "force" to proceed without them
 ================================================================
 ```
 **STOP. Wait for user response.**
-- Re-run → restart from STEP 0b
+- Re-run → restart from STEP 0
 - "force" → note missing plugins, continue to STEP 1
 
 **If `ACTION REQUIRED: NO`:**
@@ -341,8 +306,7 @@ SYNC mode — no stop required. The readme-updater:
 
 ## RULES
 
-- Never skip STEP 0a — branch setup is mandatory. Never commit on main/master.
-- Never skip STEP 0b — plugin check is mandatory.
+- Never skip STEP 0 — plugin check is mandatory.
 - Never skip STEP 1 — no assumptions about missing info.
 - Never implement without explicit user approval at STEP 4.
 - Never implement without explicit user approval at STEP 7.

+ 1 - 1
skills/plugin-check/SKILL.md

@@ -1,6 +1,6 @@
 ---
 name: plugin-check
-description: Check active plugins vs current project needs. Recommends enabling or disabling based on context signals (frontend, design, QA, deployment, multi-session, fast-evolving libs). Run before init-project or ship-feature on a new project type.
+description: Audit active plugins vs project needs. Recommends enable/disable actions.
 argument-hint: [project description or feature to build]
 disable-model-invocation: true
 allowed-tools: Read, Bash, Glob, Grep

+ 1 - 1
skills/readme/SKILL.md

@@ -1,6 +1,6 @@
 ---
 name: readme
-description: Update the project README to reflect the current state of the codebase. Audits what is outdated, missing, or no longer accurate, then applies surgical updates. Preserves existing structure and style.
+description: README audit — detect outdated sections, apply surgical updates
 argument-hint: [what changed, feature name, or leave empty for full audit]
 disable-model-invocation: true
 allowed-tools: Read, Write, Edit, Bash, Glob, Grep

+ 3 - 1
skills/refactor/SKILL.md

@@ -1,7 +1,9 @@
 ---
 name: refactor
-description: Improve code quality without changing behavior
+description: Improve code quality without changing behavior — strict norm enforcement
 argument-hint: <file, function, or module to refactor>
+disable-model-invocation: true
+allowed-tools: Read, Write, Edit, Grep, Glob, Bash
 ---
 
 Load and follow strictly:

+ 4 - 76
skills/ship-feature/SKILL.md

@@ -1,6 +1,6 @@
 ---
 name: ship-feature
-description: Ship a feature end-to-end using the Superpowers workflow. Starts with a plugin check, then Brainstorm → Plan → Implement (subagent-driven) → Review → Finish branch.
+description: Ship feature end-to-end: design → plan → implement (TDD) → review → finish
 argument-hint: <feature description>
 disable-model-invocation: true
 allowed-tools: Read, Write, Edit, Bash, Grep, Glob
@@ -33,48 +33,7 @@ $ARGUMENTS
 
 ---
 
-### STEP 0a — BRANCH SETUP
-
-Load the BRANCH SETUP section from: `.claude/agents/git-workflow.md`
-
-```bash
-git branch --show-current
-```
-
-**If on `main`, `master`, `develop`, or any protected branch:**
-
-Derive a branch slug from the feature request:
-- Take the first 3–4 meaningful words from $ARGUMENTS
-- Lowercase, hyphen-separated, max 50 chars
-- Prefix with `feature/`
-
-```bash
-git fetch origin
-git pull origin <current> --ff-only 2>/dev/null || true
-git checkout -b feature/<feature-slug>
-```
-
-Print: `✅ Working branch created: feature/<feature-slug>`
-
-**If already on a feature/bugfix/hotfix branch:**
-Run the CONFLICT-SAFE REBASE procedure from git-workflow.md
-to sync with the base branch before implementing.
-
-Print: `✅ Branch: <current> (synced)`
-
-**Special case — bugfix on a feature branch:**
-If the user explicitly says "bugfix" or "fix" in the request AND
-the current branch is a feature branch:
-```bash
-git checkout -b bugfix/<bug-slug>
-```
-Creates the bugfix branch FROM the feature branch — correct hierarchy.
-
-**Do not proceed until the branch is clean.**
-
----
-
-### STEP 0b — PLUGIN CHECK (mandatory gate)
+### STEP 0 — PLUGIN CHECK (mandatory gate)
 
 Load and follow: `.claude/agents/plugin-advisor.md`
 
@@ -105,7 +64,7 @@ Options:
 ```
 
 Wait for user response.
-- If user re-runs `/ship-feature` → start from STEP 0a again
+- If user re-runs `/ship-feature` → start from STEP 0 again
 - If user types "force" → note missing plugins and continue to STEP 1
 
 **If the advisor output says `ACTION REQUIRED: NO`:**
@@ -198,40 +157,9 @@ SYNC mode — no stop required. The readme-updater:
 
 ---
 
-### STEP 9 — CREATE PR (optional gate)
-
-Ask the user:
-```
-================================================================
-SHIP FEATURE — PR CREATION
-================================================================
-Feature is implemented, tested, and README is synced.
-
-Create a PR/MR now?
-  yes    → run /git-pr and open a draft PR
-  no     → stop here, you can run /git-pr manually later
-================================================================
-```
-
-**STOP — wait for user response.**
-
-IF yes:
-  Load and follow: `.claude/agents/git-workflow.md`
-  The git-workflow agent will:
-  - Show all changes since branch start (retroactive)
-  - Propose a commit plan for approval
-  - Push and create a draft PR/MR on GitHub/GitLab/Gogs/Gitea
-
-IF no:
-  Print: `✅ Feature shipped. Run /git-pr when ready to open a PR.`
-  Stop.
-
----
-
 ## RULES
 
-- Never skip STEP 0a — branch setup is mandatory. Never implement on main/master.
-- Never skip STEP 0b — plugin check is mandatory.
+- Never skip STEP 0 — plugin check is mandatory.
 - Never skip brainstorming.
 - Never implement without explicit user approval of the plan.
 - Keep subagents isolated — no shared context between tasks.

+ 78 - 0
update-all.sh

@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+# ============================================================
+# Claude Code — Update all components
+# Pulls latest config, updates submodules, refreshes symlinks,
+# and runs doctor to verify.
+# ============================================================
+set -euo pipefail
+
+RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
+ok()   { echo -e "${GREEN}✓${NC} $1"; }
+warn() { echo -e "${YELLOW}⚠${NC}  $1"; }
+info() { echo -e "${BLUE}→${NC} $1"; }
+
+REPO="$(cd "$(dirname "$0")" && pwd)"
+VERSION=$(cat "$REPO/version.txt" 2>/dev/null || echo "unknown")
+
+echo ""
+echo "═══ claude-config update (v${VERSION}) ═══"
+echo ""
+
+# ── 1. Pull latest config ──
+echo "── Pulling latest config..."
+cd "$REPO"
+if git pull --rebase 2>/dev/null; then
+  ok "Config repo updated"
+else
+  warn "git pull failed — check for uncommitted changes"
+fi
+
+# ── 2. Update GStack submodule ──
+echo ""
+echo "── Updating GStack submodule..."
+if git submodule update --remote skills-external/gstack 2>/dev/null; then
+  if [ -d "skills-external/gstack" ]; then
+    cd skills-external/gstack && ./setup 2>/dev/null && cd "$REPO"
+    ok "GStack updated"
+  fi
+else
+  warn "GStack submodule update failed — run: git submodule update --init"
+fi
+
+# ── 3. Update RTK (if pinned version available) ──
+echo ""
+echo "── Updating RTK..."
+if command -v cargo &>/dev/null; then
+  RTK_VERSION=""
+  if [ -f "$REPO/plugins.lock.json" ] && command -v python3 &>/dev/null; then
+    RTK_VERSION=$(python3 -c "
+import json
+with open('$REPO/plugins.lock.json') as f:
+    d = json.load(f)
+print(d.get('rtk',{}).get('version',''))
+" 2>/dev/null || true)
+  fi
+
+  if [ -n "$RTK_VERSION" ] && [ "$RTK_VERSION" != "latest" ]; then
+    info "Pinned version: $RTK_VERSION"
+    cargo install --git https://github.com/rtk-ai/rtk --tag "$RTK_VERSION" --force 2>/dev/null \
+      && ok "RTK updated to $RTK_VERSION" \
+      || warn "RTK update failed"
+  else
+    info "No pinned version — installing latest"
+    cargo install --git https://github.com/rtk-ai/rtk --force 2>/dev/null \
+      && ok "RTK updated (latest)" \
+      || warn "RTK update failed"
+  fi
+else
+  warn "Cargo not available — skipping RTK"
+fi
+
+# ── 4. Refresh symlinks ──
+echo ""
+echo "── Refreshing symlinks..."
+bash "$REPO/link.sh"
+
+# ── 5. Run doctor ──
+echo ""
+bash "$REPO/doctor.sh"

+ 1 - 0
version.txt

@@ -0,0 +1 @@
+1.0.0