observability-and-instrumentation, deprecation-and-migration,
ci-cd-and-automation from addyosmani/agent-skills 2686b620, curl'd into
skills-external/<name>/ by install-plugins.sh Step 8e (tmp+mv), refreshed
by update-all.sh 7.3, symlinked by link.sh, registered in toggle-external,
profile.sh and the full/backend/dev profiles. Pin read from the lock via
argv, never hardcoded. Case 2 of the 6-repo review, BDR-102.
`profile.sh apply full` linked skills/diagram (added to full today) and it
showed as untracked: the per-skill allowlist never listed it (LRN-025
class). One literal line, alphabetical slot; the full.profile census now
finds every bare gstack entry ignored.
settings.json: the user's hand-edit (feedbackDrafts: off) committed as is. .gitignore: skills/synced/ and its .bucket-* marker are Claude Code's mirror of the claude.ai synced skills (UUID bucket, manifest.json, Anthropic stock skills incl. 117 ISO xsd schemas), rewritten at each sync — same treatment as the graphify and impeccable machine-owned copies (BDR-028, LRN-154).
make plugin never installed impeccable. The 3.2.0 pin had rotted upstream
(the CLI fetches its skill dist at install time; that release's zip is
gone), the --scope=project staging moved the skill dir alone and dropped
the 4 impeccable-* subagents, and /impeccable init was never announced.
Step 8d now installs at --scope=global straight through the
~/.claude/{skills,agents} symlinks into the repo (both paths gitignored),
guards on those symlinks existing, keeps a profile-parked copy parked,
falls back to @latest on a pin failure with a bump-the-lock warning, and
prints the per-project init hint. update-all.sh mirrors the shape.
Found while probing: with a copy already installed a rotted pin exits 0
("Could not check for skill updates ... left unchanged"), byte-identical
on disk to an up-to-date rerun, so imp_install reads the installer output
instead of trusting the exit code. Harness 4/4 in a sandbox HOME with the
real installer.
plugins.lock.json: impeccable 3.2.0 -> 4.1.0 (CLI only). link.sh drops
impeccable from EXTERNAL_SKILLS. lib/design-gate.md section 5: suggest-only
/impeccable init check when a frontend project has no PRODUCT.md.
Upstream supersedes `@21st-dev/magic` with `@21st-dev/cli` (bin `21st`):
same endpoint, `21st login` in place of an API key, no MCP process loaded
into every session.
- install-plugins.sh Step 8.7: `npm i -g @21st-dev/cli` (pinned in
plugins.lock.json), staged `21st skills install`, TTY-only login offer,
pack disabled by default. update-all.sh 7.4 refreshes both.
- The documented `21st install-skill` cannot be used: the installer refuses
to follow a symlink on the target path and `~/.claude/skills` is one. The
install runs under a throwaway HOME and the result moves into
skills-external/21st-* (gitignored), symlinked on demand.
- toggle-external.sh manages `21st` as a pack (names globbed from
skills-external/21st-*, parked under plain names). `magic` is gone.
- The 5 design skills join design/web/web-full/full and MANAGED_EXTERNALS;
21st-registry and 21st-design-sync stay parked. MANAGED_MCPS is now empty
and profile.sh's dead magic branches are removed.
- Design gate: GATE-BLOCK gains `21st` (required-manual, magic's old slot)
and `21st-ui-build`; PATH repair extended to the npm global bin.
- settings.json: the 4 mcp__magic__* ask entries go; the outward-facing
21st verbs land in autoMode.soft_deny, the tier that holds under auto
mode (LRN-153).
- Docs: README, CLAUDE.global.md, design-gate.md, profile SKILL.md,
.env.example, .gitleaks.toml, link.sh. BDR-093, LRN-158.
Tests: profile-set-managed 17/17, make test green except 2 pre-existing
gitflow FAILs (gitleaks binary absent on this host), shellcheck clean.
graphify: `graphify claude install` (install-plugins.sh STEP graphify)
writes SKILL.md, references/ and .graphify_version straight into the repo,
because ~/.claude/skills is a symlink to skills/. Every `pipx upgrade
graphifyy` therefore dirtied the tree and cost a `chore(graphify): sync
vendored skill X -> Y` commit. Now gitignored and untracked; a fresh clone
gets them back from `make plugin`. test-prompts.json is hand-written for
darwin and stays tracked. The accepted trade-off, documented in CLAUDE.md,
is that an upstream release can change the skill's prompt with no diff to
review.
settings.local.json (gitignored, so not in this commit) went from 14.6 KB
to 6.2 KB. It was a near-complete shadow copy of the global settings at a
higher precedence tier, which hid its own drift until the global moved.
Two entries were actively defeating BDR-090, merged an hour earlier:
- local `deny` still carried rsync / kill -9 / killall / pkill, the four
rules deliberately moved out of global deny. deny wins across sources,
so autoMode.soft_deny was a dead letter in this repo.
- local `allow` carried `sed *`, `cp *` and `python3 -`. An allow rule
short-circuits the classifier, punching a hole through the same
soft_deny rules.
deny and ask are dropped whole (102 and 27 of their entries duplicated the
global; ask gates nothing under defaultMode auto). allow went 185 -> 98:
81 duplicates plus six policy conflicts, the three above and
Read(//home/bchanot/**), WebSearch, and a leftover command-injection test
payload that had been allowlisted verbatim. Every non-permissions key was
a verbatim copy of the global, including a hooks block whose only original
entry pointed at hooks/config-protection.sh, a script that exists nowhere.
skills-external/emil-design-eng/SKILL.md is curl'd from emilkowalski/skill
by install-plugins.sh when absent and re-fetched unconditionally by every
update-all.sh run, so tracking it produced a repo diff on each upstream edit
(latest: Radix vars dropped for Base UI). Same category as frontend-design/
and impeccable/, already ignored on that rationale — a fresh clone re-fetches
it, so no offline copy is needed and nothing was pinned here anyway.
design-motion-principles/ has the same overwrite-on-update behaviour but NOT
the same bootstrap: install-plugins.sh only warns instead of cloning it, so it
stays tracked until that gap is closed.
RC fix (soak day 1): `make update` step 7.5 failed on a 300s clone timeout
of alchaincyf/find-skills. The skill (search the skills.sh registry from
Claude) was never used; the discovery case stays reachable manually via
`npx -y skills find <query>`. Removed from install-plugins.sh (install list
+ summary + comment), update-all.sh (refresh list), link.sh
(NPX_EXTERNAL_SKILLS), lib/toggle-external.sh (MANAGED_TOOLS + case arms),
plugin-advisor.md, .gitignore; local skills/find-skills symlink deleted.
Memory-registry and test-fixture mentions kept — append-only history.
toggle-external `list` verified post-removal; suites 8/8.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XpphkdTosUzokBDNG7PToS
Complementary to frontend-design (kept: build-time aesthetic direction).
impeccable adds what the chain lacked: 45 deterministic anti-slop rules
(npx impeccable detect, exit 0/2, --json) — the design counterpart of the
semgrep gate — plus 23 design verbs under one /impeccable skill and
persistent per-project design context.
- plugins.lock.json: CLI pinned 3.2.0 (rules update = audit output change
on unchanged code, LRN-077 class); skill dist = its own release track
- install-plugins.sh Step 8d: staged npx install (tmpdir) -> moved to
skills-external/impeccable (machine-owned, gitignored, ctx7 pattern);
never writes through the ~/.claude/skills symlink into the tracked tree
- update-all.sh: pin-honored refresh, Node<24 or failure -> dist kept
- Node >= 24 required (host at 22): steps skip gracefully, activation
deferred to a deliberate Node bump
- link.sh EXTERNAL_SKILLS, profiles (design/web/web-full/full),
plugin-advisor, CLAUDE.md design routing, design-gate, README, CHANGELOG
- NOT in design GATE-BLOCK yet: promotion after first dogfood
Claude Code loads modular rule files from ~/.claude/rules/ (user scope,
recursive, markdown, optional paths: frontmatter for lazy path-scoped
loading — stable, symlink-supported). The repo had no rules/ at all, so
the ctx7 setup had created ~/.claude/rules as a REAL directory outside
version control — invisible to the repo, unreproducible on a new machine.
- rules/README.md — doctrine: one rule per file; paths:-scoped extraction
is the token win, always-on doctrine stays in CLAUDE.md
- link.sh — rules added to the symlinked-dirs loop
- .gitignore — rules/context7.md ignored (machine-owned: `ctx7 setup`
(re)writes it, same treatment as skills/find-docs/)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XpphkdTosUzokBDNG7PToS
STEP 6 ctx7 auth, when anonymous:
- interactive TTY -> prompt [y/N] then run `ctx7 login`; non-interactive
(CI/headless/re-run) keeps text guidance, never opens a browser or blocks.
- run `ctx7 setup --claude --cli` when the find-docs skill is absent, to
(re)install CLI+Skills mode. Guarded on absence so a re-run never clobbers
a customized ~/.claude/rules/context7.md.
gitignore skills/find-docs/: it is a ctx7-managed skill materialized by
`ctx7 setup --claude --cli` into ~/.claude/skills (symlink to repo skills/),
re-created on demand by Step 6 — not vendored here.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C8bmCXTHNccS7KRV4gWXEF
Three paths are (re)generated by every install/update and should never be
committed:
- skills-external/frontend-design/ — install-plugins.sh Step 8b and
update-all.sh cp the latest SKILL.md from the example-skills plugin cache
over it, so it churned a diff each time Anthropic shipped an update. The
source is always re-synced (example-skills is always installed), so no
vendored copy is needed.
- .agents/ and skills-lock.json — `npx skills add` (darwin-skill) installs
at project scope into the repo. Our own agents live in agents/ (no dot)
and stay tracked; the dotted pollution dir is anchored-ignored (/.agents/).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UyNYwD4UccVw9ZCFZyJX55
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>
Wrap the frontmatter description in quotes (defensive valid-YAML: it contains an em-dash and an apostrophe). Add skills/design-motion-principles to the external-skill-symlink ignore allowlist so it matches its 4 siblings (emil-design-eng, frontend-design, darwin-skill, find-skills) and stops surfacing as untracked noise — consistent with the LRN-025 allowlist rule.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A gstack submodule bump added `spec` (v1.47) and the iOS device-farm
5-skill set (v1.43) but gstack `./setup` was never re-run, leaving all 6
as source-only — unlinked, invisible to Claude and untouched by
reset/`gstack on`.
- Link `spec` only, surgically: skills/spec/SKILL.md symlink matching
gstack setup's per-skill pattern (real dir + absolute SKILL.md link).
Platform-agnostic, useful planning skill. Added to full + web-full
profiles (must be in the active `full` profile or `set full` would
re-disable it).
- iOS skills deliberately NOT linked: this is a Linux host, and the iOS
device-farm needs a Mac daemon + Tailscale + physical iOS devices.
Linking them would add 5 dead skills plus passive token cost.
- Complete the .gitignore gstack allowlist: add the 12 entries missing
from it — `spec`, the 5 `ios-*` (so they stay ignored if a future
setup on a Mac materializes them), and 6 already-parked skills
(document-generate, landing-report, scrape, setup-gbrain, skillify,
sync-gbrain). The parked ones matter because `gstack on` moves parked
skills into skills/, where any allowlist gap becomes untracked git
noise. Also drop the stale `skills/checkpoint` entry (renamed to
context-save).
Verified: `profile show full`/`web-full` report spec enabled; the
source-vs-allowlist drift check is now empty; profile.sh still parses.
The gstack submodule pointer bump itself is left uncommitted (separate
pending work).
Memory: BLK-007 -> resolved; LRN-025 (gitignore allowlist must cover all
toggleable skills incl. parked, else enabling one = git noise).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Source: anthropic-agent-skills plugin cache → skills-external/frontend-design/
Auto-install via install-plugins.sh step 8b, auto-update via update-all.sh
step 7.1, symlinked by link.sh (refactored to loop over EXTERNAL_SKILLS).
Added to profiles: design, web, web-full, full.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
`bash lib/profile.sh current` is 12s+ — far too slow to call from the
statusline hook (runs on every keystroke). Add a one-line cache file at
`<repo>/.active-profile`, written by `cmd_apply` and `cmd_reset`. The
statusline reads the file directly with a single `head -n1`, no
sub-shell into `profile.sh`.
Behavior:
- `bash lib/profile.sh set <name>` (which ends in `cmd_apply`) and
`bash lib/profile.sh apply <name>` both write `<name>` to
`<repo>/.active-profile`.
- `bash lib/profile.sh reset` writes the literal `none`.
- Statusline inserts the cached profile name between the plan segment
and the context-bar segment, e.g.
`Opus 4.7 | claude (master) | Max | full | ████░░░░░░ 42% | 3m`.
- Missing or empty cache → statusline shows `?`.
Cache file is gitignored — it tracks runtime state, not source.
Co-Authored-By: Claude <noreply@anthropic.com>
Three bugs surfaced on the LIVRAISON.pdf test render:
1. **MD→HTML conversion** — host had no pandoc, no python-markdown, fell
back to `npx marked < "$src"`. marked CLI 16.x ignores stdin and
dumps its own cli.js source. Resulting PDF body = marked's binary
source (`#!/usr/bin/env node`, `Marked CLI`, copyright). Fix:
`npx --yes marked --gfm -i "$src"` (file path via -i, not stdin).
2. **Cover background** — original cream `#F5F0EB` + 8mm green stripe
was washed out. Iterated to white-pure bg with subtle radial
sage/forest tints, black-deep title, green-forest accents
(eyebrow, meta labels, footer, border). Solid green-dark tried
first then rejected (too heavy for long client-facing doc).
3. **Default logo** — SVG `logo-horizontal.svg` rendered cream-toned,
blended into bg. Switched LOGO_URL default to
`https://zenquality.fr/assets/logo-horizontal-1024.png`.
Also added test-artifact gitignore rules for LIVRAISON.* / HANDOVER.*
project-local renders.
Verified: regenerated LIVRAISON.pdf → 164 KB, 19 pages, full content
rendered, white cover with black title + green-forest accents +
visible PNG logo.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
/caveman:compress writes a human-readable backup as <file>.original.md
before overwriting. Backups are recoverable via git history (the
pre-compression state lives in the previous commit), so committing
them duplicates content and bloats the repo.
Globbing on *.original.md catches all compressed registries plus
CLAUDE.original.md.
Co-Authored-By: Claude <noreply@anthropic.com>
Wires JuliusBrussee/caveman into the always-on tier alongside
security-guidance and superpowers. Caveman compresses Claude's output
tokens (~75%) by speaking like a caveman while keeping technical
substance. Three layers:
1. Plugin (caveman@caveman, marketplace JuliusBrussee/caveman)
— adds /caveman, /caveman-commit, /caveman-review, /caveman-stats,
/caveman-help, /cavecrew, /compress + 3 cavecrew agents +
SessionStart/UserPromptSubmit hooks from the plugin path.
2. Standalone hooks (statusline + stats badge) deployed by
caveman's own hooks/install.sh into ~/.claude/hooks/. Paths in
settings.json normalized to ~/.claude/hooks/... so this user's
home dir doesn't leak across machines.
3. caveman-shrink MCP proxy — NOT auto-registered. The bare proxy
fails health checks because it requires an upstream MCP server
to wrap. install-plugins.sh STEP 5.5 prints a snippet showing how
to register a wrapped entry (e.g. caveman-shrink-fs) when the user
decides which upstream to compress.
New helper enable_plugin() for explicit always-on activation —
'claude plugin install' only copies into cache, doesn't write
enabledPlugins. Idempotent via Python json check.
doctor.sh adds detect_caveman / detect_caveman_hooks / detect_caveman_shrink
checks plus a 300t passive-cost adder. update-all.sh refreshes hook
files via the upstream installer's --force mode.
.gitignore covers caveman runtime files materialized into hooks/
because ~/.claude/hooks is symlinked to this repo.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previous rule (.claude/) ignored everything under .claude/, making
the new governance files invisible to git. Switches to a wildcard
pattern with explicit negations: tasks/memory/audits/settings.json
become trackable; settings.local.json and agent-memory/ stay
per-machine. Commits existing .claude/settings.json which now falls
under the tracked scope.
Verified with git check-ignore:
- .claude/memory/decisions.md → exit 1 (not ignored) ✓
- .claude/tasks/TODO.md → exit 1 (not ignored) ✓
- .claude/settings.local.json → exit 0 (ignored) ✓
- .claude/agent-memory/ → exit 0 (ignored) ✓
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
gstack 0.17.0 added 5 skills that land in skills/ via gstack ./setup
(benchmark-models, context-restore, context-save, make-pdf, plan-tune).
The older gstack skills are already ignored here — extend the list so
these don't show up as untracked after `make update`.
Co-Authored-By: Claude <noreply@anthropic.com>
`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>
`claude plugin update` rejects a bare plugin name when multiple
marketplaces are registered — the CLI demands `name@marketplace`.
update-all.sh stripped the suffix via `${_p%%@*}`, causing every
marketplace plugin update to fail with "Plugin not found". Fixed
by passing the unmodified spec from `claude plugin list`.
Also adds install + update paths for external skills distributed
through the `npx skills` CLI (vercel-labs/skills):
- alchaincyf/darwin-skill
- alchaincyf/find-skills
These land in ~/.agents/skills/ and are now symlinked into
$REPO/skills/ via link.sh using absolute paths — the previous
relative `../../.agents/...` targets resolved incorrectly when
the repo is cloned below $HOME (as ~/Documents/claude/), leaving
dangling symlinks.
Co-Authored-By: Claude <noreply@anthropic.com>
These 37 symlinks point to skills-external/gstack/ and are recreated
automatically by the gstack setup during install-plugins.sh. They
should not be versioned. Added all patterns to .gitignore.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Track all gstack-provided skill symlinks (autoplan, browse, qa, etc.)
and the graphify skill. Add .claude/, graphify-out/, .ctx7-cache/ to
gitignore to exclude local/generated files from the repo.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>