Optimizing Skills & Agents
|
This content was generated with the assistance of AI and should be verified against the official documentation of each tool and framework before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
This page is written against the Claude Code CLI 2.1.283, VS Code 1.139 with the GitHub Copilot Chat
extension, and the GitHub Copilot CLI 1.0.88, all re-verified as current as of 2026-09-28. Every ai-catalog
example is excerpted from the repository at the pinned commit
58fb709
(main), which was still the current main commit as of 2026-09-28.
Skills and subagents are cheap to add and expensive to leave unmanaged: every installed skill’s description
loads into context on every turn (Skills covers the mechanism),
every subagent call spends tokens standing up a fresh context, and every tool invocation is either
pre-approved or an interactive prompt. The twelve techniques below are not abstract advice — each one is
something ai-catalog’s own skills and agents actually do, and each entry states what was verified directly
(a token count, a real proportion of the catalog) versus what is described qualitatively because it cannot be
measured from static files (latency, which depends on the model and the run).
Measurement method
Two of the techniques below (context budget awareness and progressive disclosure) are backed by a real token count taken as of 2026-09-28:
-
Source. Every
.claude/skills/<name>/SKILL.mdat the pinned commit (git -C ai-catalog ls-tree -r 58fb709 --name-only | grep SKILL.md) — 102 skills, each read withgit show 58fb709:<path>. The frontmatter between the two---markers is read line by line rather than with a YAML parser: each top-levelkey:starts a field, every following line up to the next key is a continuation, and continuations are joined with single spaces, the way YAML folds a multi-line plain scalar. That yields adescriptionfor all 102 skills (23 of them span more than one line) and nowhen_to_useanywhere, confirming the catalog does not currently use that key. -
Why not a YAML parser. 52 of the 102 frontmatters fail
yaml.safe_loadwith "mapping values are not allowed here": their unquoted plain-scalardescriptioncontains a colon followed by a space (for exampleas it actually is: service overviewin `iru-update-java-springboot-documentation’s description), which YAML reads as the start of a nested mapping. A YAML-based count would silently drop those descriptions. What that means for how the skills actually load is covered in Half the catalog’s frontmatter is not valid YAML below. -
Tokenizer. No Claude-specific tokenizer is published for offline counting, so this page uses
tiktoken'scl100k_baseencoding as a documented approximation — the same GPT-family byte-pair encoding commonly used as a stand-in when a model’s own tokenizer isn’t available offline. Anthropic’s Messages API also exposes a livecount_tokensendpoint for an exact count against a given model, which this page did not call (no request budget for 102 live calls); thecl100k_basefigures below should be read as a close approximation, not an exact Claude count. -
Result, as written. The 102 descriptions total 40,420
cl100k_basetokens (172,553 characters), averaging 396 tokens (1,692 characters) each. -
Result, as listed. Claude Code truncates each skill’s listing text at 1,536 characters, so the always-on figure counts each description cut to its first characters and then tokenized: 31,703
cl100k_basetokens (135,645 characters), averaging 311 tokens (1,330 characters) each. 43 descriptions fit within the cap untouched and 59 are over it; 84 are over 1,024 characters, thedescriptionmaximum set by the Agent Skills specification.
The worked estimate in A back-of-envelope for the always-on cost uses these measured figures.
Half the catalog’s frontmatter is not valid YAML
The 52 frontmatters that fail yaml.safe_load are not only a measuring problem. Per
Claude Code — Skills (as of 2026-09-28), when the frontmatter YAML
doesn’t parse, "the skill still loads with no fields set": /skill-name still works, but Claude cannot match
the skill against its description, and every other key is ignored too. At the pinned commit that covers:
-
the
descriptionof 52 skills — the 50 skills whose frontmatter does parse account for 13,779 of the 31,703 capped tokens above, so the figures in this page describe the catalog as written, not what Claude Code 2.1.283 actually lists for it today; -
the
modelpin of 52 skills — 31 of the 48haikuskills, 20 of the 51sonnetskills and 1 of the 3opusskills (iru-explore) in the tiering table under technique 7; -
the
allowed-toolsgrant of 13 of the 21 skills that declare one (technique 8).
The cause is the same in all 52: an unquoted plain scalar containing a colon followed by a space. The fix belongs in ai-catalog, not here, and is mechanical — quote the value, or turn it into a folded block scalar so no colon inside it can be read as a key. An illustrative (not excerpted) frontmatter in the folded form:
---
name: iru-example-setup
description: >-
Scaffold the example configuration for a repository.
Accepts pre-resolved inputs via `args` (`key: value` lines).
model: haiku
---
The folded (>-) form keeps the text on as many lines as needed and joins them with spaces, which is the
reading the catalog’s authors intended; the frontmatter rules it has to satisfy are in
Claude Code — Skills. This page suggests it as an ai-catalog follow-up; applying
it would change none of the numbers above, because the line-based extraction already reads each description
the way the fix would.
The twelve techniques
1. Context budget awareness
Principle. Every installed skill’s description (and when_to_use, if set) loads into every session’s
context whether or not that skill ever runs, capped at 1,536 characters combined per skill (see
Skills's frontmatter table). A catalog of N skills therefore
carries a fixed always-on cost of N descriptions before a single task is discussed — keeping each one short is
the cheapest lever available, because it is paid on every turn of every session, not just the turns that use a
given skill.
Catalog example. Only 43 of ai-catalog’s 102 descriptions fit within the cap — iru-check-license/SKILL.md's
is 593 characters (126 tokens). The measurement above surfaces the counter-example just as clearly: the other
59 are over it, and the five longest by token count are each at least 1,299 characters past it:
| Skill | Characters | cl100k_base tokens |
|---|---|---|
|
3,546 |
917 |
|
3,365 |
887 |
|
3,331 |
862 |
|
3,331 |
842 |
|
2,835 |
720 |
iru-setup-swift-github-workflows/SKILL.md’s description alone is more than double the limit, because it
packs its entire `args vocabulary into one sentence instead of relying on the skill body. Everything after
character 1,536 is cut from the listing, so the tail of each of these descriptions costs nothing on every turn
but also never reaches the model when it decides which skill to use. This is not invented for illustration:
it is what git show returns for the pinned SHA, and it is a real instance of the discipline lapsing in
skills that otherwise follow every other convention in this page.
Measured effect. 31,703 cl100k_base tokens for all 102 descriptions combined, each counted only up to the
1,536-character cap (40,420 tokens as written) — the fixed, always-on cost of having the whole catalog
installed, before any skill body is ever read. See A back-of-envelope for the always-on cost for the
worked estimate this feeds into.
2. Progressive disclosure via reference files and routing tables
Principle. Put the detail a task only sometimes needs in a separate file, and have the skill body point at it with a routing table, instead of inlining everything into the body that loads on every activation.
Catalog example.
iru-java-code-one-task/reference/README.md
opens with two short prose paragraphs on what the directory is for, then gives exactly this routing table:
## Read this much, and no more
| Read | When |
|---|---|
| `code-style.md` | **Always.** Type inference (`var`), `final` wherever possible, ... |
| `class-member-ordering.md` | The task adds a new type, or adds/moves a constant, field, ... |
| `javadoc.md` | The task adds or changes a type, or any public/protected member. |
| `testing.md` | The task writes or updates tests — which is nearly every task, ... |
A task that only changes logic inside one existing method needs `code-style.md` plus `testing.md`, and nothing
else. Don't read the rest speculatively.
Measured effect. The four reference files total 6,169 cl100k_base tokens
(code-style.md 2,396 + class-member-ordering.md 1,750 + javadoc.md 915 + testing.md 1,108, each counted
from git show 58fb709:.claude/skills/iru-java-code-one-task/reference/<file>). A task
that only edits inside an existing method body — the routing table’s stated minimum, code-style.md
testing.md — loads 3,504 tokens instead: a 43% reduction against reading all four unconditionally, paid
only on the tasks that actually add or reorder a type.
3. Context isolation with compact structured summaries
Principle. Run the noisy part of a job (a test suite, a lint pass, a build) in its own context window, and report back a compact structured summary instead of the raw output — so the token cost of the raw report is paid once, inside the isolated run, never in the caller that keeps accumulating turns.
Catalog example.
iru-gate-runner.md's
"What you report back" section is explicit about the shape of that summary:
- A pass/fail run (tests, a build): state only that it passed, or the failing name(s), failure reason, and
relevant stack trace/error output for each failure — never the full log of everything that passed.
- A coverage check: the requested percentage(s) only — not the per-line/per-branch detail ...
Effect (qualitative). No public tool measures the byte size of a given project’s Surefire/JaCoCo/SARIF output, so this is not quantified here, but the direction is unambiguous: a full test-suite log grows with the number of tests (typically hundreds to thousands of lines for a mid-sized project), while a pass/fail-plus-counts summary stays roughly constant regardless of suite size. A naive gate vs. the gate-runner pattern shows this comparison visually. Subagents & Custom Agents covers the same isolation mechanism from the subagent side.
4. Baselines, reporting only regressions
Principle. Persist a snapshot of a check’s last-known state to a file, and on a re-run report only what’s new since that snapshot — not the full current result plus the old one for the caller to diff by hand.
Catalog example.
iru-check-security/SKILL.md
maintains a .secrets.baseline file and reports "only secrets that are new since the last baseline or were
never triaged (audited)" for a whole-repository run, rather than re-reporting every previously-audited finding
on every run. The same file’s Step 5 spells out the mechanic: rescan with
detect-secrets scan --baseline .secrets.baseline, then diff the old and new baseline contents and report only
the newly-appeared entries.
Effect (qualitative). A repository with, say, 40 previously-audited false positives sees a report listing only the genuinely new findings on each re-run, instead of 40+ lines re-litigating decisions already made — the report’s length tracks the delta, not the total number of things ever checked.
5. Validating once per group
Principle. When several tasks land together, run the expensive validation (the full test suite, coverage, lint) once for the whole batch after every task in it is implemented, instead of once per task.
Catalog example.
iru-plan/SKILL.md's
Step 5 states the rule the whole pipeline is built around:
- Within a group, task **implementation** (code + its own tests) can generally run in parallel even when the
group's final validation (running all tests, checking coverage, checking quality) must happen once, together,
after every task in the group has been implemented — that consolidated validation is what a downstream
`<key>-code-one-task-group` skill performs once per group instead of once per task.
Effect (qualitative, directional). For a group of N tasks, this collapses N separate quality-gate
invocations into one: each avoided invocation is one fewer iru-gate-runner agent call (its own context-window
setup cost) and one fewer possible interactive tool prompt for the commands it runs, without changing what gets
checked — the whole group’s code is still fully tested and linted, just in a single pass.
Orchestration Patterns walks the full pipeline
this belongs to.
6. Parallel fan-out
Principle. When a batch’s tasks don’t touch the same files, issue every task’s Agent(…) call in the
same response instead of one after another, so they run concurrently rather than serially.
Catalog example.
iru-java-code-one-task-group/SKILL.md's
Step 2 states it directly: "issue all of the Agent calls below together, in the same response, so they run
in parallel rather than one after another". Orchestration Patterns
walks the full fan-out/fan-in excerpt and its accompanying sequence diagram.
Effect (qualitative). No latency number is claimed here — how much wall-clock time this actually saves
depends on the model, the provider’s concurrency limits and each task’s own length, none of which this page can
measure from static files. Directionally, running N independent tasks concurrently makes total wall-clock
time track the slowest single task rather than the sum of all N task durations, which is why the technique
only pays off when a group’s tasks genuinely don’t depend on each other (a Parallelizable: no group is still
run one at a time).
7. Model tiering and effort levels
Principle. Pin the frontmatter model (and, where it matters, effort) to what a skill actually does — a cheap, fast tier for templated/mechanical work, a heavier tier only for work that needs to read and reason
about arbitrary code.
Catalog example. Across the same 102 SKILL.md files measured above, the model frontmatter splits as:
| Model | Skills | What that tier is used for |
|---|---|---|
|
48 |
Setup/gitignore/workflows/orchestrator/test/coverage/code-quality/bump-version skills — templated, mechanical
work, per |
|
51 |
|
|
3 |
The heaviest reasoning work: |
Measured effect. 48 of 102 skills (47%) are pinned to the cheapest tier by design — verified directly
against the model: frontmatter key at the pinned commit, not estimated. As written, that is; in practice 52
of the 102 frontmatters don’t parse as YAML, so the pin is ignored for 31 of those 48 haiku skills, 20 of the
51 sonnet skills and iru-explore among the opus ones, and each runs on the session’s model instead (see
Half the catalog’s frontmatter is not valid YAML) until the catalog quotes or folds
those descriptions. Effort levels add an orthogonal lever on top
of model choice: per Claude Code — Effort levels, a skill or
subagent’s frontmatter effort (low/medium/high/xhigh/max) trades reasoning depth for token spend and
latency independently of which model tier is pinned — ai-catalog’s own SKILL.md files do not currently set
effort (it is available but unused at the pinned commit), so this remains a lever the catalog
could still apply, described from the docs rather than measured from the repository.
8. Scoped allowed-tools
Principle. Grant exactly the tool/command prefixes a skill’s own steps need for the turn that invokes it,
never a bare Bash, so nothing outside that scope needs an interactive permission prompt while the skill runs — and nothing outside that scope can run silently either.
Catalog example.
iru-check-security/SKILL.md
scopes every entry to a command prefix: Bash(detect-secrets *) Bash(pip install *) Bash(git status *) … — never Bash alone. Permissions & Settings covers how these patterns
interact with the broader settings hierarchy.
Measured effect. 21 of the 102 skills declare allowed-tools (verified directly against the frontmatter as
of 2026-09-28); the other 81 rely on the default file-editing tool set plus whatever the session’s own
permission settings already allow, needing no per-skill grant. For the 21 that do declare it, every tool call
matching a listed prefix skips the interactive permission prompt for that turn — a directly attributable
reduction in prompt count for exactly the commands named, though the number of prompts avoided in a given run
depends on how many matching commands that run happens to issue, which this page does not simulate.
9. Deterministic work in scripts or hooks rather than prose
Principle. Where a step’s outcome should not depend on the model re-deriving it each time, express it as an exact, executable command in the skill body (or a hook, covered on Hooks) rather than a prose description the model has to reinterpret on every run.
Catalog example. Neither ai-catalog nor this docs repository’s own .claude/skills/ uses a scripts/
subfolder or Claude Code hooks as of this pinned commit (verified via git ls-tree) — so this is described
qualitatively rather than measured, and it is worth stating plainly rather than glossing over: the catalog gets
determinism a different way, by writing the exact shell invocation into the skill body itself instead of
describing the goal in prose. Two examples, both quoted verbatim:
find .claude/skills -maxdepth 1 -type d -name "*-code-one-task-group" (dispatch by key, see
Orchestration Patterns) and
detect-secrets scan --baseline .secrets.baseline (technique 4, above). Neither leaves the model to reconstruct
"find the language-specific skill" or "diff against the last scan" as an open-ended judgment call.
Effect (qualitative). An exact command produces the same result every time it runs, independent of how the model would otherwise have phrased the equivalent instruction — the reliability gain from removing that variance is real but not something this page can express as a token or latency number.
10. Idempotency, checkpointing and resumability
Principle. Before writing anything, check what already exists and skip what’s already done, so re-running a skill after an interruption — or on a repository that is already partly set up — fills gaps instead of duplicating or overwriting work.
Catalog example.
iru-setup-antora/SKILL.md's
Step 2, "Survey what already exists," is explicit about this:
- Does a `docs/` directory already exist at the repository root? ...
...
- Does `docs/modules/ROOT/` exist, and if so what pages does `docs/modules/ROOT/nav.adoc` already list?
...
... Every later step acts only
on genuine gaps — a fully-set-up repository (one that already has all of this) should result in Step
13 reporting "already set up," not in duplicated or overwritten files.
Orchestration Patterns covers the pipeline-level version of the same
discipline — implementation_plan.md’s checkboxes, letting a re-run skip every group already marked `[x].
Effect (qualitative). A re-run on an already-set-up repository costs only the survey reads, not the write operations (and their permission prompts) that creating each file from scratch would have needed — how much that saves in a given repository depends on how much was already in place, which this page does not simulate.
11. Avoiding re-prompting (pass-through args)
Principle. When one skill dispatches to another, pass along every input it already resolved as
key: value args, so the callee skips asking the user (via AskUserQuestion) for anything the caller already
knows.
Catalog example.
iru-setup-java-library-repository/SKILL.md's
Step 0 states the rule its callees follow: "Every key found here is resolved — skip the matching question in
Step 2. Only keys genuinely missing from args still need asking." Writing Effective Skills
covers the same pattern from the skill-authoring side, with a different iru-setup-* excerpt.
Effect (qualitative). Each key: value pair a caller passes through is one fewer AskUserQuestion
interruption the callee needs to raise — directly attributable per key, though the total number of prompts
avoided in a given run depends on how many of a callee’s inputs the caller happens to already have resolved.
12. Prompt-cache-friendly structure (stable prefixes)
Principle. Keep the part of the context that doesn’t change between turns — instructions, tool definitions, the set of loaded skill descriptions — in a stable order at the front, and put whatever varies per turn at the end, so a caching-aware provider can reuse the unchanged prefix instead of reprocessing it. Cost, Latency & Throughput covers the economics of this in depth (cached input is billed at a fraction of the base rate and skips reprocessing); this page covers only the structural discipline that makes a prefix cacheable in the first place.
Catalog example. With the catalog installed, a session loads the same skill listing (the name/description pairs
measured above) at session start, in the same discovery order, on every turn until a skill is added, removed or
edited — the exact "long, unchanged prefix" a cache-aware provider can reuse, per
Cost, Latency & Throughput. The catalog’s own SKILL.md frontmatter is also
written in a consistent key order (name, description, model, then allowed-tools where present) across
every file inspected for this page, rather than varying field order file to file.
Effect (qualitative). Whether a given cache breakpoint is actually hit depends on the provider and the exact request shape, which this page does not measure; the structural point stands independent of that: nothing in ai-catalog’s skill set changes turn to turn within one session, so the descriptions loaded at the start of turn 1 are byte-identical to the descriptions loaded at the start of turn 50, which is the precondition a caching mechanism needs, not a guarantee of a cache hit.
A back-of-envelope for the always-on cost
The always-on cost of having a catalog of skills installed is, to a first approximation, the sum of every installed skill’s listed description, each cut at the 1,536-character cap before it is counted:
where is skill 's description length in characters, is its first
characters and counts tokens. The cap is applied in characters because
that is how Claude Code truncates the listing; a description under the cap counts in full. This ignores when_to_use (unused across
all 102 measured skills) and any per-turn overhead outside the descriptions themselves (the system prompt, tool
definitions, CLAUDE.md), so it is a lower bound on the always-on skill-related cost, not the full context
budget.
Worked estimate, ai-catalog main, 2026-09-28. skills. Summing the capped descriptions in
cl100k_base tokens (method: Measurement method, above) gives:
— an average of 311 tokens per skill ( ), against 40,420 tokens if nothing were
truncated. Read against
Context Windows & Memory's coverage of typical context
window sizes, 31,703 tokens is a small fraction of a modern long-context window, but it is a fixed fraction
paid before any task-specific work begins, and it grows linearly with every skill added. At the measured
average of 311 tokens each, a catalog half this size (51 skills) would carry roughly 15,850 tokens; growing to
102 doubles the always-on cost with it. The cap only bounds the worst case: it saved 8,717 tokens here, and
each new skill can still add up to 1,536 characters (313 to 432 cl100k_base tokens for this catalog’s
prose, which is what the 59 over-cap descriptions cost once cut). That linear growth is why technique 1’s per-skill description-length
discipline compounds as a catalog grows.
A naive gate vs. the gate-runner pattern
This is technique 3 (context isolation) made concrete: the two sides run the same underlying tool, the difference is only where the output is read. Two of the techniques above compound with this pattern in practice: model tiering picks which model runs inside the isolated agent (a cheap tier for a mechanical check, a heavier one only where the check itself needs to reason about code), and prompt caching (technique 12) means the isolated agent’s own stable prefix — its system prompt and tool definitions — can itself be cached across repeated invocations within a session, independent of whether its raw output is ever shown to the caller.