English · 한국어
Does your agent earn its context?
roster audit also renders a shareable HTML report with --html — view a live sample report.
Most agent tooling optimizes personas — tone, role-play, instructions. roster starts from a different premise: structure earns value, not persona. An agent's context is a dependency, and dependencies churn — they overlap, route badly, cost tokens, and rot. roster is a static analyzer for your agent roster (skills, subagents, tool configs) that surfaces those problems before they burn context in production.
roster ships as a Claude Code plugin — a resident guard instead of a one-off report.
Install via the bundled marketplace manifest:
/plugin marketplace add sshworld/roster
/plugin install rosterOnce installed:
roster-auditskill — triggers when you ask to audit an agent roster (overlap, missing harness/tools, routing ambiguity, cost); runs the bundled CLI and explains how to read the findings.roster-cleanupskill — triggers when you ask to clean up, prune, or merge agents. Audits, classifies findings into concrete actions (delete / move / merge / rename / uninstall / narrow tools), asks you to approve each destructive step, executes only what you approved, then re-audits and reports the delta.roster-usageskill — triggers when you ask which agents you actually use. Joins your transcript history against the roster to surface unused agents and ghost invocations, and points you at/roster-cleanupwhen dead weight shows up.roster-drift.shhook (SessionStart) — on each session, content- fingerprints (checksum, not just size) the watched agent-md dir(s) recursively against a cached snapshot and emits a short advisory if agents were added/removed/changed (ROSTER_DRIFT_DISABLE=1to opt out). By default it watches.claude/agentsplus, in a plugin-layout repo (one with a top-level.claude-plugin/plugin.json), the rootagents/dir; override withROSTER_DRIFT_DIR(colon-separated dir list). The scan follows symlinks and prunesnode_modules/.git. The advisory is injected into Claude's session context along with a relay directive, so Claude surfaces it to you in its first response of the session. Advisory only — never blocks a session.roster-warn.shhook (PostToolUse) — right after Claude invokes an agent (Task/Agenttool) or a skill (Skilltool), scores the TF-IDF overlap between the just-invoked name and every sibling already in the roster; above threshold (default 0.7 for the hook, 0.6 for the standalone CLI —--aboveoverrides either), it injects a short advisory into Claude's session context, same relay pattern as the drift hook. Deduped per name per session (a marker file under~/.cache/roster/warn-seen-<session>/), so a repeatedly-invoked agent only warns once.ROSTER_WARN_DISABLE=1opts out entirely. Advisory only — never blocks the tool call.
npm i -g roster-clior run it without installing:
npx roster-cli audit <dir>roster is one binary with four commands: audit, doccheck, usage, and
warn. The plugin wraps audit and usage as the /roster-audit and
/roster-usage skills, and adds /roster-cleanup — a skill-only
interactive workflow built on top of both. doccheck is CLI-only. warn
is wired as the roster-warn.sh PostToolUse hook above, plus available
standalone.
roster audit <dir>
roster audit <dir> --user
roster audit <dir> --repo owner/name[@ref][:subdir]
roster audit <dir> --html report.html
roster audit --plugin --enabled-only
roster doccheck README.md
roster usage --days 14 --user
roster warn --name my-agentFull flag surface for audit:
roster audit <dir> [--json] [--html <out>] [--user] [--plugin [name]]
[--enabled-only] [--repo <owner/name[@ref][:subdir]>] [--top <n>]
[--fail-above <s>] [--no-fail]
--enabled-only (with --plugin) restricts the plugin-cache source to entries
active for the current project.1
What counts as an agent. --repo and <dir> scans ingest a markdown
file only if it has frontmatter with a non-empty name; description is
recommended but not required. Files named SKILL.md, CLAUDE.md, or
AGENTS.md are excluded by basename even if they carry a name key.
Collections that rely on a filename-only naming convention (no name key
in frontmatter) are not ingested by repo/dir sweeps.
roster mcp runs a Model Context Protocol
server on stdio, so any MCP client — Claude Code, Cursor, Codex CLI, MCP
Inspector — can call roster_audit, roster_usage, and roster_doccheck
directly as tools, without shelling out.
npm i -g roster-cli
claude mcp add roster -- roster mcpnpx alternative (no global install):
claude mcp add roster -- npx -y roster-cli mcpCursor (.cursor/mcp.json):
{ "mcpServers": { "roster": { "command": "roster", "args": ["mcp"] } } }Codex CLI (~/.codex/config.toml):
[mcp_servers.roster]
command = "roster"
args = ["mcp"]Prefer a global install over npx in MCP client configs — a cold npx
download can exceed the client's startup timeout. Env vars like
ROSTER_CLAUDE_DIR go in the MCP config's env block, not inline in args.
Scope. roster parses markdown+frontmatter agent definitions (the Claude
Code format), and roster_usage reads Claude Code transcript files.
Adapters for other agent formats (Cursor rules, AGENTS.md packs) are on the
roadmap. The MCP server doesn't change what roster understands — it makes
that same analysis callable from any MCP client today.
roster doccheck README.md
roster doccheck docs/
roster doccheck # defaults to README.md + docs/**/*.mdScans fenced sh/bash/shell code blocks in markdown docs for commands
that would fail if a reader copy-pasted them: dead relative paths, missing
npm run <script> scripts, and scripts that exist on disk but lack the
executable bit.
To keep false positives at zero, it skips anything it can't verify cheaply:
absolute paths (/plugin ...), npx ... invocations, and bare global
binaries (node, git, ...) with no path separator.
Exits 1 if any finding is reported, 0 otherwise (--json for machine-
readable output).
roster usage
roster usage --days 14
roster usage --user
roster usage --plugin --jsonAggregates how often each subagent_type was invoked (via the Agent/Task
tool) across Claude Code transcript files under ~/.claude (override with
ROSTER_CLAUDE_DIR), within the last --days (default 30).
Joining with --user and/or --plugin also reports:
- unused — agents present in the roster with zero observed invocations
- ghosts — invoked
subagent_typevalues that don't match any roster agent
--plugin --json additionally adds a plugins array (always present and
always an array when --plugin is passed, even if empty) — one entry per
installed plugin:
{ "name": "some-plugin", "scope": "user", "version": "1.2.0",
"agentCount": 3, "usedCount": 0, "unusedAgents": ["a", "b", "c"],
"status": "unused" }status is "unused" when every agent that plugin ships has zero observed
invocations (a plugin-level uninstall candidate — human output lists
these under Fully-unused plugins (uninstall candidates): with a
claude plugin uninstall <name> hint), "used" when at least one agent was
invoked, or "no-agents" when the plugin ships zero agents (excluded from
the uninstall-candidate judgement — listed separately as
No agents (usage unknown): ...).
Always exits 0 — this is a reporting tool, not a gate.
roster warn --name my-agent
roster warn --name plugin:my-skill --kind skill --above 0.5
roster warn --hook # reads a PostToolUse payload from stdin insteadStandalone entry point for the same overlap check the roster-warn.sh
PostToolUse hook runs above: scores TF-IDF cosine similarity between
--name and every other agent/skill in the roster, and reports siblings
scoring at or above --above (default 0.6; the hook itself defaults to
0.7). --kind restricts matching to agent or skill.
roster warn --name code-reviewer
[roster warn] 'code-reviewer' overlaps with 2 sibling(s):
- pr-reviewer (agent, dir:.claude/agents) score=0.812
- security-reviewer (agent, user) score=0.734
Limits:
- Only
Task/Agenttool calls (subagents) andSkilltool calls are observed by the hook — a slash command that never routes through theSkilltool produces no advisory either way. - A skill is vectorized as
name + descriptiononly (aSKILL.mdbody is boilerplate, not signal); an agent is vectorized asdescription + body, matchingroster audit's own overlap rule. Because of that asymmetry,warnscores are not directly comparable toaudit's overlap scores. - Advisory only —
warnnever blocks, retries, or modifies the tool call it fires after.
Quiet by default — that's the point. A healthy roster produces no
warnings: in typical setups the highest sibling scores sit far below the
hook's 0.7 threshold, so silence means "no risky overlap", not "the hook
is broken". To check what your roster actually scores, lower the bar:
roster warn --name <your-agent-or-plugin:skill> --above 0.1 --jsonTo watch the hook fire end-to-end, give it something to warn about — two near-duplicate agents in a scratch project:
mkdir -p /tmp/warn-demo/.claude/agents && cd /tmp/warn-demo
printf -- '---\nname: deploy-helper\ndescription: Deploys the app to production kubernetes, checks rollout status, rolls back on failure, notifies the team channel\n---\nProduction deploy workflow.\n' > .claude/agents/deploy-helper.md
sed 's/deploy-helper/release-deployer/' .claude/agents/deploy-helper.md > .claude/agents/release-deployer.md
claude # then ask it to invoke the deploy-helper subagentThe tool result gains a PostToolUse:Agent says: [roster] 'deploy-helper' overlaps with: release-deployer (0.89) line. Even when no warning fires,
marker files under ~/.cache/roster/warn-seen-<session>/ prove the hook
ran for each invoked name.
| Rule | Description | Status |
|---|---|---|
overlap |
Detects agents/skills covering the same responsibility | stable |
harness |
Flags harness-incompatible or malformed configs | stable |
routing |
Checks routing/trigger ambiguity between agents | stable |
cost |
Estimates context/token cost of a roster | stable |
fluff |
Flags low-signal, filler instructions (bodies >20 lines) | experimental |
roster audit --repo run against well-known public agent rosters (SHA-pinned,
reproducible via scripts/bench.sh). Full reports: docs/benchmarks/.
A weekly cron re-runs the benchmark suite against each roster's latest
upstream HEAD and pushes any changes straight to main.2
| Repo | Agents | Top overlap pair | No-tools % | Fixed cost |
|---|---|---|---|---|
| affaan-m/ECC:agents | 68 | swift-build-resolver <-> swift-reviewer (0.726) | 0.0% | ~3569 tokens/turn |
| contains-studio/agents | 32 | test-writer-fixer <-> test-results-analyzer (0.475) | 3.1% | ~8421 tokens/turn |
| msitarzewski/agency-agents | 283 | Backend Architect (github:msitarzewski/agency-agents@83294689da3832c0a9f223221148c411fd3eacc0) <-> Backend Architect (github:msitarzewski/agency-agents@83294689da3832c0a9f223221148c411fd3eacc0) (0.872) | 94.0% | ~15670 tokens/turn |
| wshobson/agents | 202 | api-scaffolding-backend-architect <-> backend-api-security-backend-architect (1.000) | 93.1% | ~14253 tokens/turn |
Several top pairs score at or near 1.000 similarity (e.g. wshobson/agents has five pairs at a perfect 1.000) — these are near-duplicate agent files (same description/body reused across roles), not incidental topic overlap.
- Agents — real subagent definitions found (markdown with an explicit
frontmatter
name; docs, skills, and command files are not counted). - Top overlap pair — highest TF-IDF cosine similarity between two agent descriptions. The router picks a subagent by reading these descriptions, so similar descriptions make routing a coin flip. Rough scale: 1.000 = literally the same agent twice, 0.7+ = merge or differentiate, < 0.5 = healthy.
- No-tools % — share of agents with no
toolsdeclaration. An agent without one inherits every tool, so the model must guess its actual capabilities and least-privilege is gone. - Fixed cost — estimated tokens injected into context every turn just by having the roster registered, before any agent is invoked.
In order of impact:
- Delete unused agents —
roster usagejoins your real invocation history; agents you registered but never invoke are pure per-turn tax. Fully-unused plugins are uninstall candidates (roster usage --plugin). - Merge or differentiate overlapping pairs — a 1.000 pair means one is
dead weight; for 0.7–0.9 pairs, either merge them or rewrite the
descriptions so it's obvious when to pick which one. The
/roster-cleanupskill walks through this. - Declare
tools— give each agent the minimal set it actually needs (a reviewer needsRead, Grep, Bash, notWrite). - Diet the descriptions — keep only what routing needs; a two-sentence description routes as well as a three-paragraph bio and costs a fraction.
See CONTRIBUTING.md.
Footnotes
-
Two filters, AND-combined. Scope: user-scope entries are always active; local/project-scope entries are active only when the cwd is inside the pinning project. Settings: a plugin explicitly disabled via
enabledPluginsinsettings.json/settings.local.jsonis excluded — checked across<home>/.claude/, then the nearest project directory at-or-above cwd that has a.claude/settings.json, with later files winning and a key absent from all of them treated as enabled. This is audit-path only —usagedoes not take--enabled-only. ↩ -
Runs every Monday via
.github/workflows/leaderboard.yml. GitHub automatically disables scheduled workflows after 60 days of repo inactivity — re-enable with a manualworkflow_dispatchrun if that happens. ↩