Agent repos get messy fast. Skills get copied around, docs disagree, links go stale, and nobody remembers which file is actually canonical.
Skeleton is an SSOT linter for that layer. Define the contract once; Skeleton checks it locally and in CI. If a canonical doc disappears, SSOT markers drift, a skill index stops matching disk, or a local link breaks, the audit fails before merge.
Think ESLint — for the docs and skills your agents rely on. Primary CLI from src/cli.ts: audit, validate, catalog, init, and build-plugin (plus customize / hook when using overlays). Commands dispatch through that entry file.
Skeleton is not a runtime agent harness. It doesn't execute tools, enforce permissions, or manage memory. It checks whether the repo around those systems still holds together.
Agents can read the repo. They can't reliably infer which of three conflicting docs wins, whether a synced skill should be edited here, or which validation command actually proves a change.
That needs to be explicit — and stay true after the next 50 PRs. Skeleton turns those conventions into checks:
| Code repos | Agent repos |
|---|---|
| ESLint catches broken imports, unused vars, style drift | Skeleton catches broken links, bad SSOT markers, stale doc-meta, deny.paths artifacts |
eslint --fix on changed files |
skeleton validate changed on changed docs, skills, and matching document dependencies |
| Pre-commit + CI gate | --staged pre-commit + --base CI gate |
Skill linters ask: "Is this SKILL.md well-formed?"
Skeleton asks the repo-level question: "Does this whole thing still agree with itself?"
Does an intact Skeleton contract change agent behavior — grounding on the right doc, picking the right validation lane, and how much work it takes to get there?
We ran a paired live A/B self-benchmark with @post-print/agent-test: skeleton-clean vs skeleton-messy. The same authored prompts compare an intact fixture with a conflicting fixture.
Scenarios covered contested grounding (conflicting docs), docs-only validation routing, canonical grounding, owned-skill routing, and customize ownership. Protocol: N=10 sequential paired compares on 2026-07-17; McNemar on paired pass/fail; median token deltas with a bootstrap CI on the mean.
Full method: refs/llm-harness.md. Suites: agent-suites/README.md. Aggregated numbers: SUMMARY.md. Side-by-side excerpts: evidence/transcripts/.
Inside this harness, tasks that depend on an intact SSOT favored the clean fixture:
- Contested grounding — In every paired run, clean settled on the SSOT canonical; messy never did (McNemar p = 0.002). Clean hops the catalog/SSOT path; messy thrashes across conflicting docs.
- Docs routing — Clean consistently chose the correct audit lane; messy invented a non-existent
audit allpath (McNemar p = 0.002). - Token cost — Across grounding tasks, messy used a median ~312k more tokens than clean (bootstrap 95% CI on the mean excludes 0). Pass rate alone understates the gap: messy can still luck into an answer while spending far more.
Two scenarios did not show a clean accuracy win:
- Canonical grounding — Pass rates were close; the difference was not significant. Cost still favored clean.
- Skill routing + customize — Tied. The caller
AGENTS.mdalready encodes both rules, so the fixtures did not separate on those prompts.
Charts regenerate from SUMMARY.json via bun run agent:evidence:charts.
This is preliminary evidence from Skeleton’s own authored fixture, prompt set, repository, and execution period. Repeated runs characterize variance inside that harness; they do not independently establish a causal product effect. It is not a general coding-task or SWE-bench claim. Skill/customize did not separate when the entry doc already taught the correct rule.
Not a Skeleton measurement — broader context research points the same direction: more context isn’t free. A 2026 study of repo-level context files (438 tasks) found human-written files helped ~4% on average, generated files hurt ~3%, and both raised inference cost >20%. A 2025 METR trial found experienced OSS developers took 19% longer with early-2025 AI tools while believing they were faster. Those papers motivate small instructions and explicit ownership; they do not measure this tool.
npm install -D @csark0812/skeleton
npx skeleton init --skillsThat writes skeleton.toml, ensures .skeleton/customize/, adds validation scripts, and may wire optional customize hooks for Cursor, Claude Code, and Codex.
Edit skeleton.toml for your repo layout, then verify:
npx skeleton catalog
npx skeleton audit docsFlag details: install.
- SSOT markers — opt-in
source-of-truth(comment or visible); dual/malformed forms fail; legacy banners accepted - Near-duplicate docs — shingle overlap + duplicate SSOT summaries (warn /
--strict) - SSOT summary fit — heuristic overlap between the one-liner and the body (warn /
--strict) - Link audit — broken refs, skill links, anchors in scanned markdown
- Skill index — disk matches taxonomy READMEs in detected skill roots
- deny.paths — globs for files that must not exist (often outside
scan.include) - Coverage gaps — markdown outside the scan perimeter (warn-only)
- Doc meta + stale dates — owner and
last-reviewedon indexes and SSOT-bearing files - Review proof — optional hashes bind a human review to exact document and
review-depsbytes - Dependency routing — changed repository files automatically pull matching documents into validation
- Prose policy (optional plugins) — YAML pattern rules; idle with no plugins
- Shell / JSON syntax — lightweight checks on changed
.shand.jsonfiles
Agents skim .skeleton/catalog.md (generated, gitignored) before opening full papers.
Shared reference files can live in any scanned path. Public repositories can link skills directly to GitHub-hosted references; Skeleton leaves those external links unchanged and does not check their remote reachability.
Skeleton doesn't replace your code gates. Keep TypeScript, Python, Nx, pytest, and the rest in the repo that owns them.
Config lives in skeleton.toml at the repo root (preferred). Optional under .skeleton/:
skeleton.toml # scan perimeter, deny.paths, docsLint, …
.skeleton/
├── catalog.md # generated by `skeleton catalog` (gitignored)
├── review-lock.json # generated review evidence when reviewProof.mode = "hash"
├── plugins/ # optional consumer audit plugins (.ts + built .mjs)
└── customize/ # project-specific skill overrides (optional)
└── code-review.md
Legacy .skeleton/config.yaml still loads when no TOML is present.
Every canonical doc opts into the catalog with a marker:
<!-- source-of-truth: Backend API conventions -->Then refresh the agent index:
skeleton catalogSynced skills stay pristine. Project overrides live in .skeleton/customize/<slug>.md and inject when the skill is read — no editing copied SKILL.md files.
skeleton init [--skills] [--force-hooks]
skeleton catalog [--check] [--strict]
skeleton audit docs|skills|self [--strict] [--json] [--paths=a,b] [--fix[=doc-meta|anchors|ssot]] [--dry-run]
skeleton audit docs --paths=docs/a.md --fix=doc-meta --confirm-reviewed
skeleton build-plugin [path] [--check]
skeleton validate changed [--staged | --base <ref>] [paths…]
skeleton customize resolve <slug>Validate changed routes git diffs to the right audit:
| Path | Action |
|---|---|
| Docs in scan perimeter | path-scoped audit |
Owned skill bodies (SKILL.md trees) |
exit 1 → run audit skills |
| Foreign / lockfile-synced skill bodies | skip → lint in the owning skills/toolbox repo |
.sh, .bash, .zsh |
shellcheck or bash -n |
Other .json |
JSONC-tolerant syntax check |
| Any repository file | native gates where applicable + audit documents whose review-deps path or glob matched |
Pre-commit: skeleton validate changed --staged (path-scoped, fast).
CI: skeleton validate changed --base origin/main (global rules first, then changed files).
| Layer | Role |
|---|---|
| Skeleton | Defines and checks the SSOT contract |
| Shared skills | Reusable team or public skills. toolbox is one example |
| Consumer apps | Pull in the skills, run Skeleton on SSOT paths, and keep their own code gates |
Skeleton never calls Nx or another app task runner. Consumer repos keep ownership of test, typecheck, and build.
See tiers. Related work: Toolbox packages portable process skills, and Christopher's profile connects the broader builder story.
Requires Bun 1.2.x and Node ≥ 22. Agent cold-start: AGENTS.md.
bun install
bun run checkbun run check = lint + test + typecheck + build + audit:self.
validate:changed does not replace code tests. It classifies code separately and also audits every scanned document whose review-deps declaration matches a changed file. Owned skill-body edits need audit skills. Code-only changes with no linked document still exit non-zero locally and point to native gates.
For code: bun test, bun run typecheck, bun run build.
Optional: brew install pre-commit (or pipx install pre-commit), then pre-commit install to wire .pre-commit-config.yaml.