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>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
2e6725e8bb
commit
131d0bcb5d
+2
-2
@@ -75,7 +75,7 @@ Exit codes: `0` = ready (proceed) · `10` = incomplete (gate trips) · `2` = err
|
||||
- **required + manual step** → required tools the profile can't flip silently.
|
||||
**magic lands here: it TRIPS the gate** (it's required for Build), it is NOT
|
||||
a silent "optional". `/profile design` runs `toggle-external.sh` for magic,
|
||||
which needs a valid `MAGIC_API_KEY` in `.env` — tell the user to verify it.
|
||||
which needs a valid `MAGIC_API_KEY` in `~/.claude/.env` — tell the user to verify it.
|
||||
- Do NOT hand-activate individual tools. The profile is the unit of activation.
|
||||
- **`unverified` line** (claude CLI absent) → the state of a plugin/mcp couldn't
|
||||
be checked; it does not block. Mention it, proceed.
|
||||
@@ -92,7 +92,7 @@ remedy is always `/profile <that>` — a profile, never a lone tool.
|
||||
- Remedy is ALWAYS a profile (`/profile design`), never an atomic tool toggle —
|
||||
the profile system is the single source of truth for what's active.
|
||||
- magic is REQUIRED (it trips the gate), but `/profile design` only enables it
|
||||
if `MAGIC_API_KEY` is in `.env` — the gate says so; surface that to the user.
|
||||
if `MAGIC_API_KEY` is in `~/.claude/.env` — the gate says so; surface that to the user.
|
||||
- The design-core set (what trips the gate) is declared in `design.profile` on
|
||||
the `# GATE-BLOCK:` line(s) — edit there to add/remove a blocking design tool,
|
||||
not in the script.
|
||||
|
||||
@@ -131,7 +131,7 @@ fi
|
||||
if [ "${#manual[@]}" -gt 0 ]; then
|
||||
echo " required + manual step (API key / external install): ${manual[*]}"
|
||||
case " ${manual[*]} " in
|
||||
*" magic "*) echo " magic needs MAGIC_API_KEY in .env (/profile $PROFILE runs toggle-external.sh)" ;;
|
||||
*" magic "*) echo " magic needs MAGIC_API_KEY in ~/.claude/.env (/profile $PROFILE runs toggle-external.sh)" ;;
|
||||
esac
|
||||
fi
|
||||
if [ "${#unverified[@]}" -gt 0 ]; then
|
||||
|
||||
@@ -181,7 +181,7 @@ enable_tool() {
|
||||
magic)
|
||||
load_env
|
||||
if [ -z "${MAGIC_API_KEY:-}" ]; then
|
||||
err "MAGIC_API_KEY not set — add it to $REPO/.env (template: .env.example)"
|
||||
err "MAGIC_API_KEY not set — add it to ~/.claude/.env (template: .env.example)"
|
||||
return 1
|
||||
fi
|
||||
if [ "$(status_tool magic)" = "enabled" ]; then
|
||||
|
||||
Reference in New Issue
Block a user