A third tier for Claude Code skills β dormant, zero tokens, still findable. Search a graph of your collection instead of pre it.
53 skills, 6 kept enabled: 2,544 β 338 tokens per session (β86.7%). The other 47 cost nothing until asked for.
claude plugin marketplace add danielLublinsky/Skill_Atlas
claude plugin install skill-atlas@skill-atlas
Python 3 only β no dependencies, no network (d3 is vendored). Later:
claude plugin update skill-atlas@skill-atlas
.
From a local clone (for hacking on it) #
git clone https://github.com/danielLublinsky/Skill_Atlas.git
claude plugin marketplace add ./Skill_Atlas
claude plugin install skill-atlas@skill-atlas
| Command | What it does |
|---|---|
/skill-atlas |
|
Build the graph, categorize what's new, render atlas.html . Run this once to set up. |
|
/skill-atlas:edit-searchable |
|
| Move plugins in and out of the searchable tier, interactively. | |
/skill-atlas:skill-search |
|
| Find the right skill for a task across the whole library, dormant tier included. Usually you never type this β Claude calls it on its own before a nontrivial task. | |
| (automatic) | |
| A SessionStart hook keeps everything fresh after that. |
Then open ./.claude/skill-atlas/atlas.html
in a browser, and just ask for a task β the search runs itself, names the skill it picked in one line, and gets on with the work.
Without the plugin (Makefile) #
make build # graph.json + catalog/ from your live manifests
make render # atlas.html
make check # CI gate: exit 1 on any broken reference or dangling mention
make test # unit suite against fixtures β never touches the real ~/.claude
Claude Code injects every enabled skill's description into every session β ~48 tokens each. At 100+ skills that's thousands of tokens you pay for constantly, and near-duplicates quietly compete for the model's attention.
Disabling fixes the cost and loses the skill. So Skill Atlas adds a tier in between:
| Tier | In context? | Findable? | Cost / session |
|---|---|---|---|
| π’ enabled | |||
| yes | natively | ~48 tokens each | |
| π£ searchable | |||
| no | |||
via skill-search |
|||
| 0 | |||
| β« disabled | |||
| no | no | 0 |
A searchable skill is dormant β its description never enters your context, but it stays discoverable on demand. All that advertises the whole dormant tier is one ~50-token line at session start.
flowchart LR
A(["π§ a task arrives<br/><i>βresolve this merge conflictβ</i>"])
subgraph R1["1οΈβ£ read the index Β· ~1.6k tok"]
I["<b>_index.md</b> β 14 lines<br/><i>name Β· count Β· what it covers Β· member tokens</i>"]
end
subgraph R2["2οΈβ£ read one shard Β· ~0.6k tok"]
S["<b>version-control.md</b><br/>using-git-worktrees<br/>resolving-merge-conflicts β hit"]
end
X["the other 13 shards<br/><i>~10k tok Β· never opened</i>"]
A --> I
I -- "pick ONE category" --> S
I -. skipped .-> X
S --> E["π’ <b>enabled</b><br/><i>invoke natively</i>"]
S --> F["π£ <b>searchable</b><br/><i>read its path,<br/>follow as instructions</i>"]
classDef file stroke:#8a8578,stroke-width:1.5px
classDef ghost fill:transparent,stroke:#8a8578,stroke-width:1.5px
classDef hit fill:#1baf7a26,stroke:#1baf7a,stroke-width:2px
classDef dormant fill:#8a5cd626,stroke:#8a5cd6,stroke-width:2px
classDef muted fill:transparent,stroke:#8a8578,stroke-width:1px,stroke-dasharray:4 3
class I,S file
class A ghost
class E hit
class F dormant
class X muted
style R1 fill:#3987e514,stroke:#3987e5,stroke-width:1.5px
style R2 fill:#3987e514,stroke:#3987e5,stroke-width:1.5px
A search costs ~2.4k tokens β the index (1.6k), one shard (~0.6k) and the search skill itself (0.4k) β and you pay it only when a search happens. The alternative it replaces is every dormant description sitting in context from session start, billed whether you search or not. The arbitrage is real when searches are occasional; it is not free, and the numbers above are measured rather than estimated.
One shard is the norm. A second is opened only when the entry you found lists a category you haven't read β the catalog pointing, not the model guessing β and never a third. Counts overlap on purpose, so the pick doesn't have to land on the right bucket, only a right one. Tier-off skills are excluded when shards are written, so a disabled plugin can never return through a side door. The result is announced in one line before the work continues: search is a lookup inside a task, not a deliverable.
The model categorizes once. The first run drafts 8β12 categories named for user-intent task shapes, not products, then freezes the taxonomy. Later runs only file new skills and re-confirm the ones whose description changed β each assignment carries a hash of the description it was made against.
Discovery is manifest-driven β installed_plugins.json
β each plugin.json
β
settings β so marketplace catalogues and stale cached versions never pollute the
picture. (The naive "every directory with a SKILL.md" count over-counts by ~60% on a
real machine: build_graph.py --naive-count
.)
Skills are nodes. The edges are the interesting part:
| Edge | Caught | |
|---|---|---|
| π | references β a skill β its own bundled files | |
| broken when the file isn't there | ||
| π¬ | mentions β a skill naming another skill | |
dangling when the target is disabled , unregistered or absent |
Mention matching is deliberately strict β only backticked, skills/<name>
, or unambiguous hyphenated names, code fences stripped first. Loose matching produced 91 edges on a 41-skill collection, almost all of them ordinary English words. You also get duplicate names, orphans, and an exit code to gate CI on.
atlas.html
is self-contained and opens from file://
with zero network requests:
scope (origin, state, breakage in red) and categories (hub-and-spoke β solid
edge to the home category, dashed to the rest; search cat:<name>
to isolate).
What's really registeredβ discovery is manifest-driven, so unregistered copies and stale plugin caches surface as their own nodes instead of quietly counting.Broken bundlesβ areferences
edge whose file isn't on disk draws red, so a typo'dreferences/foo.md
is visible without opening anything.Why it didn't triggerβ tier is the node's fill (enabled Β· searchable Β· disabled), and duplicate names are called out in the footer with both nodes drawn.Read it in placeβ pin any skill or bundled file and hit** open markdown**to read the source in a popup without leaving the graph.
docs/ β component guide, numbered 1β9: start at
overview, then jump to the component you're touching (discovery, graph build, categorization, catalog & search, rendering, hooks).
DESIGN.md β the historical record for both phases: what was considered, what was chosen, what was dropped, and why
Apache-2.0 β see LICENSE.
D3 is vendored in vendor/d3.v7.min.js and inlined into
every generated atlas.html
. It is ISC-licensed, Β© 2010-2023 Mike Bostock β see vendor/LICENSE-d3.