A coordinate-addressed tree of agent skill dirs wired by cat/Read breadcrumbs, with programmatic validation.
Project description
skilltree
Turn a flat folder of skills (or any .claude directory) into a navigable tree that a model can walk one layer at a time — and keep it coherent.
Claude Code auto-loads ~/.claude/skills (and a project's .claude/skills) one layer deep: every skill directory loads at once, and a .claude nested inside another .claude never loads. At a handful of skills that is fine; at a hundred it is melt — the whole pile lands in context every turn, and tool selection degrades as the set grows. The substrate ships the nodes and forbids the edge.
skilltree imposes the missing structure on that flat substrate, using the only three levers the platform leaves open:
- placement — each node is a plain directory carrying its own one-skill
.claude/; the path is the coordinate (0→0.1→0.1.1); - the inert-nested-
.claudeboundary — only the top layer auto-loads, so deeper nodes stay out of context until entered; - breadcrumbs — each node's
SKILL.mdends with an index summary of its subtree and explicit instructions to Read its children.
You load one layer and walk; you never load the pile.
The load mechanism it exploits (verified against the runtime)
The design rests on one fact about Claude Code, which skilltree verifies rather than assumes:
Your context + Skill-tool menu =
~/.claude(always, one layer) + every project directory you Read into (itsCLAUDE.md+.claude/rules+.claude/skills, dynamically, one layer). Descendants don't load until Read; out-of-project directories don't trigger it; the trigger is the Read tool, notcat(a shellcatof the same file injects nothing).
So descending the tree is a Read into the next node — which loads exactly that node's layer and no more. That is why the breadcrumbs say Read, not cat: a cat reads the bytes but loads nothing.
Install
pip install -e . # from a clone
# or: pip install skilltree
This installs the skilltree CLI.
Quickstart
# 1. See the tree that is actually on disk
skilltree discover ~/my-skills
# 2. Check coherence — is it a tree, or a bare forest with stale wiring?
skilltree cohere ~/my-skills # exits non-zero on drift
# 3. Tree-ify a flat forest IN PLACE (lossless: whole dirs moved, baggage kept,
# symlinks de-symlinked; every move journaled to .emit-journal.json)
skilltree emit ~/my-skills --root-forest --name my-skills
# 4. ...and undo it exactly, byte-for-byte, any time
skilltree unemit ~/my-skills
# 5. Search the tree (BM25), scoped to a coordinate subtree
skilltree search ~/my-skills "deploy rollback" --scope 0.1
Programmatic use mirrors the CLI:
from skilltree import discover, cohere, emit, materialize, SkillTree, TreeNode
findings = cohere("~/my-skills") # list[Finding] — the drift report
emit("~/my-skills", root_forest=True) # tree-ify, journaled
materialize(SkillTree(TreeNode("root", "sc", children=[...])), "out/", coords=True)
Subcommands
One CLI for the whole skill-substrate toolkit — skilltree <command> …:
| Command | What it does |
|---|---|
tree <root> |
show the coordinate tree on disk (every node by its <coord>-<name> address) |
map <folder> [--write] |
render a flat folder into one coordinate-addressed CLAUDE.md (Folder Map + addressable Index + branch summaries) — progressive disclosure over a flat pile |
search <folder> <query> [--scope <coord>] |
FTS5/BM25 over any folder; --scope restricts to a coordinate subtree when the folder carries skilltree coordinates (a plain folder = coordinate-free search) |
cohere <root> |
report drift between the on-disk tree and its coherent shape |
emit <root> [--root-forest] |
re-cohere in place; --root-forest tree-ifies a bare forest (lossless, journaled) |
unemit <root> |
reverse the last emit, byte-for-byte |
discover · validate · build · notify · watch |
read a tree · gate breadcrumb-resolvability · materialize from a manifest · write the notification rule · run the decoherence cron |
map and search fold the former standalone skillmap / foldersearch / skillsearch seedlings into one product: map uses skilltree's own coordinate code (assign_coords / skill_name, no vendored copy), and search is one FTS5/BM25 engine where --scope is the only difference between coordinate-free and tree-aware search. The <coord>-<name> frontmatter and the Read-breadcrumb format are preserved for backward compatibility.
Self-management (it keeps itself coherent)
A structure the platform won't maintain decays back to the flat forest it replaced — so skilltree maintains itself:
discoverreconstructs the on-disk tree from reality, independent of any manifest.coherereports drift between reality and the engineered shape — a bare (unrooted) forest, a stale breadcrumb, a coordinate that no longer matches, a skill dropped in flat.emitre-coheres in place; given a flat forest it tree-ifies it, moving each skill directory whole (all of its files preserved — no body-only re-render, normtree) and de-symlinking any symlink'd skill, journaling every move sounemitrestores the prior state byte-for-byte.- A scheduled check (
skilltree watch <root>) writes its verdict into a single managed rule, so a decohered tree announces itself in every subsequent session.
How a tree looks on disk
domain/.claude/skills/0-domain/SKILL.md # root menu — the only node that auto-loads
domain/A/.claude/skills/0.1-A/SKILL.md # child A — loaded only when Read
domain/A/A1/.claude/skills/0.1.1-A1/SKILL.md # grandchild — one level deeper
domain/B/.claude/skills/0.2-B/SKILL.md
The root menu carries an index summary (so a query about A1 still finds the branch that leads to it) and the descend breadcrumbs (the out-edges, expressed as the Read that loads them). A coordinate stands in for identity; a breadcrumb stands in for an edge — emulations of what a graph would hold natively.
Roadmap
- v1 — Claude Code (shipping) — the tree, the front half (
discover/cohere/emit/unemit), the decoherence watch. The descent mechanic is Claude-Code-specific by design. - v2 — Cross-format adapters — per-format, not symlinks: the descent mechanic doesn't generalize (Codex resolves once at cwd; Gemini eager-loads the whole tree).
SKILL.md+.agents/skillsis the portable foundation. - v3 — Chaining — compose skills into validated chains over the tree.
Full detail in ROADMAP.md — generated from roadmap.json (the single source); the site renders it live. Run python3 scripts/update_site.py after editing the roadmap or changelog.
Papers
Two papers document the project:
- "Flat versus Tree: Why Agent Skills Need a Graph" — the why. The structural argument: a flat skill substrate starves the faculty agents actually run on; the correction is a tree traversed in
O(depth), not loaded inO(#tools). →papers/flat-vs-tree.md - "Coordinate-Addressed Skill Trees: Progressive Disclosure on a Flat Filesystem" — the how. The coordinate scheme, the Read-breadcrumb tree, the
discover/cohere/emit/unemitself-coherence loop, and the runtime-verified load mechanic. →papers/skilltree-paper.md
arXiv submission is pending an endorser.
Changelog
v0.2.0 — 2026-06-18
- Folded the
skillmap/foldersearch/skillsearchseedlings into skilltree as subcommands — one product.skilltree map <folder> [--write]renders a flat folder into one coordinate-addressedCLAUDE.md, using skilltree's own coordinate code (assign_coords/skill_namefrommodel.py; the vendored copy is gone).skilltree search <folder> <query> [--scope <coord>]is one FTS5/BM25 engine over any folder — coordinate-free on a plain folder, coordinate-subtree-scoped when the folder carries skilltree coordinates (foldersearch+skillsearchunified; the--scopeflag is the only difference). Added thetreeview command. The<coord>-<name>frontmatter and the Read-breadcrumb format are preserved (backward compatible). Suite grew 56 → 62 tests.
v0.1.0 — 2026-06-18
- Initial release. The Read-breadcrumb tree (
materialize+ the traversabilityvalidategate); the front half —discover(fs→tree),cohere(drift report),emit(lossless, journaled tree-ify of a forest),unemit(exact undo); the decoherencewatchwriting a self-managed notification rule; the CLI; the site + Dev Log. The auto-load mechanic — Read-into-a-dir injects its layer,catdoes not, nested doesn't load — was verified against the runtime, not asserted. 56 tests · Python 3.11+ · MIT.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agent_skilltree-0.2.0.tar.gz.
File metadata
- Download URL: agent_skilltree-0.2.0.tar.gz
- Upload date:
- Size: 45.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a4bb2bcc012ab744db07d02d2555bf8fd6d6251d5ad9b885b0a40ca1a6e33401
|
|
| MD5 |
7b08856d4681697e450b1a6342cbce72
|
|
| BLAKE2b-256 |
392f2280f8fe015bd107ef139c75930acf14aff8b63ee6040abcd692566d39d3
|
File details
Details for the file agent_skilltree-0.2.0-py3-none-any.whl.
File metadata
- Download URL: agent_skilltree-0.2.0-py3-none-any.whl
- Upload date:
- Size: 41.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0b620c5ae996c399df6ea87c62c94e139593a58f8f8175e738dd1fd6e2c12543
|
|
| MD5 |
66ff5aa50d3a8f8781efe243e37a9ec9
|
|
| BLAKE2b-256 |
b150b1010c739a03fdd52cf074d78972f417c7bad3aeb4b0e22182b611f8db99
|