Commit Graph

6 Commits

Author SHA1 Message Date
Bastien Chanot
131d0bcb5d feat(secrets): .env source-of-truth in ~/.claude + repo symlink
Move the real secret out of the git tree: the key lives in ~/.claude/.env
(outside the repo), and link.sh symlinks repo/.env -> ~/.claude/.env so
`source "$REPO/.env"` resolves transparently. The secret never enters git —
not as content (it's a link) and not by accident (gitignored).

link.sh: add link_env() — verify ~/.claude/.env exists + has MAGIC_API_KEY
(warn, never create/copy the secret), then create repo/.env -> ~/.claude/.env.
Defensive + idempotent: links only when repo/.env is absent or already the
right symlink; a residual REAL repo/.env is left untouched with a migrate hint
(never clobbered, so the secret can't be destroyed).

.gitignore: harden .env -> .env + .env.* + !.env.example (covers .env.local,
.env.bak, .env.save; keeps the template tracked).

Messages point at ~/.claude/.env (the canonical edit location) instead of the
ambiguous $REPO/.env: design-tool-gate.sh gate output, design-gate.md
(branch 3 + IMPORTANT), toggle-external.sh, install-plugins.sh.

Verified: shellcheck clean (link.sh, toggle-external.sh, design-tool-gate.sh);
link.sh created the symlink (1 change, idempotent re-run); repo/.env absent
from git status; magic-off path still exits 10 with the ~/.claude/.env hint.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 11:44:47 +02:00
bastien
4535cce700 fix(toggle-external): handle source-only state in enable
`enable <tool>` for npx/external skills (darwin-skill, find-skills,
emil-design-eng) only handled two states: symlink in skills-disabled/
(move) and symlink in skills/ (already enabled). Missed the state
right after `make plugin` where the source dir exists at
~/.agents/skills/<tool> but no symlink has been created yet — first
run errored "not installed — run: make plugin" misleadingly.

Add a third branch: when the resolved source dir exists, create the
symlink in place. Resolve source path per tool (skills-external for
emil-design-eng, ~/.agents/skills for darwin-skill/find-skills). Error
message now names the path checked so the caller can verify install
vs symlink state without rereading the script.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-06 17:09:21 +02:00
bastien
239d91db67 feat(profile): partition skills/plugins/MCPs/CLIs by usage profile
Ship lib/profile.sh + 9 profiles in lib/profiles/. A profile is a
plain-text file listing items + types (gstack | personal | external |
plugin@<marketplace> | mcp | cli). `profile set <name>` enables the
listed items and disables the rest:

  - gstack/personal/external skills: symlink toggle skills/ ↔
    skills-disabled/ (gstack__<name> prefix to avoid collisions; no
    prefix for personal/external).
  - plugins typed `plugin@<marketplace>`: actually toggled via
    `claude plugin enable|disable <name>@<marketplace>`. Allowlist:
    MANAGED_PLUGINS = ui-ux-pro-max, plugin-dev, pr-review-toolkit.
    Denylist: PROTECTED_PLUGINS = caveman, security-guidance,
    superpowers (always-on, never disabled even if absent from a
    profile).
  - mcp magic: delegated to lib/toggle-external.sh which already
    handles the MAGIC_API_KEY env lookup. Other MCPs stay advisory.
  - cli (rtk, gsd, ctx7, graphify): status-only, never auto-installed.

Profiles shipped:
  web        public website work — frontend + content + light dev
  seo        SEO + GEO + W3C audit (search/AI indexability + a11y)
  web-full   production website end-to-end (web ∪ seo ∪ qa-only/canary)
  backend    backend / API / system dev — no design, no SEO
  design     visual QA, design systems, mockups, polish
  dev        daily code work — features, fixes, refactor, ship
  qa         site testing, perf, canary, validation
  audit      comprehensive audit — security + SEO + perf + health
  minimal    strip all gstack skills (quiet session)

Commands:
  profile list / show <name> / current / apply <name> / set <name> /
  reset / diff <a> <b>

`current` heuristic returns "full" when nothing is disabled, otherwise
picks the profile with the highest available-ratio (counts both
"enabled" and "installed" — the latter for CLIs). Tiebreaker: larger
profile total wins, so web-full beats web at a 100% tie.

`reset` re-enables every gstack skill but does NOT touch plugins —
the user re-enables a managed plugin manually or via `apply <profile>`.
This is documented in the trailing info line.

Integration:
  - skills/profile/SKILL.md — `/profile` slash command, lists profiles,
    documents the per-type mechanism, points at lib/profile.sh.
  - agents/plugin-advisor.md — DETECT phase calls `profile current`,
    OUTPUT adds a PROFILE line, and TOGGLING EXTERNAL TOOLS gains a
    "Skill profiles" section with a signal → profile recommendation
    table.
  - lib/toggle-external.sh — header pointer to profile.sh for fine-
    grained activation (toggle-external still owns whole-gstack and
    magic-MCP toggles).
  - Makefile — `make profile cmd="set <name>"`, profile-list,
    profile-current, profile-reset.

Tested end-to-end: `set web` enables ui-ux-pro-max + magic; `set seo`
disables ui-ux-pro-max; `set minimal` disables ui-ux-pro-max but
spares always-on plugins; `reset` restores all 64 skills; shellcheck
clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 02:09:28 +02:00
bastien
72920e032e feat(toggle-external): manage Magic MCP (21st-dev) — installed disabled by default
Add `magic` to the unified toggle-external.sh helper alongside gstack,
emil-design-eng, darwin-skill, find-skills. MCPs are toggled via
`claude mcp add|remove` instead of symlink moves.

API key loaded from $REPO/.env (gitignored) via .env.example template.
install-plugins.sh step 8.7 forces magic MCP off after each install run
so the MCP doesn't load into every session unless explicitly enabled.

Toggle: bash lib/toggle-external.sh enable|disable|status magic

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 20:28:03 +02:00
bastien
a446a428a7 fix(toggle-external): idempotent enable/disable — clobber stale destination before mv
gstack ./setup now creates skills/<name>/ as directories (with a SKILL.md
symlink inside) rather than top-level symlinks. A second disable call used
to nest the new dir inside the existing one (gstack__<name>/<name>/),
producing "mv: cannot overwrite … Directory not empty" on the third call
and breaking `make install` under set -euo pipefail.

rm -rf the destination first — contents are symlinks into the submodule
and are regenerated by gstack ./setup, so clobbering is safe.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-21 17:05:50 +02:00
bastien
ec14261c82 feat(toggle): enable/disable non-marketplace tools via lib/toggle-external.sh
`claude plugin enable|disable` only toggles marketplace plugins.
Tools living as symlinks (gstack per-skill entries, emil-design-eng,
darwin-skill, find-skills) had no lever — users had to edit symlinks
by hand. The new script moves symlinks in/out of skills-disabled/
so Claude Code stops or starts scanning them.

Also removes the legacy global `skills/gstack` symlink that shadowed
per-skill entries with a duplicate top-level "gstack" skill (same
description as "browse"). gstack detection in detect-plugins.sh now
probes an individual skill instead.

plugin-advisor reads the new script's `list` command when gathering
state and emits its `enable|disable` commands in recommendations.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-21 13:50:40 +02:00