distill: best practices from 2026-04-19 cross-project run
Adds 3 new topic files (ai-parallel-agents, api-integration, python-patterns) and extends 21 existing topic files with new gotchas and patterns surfaced from memory across tracked projects. Index updated accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -65,3 +65,42 @@ Skills that review artifacts (plans, specs, designs) should be read-only — res
|
||||
## Separate Formatter Exit Codes from Hook Exit Codes
|
||||
|
||||
When integrating formatters with Claude Code hooks, keep formatter scripts and hook dispatch logic separate. Formatter scripts exit 0 (clean) or 1 (lint errors). The dispatch hook decides the final exit code semantically (e.g., exit 2 for PostToolUse feedback). This separation means the same formatter scripts work for both PostToolUse hooks and pre-commit hooks without modification.
|
||||
|
||||
## Pre-fetching Bounded Metadata vs. Unbounded Content
|
||||
|
||||
When a skill needs to examine large external artifacts (transcripts, logs, dumps), have a helper script pre-gather **metadata only** (a small JSON list: paths, sizes, headers) at skill-load time via `!`command``. Delegate the actual content extraction to a subagent invoked from the skill's instructions.
|
||||
|
||||
This keeps the main conversation's context small — the skill sees a compact index rather than megabytes of raw content — and lets each step pick the cheapest/strongest model for the job (metadata triage with Haiku, deep extraction with Sonnet). Never pre-fetch unbounded content via `!`command``; it bloats the system prompt and often blows past context limits.
|
||||
|
||||
## Shell Wrappers to Work Around `!`command`` Restrictions
|
||||
|
||||
When a skill needs dynamic values like `$(pwd)` in its pre-fetch command, write a thin shell wrapper script that does the substitution internally and expose the wrapper in `!`command``. The Claude Code permission checker rejects `$()` inside bang commands (see `!`command`` Gotchas above), but a wrapper invoked as a plain binary is fine.
|
||||
|
||||
Document the wrapper's reason-for-existence in a comment at the top of the script so it can be removed if the `$()` restriction ever lifts. Keep wrappers minimal — one responsibility each — so the indirection doesn't obscure what the skill is actually doing.
|
||||
|
||||
## Model Selection for Subagents by Task Type
|
||||
|
||||
When a skill spawns a subagent for a subtask, pick the model by cognitive demand:
|
||||
|
||||
| Task type | Model |
|
||||
|---|---|
|
||||
| Deterministic extraction, reformatting, metadata triage | Haiku |
|
||||
| Judgment required — detecting backtracking, gotchas, intent | Sonnet |
|
||||
| Planning, architecture, cross-file synthesis | Opus |
|
||||
|
||||
Document the rationale in the skill (a comment near the subagent invocation is enough) so future edits don't silently downgrade quality by picking a cheaper model without revisiting whether the task actually fits it.
|
||||
|
||||
## Subagent Path Discipline
|
||||
|
||||
Subagents inherit no cwd context from the parent skill — they start in whatever working directory the harness gives them, which is rarely where the parent was invoked. When a subagent writes output files, **pass absolute paths in its prompt** and never rely on relative paths resolving the way the parent expects.
|
||||
|
||||
Verify on the first real run that files land where intended; a subagent writing to a surprise cwd often fails silently (the parent looks for the file, doesn't find it, falls through to a default). `CLAUDE_PROJECT_ROOT` (see Portable Path Resolution above) is the canonical anchor — compute absolute output paths from it before handing them to the subagent.
|
||||
|
||||
## Separate Skill-Helper Scripts from General Scripts
|
||||
|
||||
Not every script in a repo is a skill helper. Maintain an explicit allowlist (e.g., a `SKILL_HELPERS` array in the installer) of scripts that get symlinked into the profile's skills-reachable dir (`$CLAUDE_CONFIG_DIR/scripts/`). Other scripts stay callable only by absolute repo path.
|
||||
|
||||
**Key points:**
|
||||
- **Symlinks, not copies.** Edits to the repo go live immediately without reinstalling.
|
||||
- **Hooks follow the same installer pattern** via their own allowlist loop — don't conflate hooks with general skill helpers.
|
||||
- **Explicit allowlist beats glob.** Auto-symlinking every script means new unrelated scripts silently become skill-reachable, which is a permission-scope surprise.
|
||||
|
||||
Reference in New Issue
Block a user