The Role System — The File Model
Where roles live on disk, and the rules that let three orchestrators evolve the same persona without corrupting each other’s copy.
Start at the concept for what an evolving role is, or choosing & chaining for which orchestrator to reach for.
The file model — everything under .claude/roles/
A per-repo directory is the single home. It is created in the repository (not in a plugin’s install
directory) for a hard reason: a marketplace-installed plugin’s files are a read-only cache
(~/.claude/plugins/cache/…), so a plugin can never evolve a registry that lives next to its own skill.
The registry must live in the repo.
.claude/roles/
crew.md # dev-crew's role registry (one writer: dev-crew)
panel.md # brainstorm-panel's registry (one writer: brainstorm-panel)
research.md # research-sweep's role registry (one writer: research-sweep)
registry.md # auto-generated index of shared core roles (written by the roles plugin hook)
<role>.md # shared core role files (one writer: the roles plugin / user-gated graduation)
The defining property: every file has exactly one writer. No write contention, no lane-violation risk, no schema drift between plugins — by construction, not by convention.
Two layers
| Layer | What it is |
|---|---|
Layer 1 — local registries (unconditional) |
Each orchestrator keeps its own registry ( |
Layer 2 — shared core (optional, the |
Shared |
The shared core role file
Written only by the roles plugin (and user-gated graduations):
## Charter ← one-sentence mandate (keeps the role in lane everywhere)
## When to use ← trigger axes; consumers match against these to seat the role
## Body ← the full persona method + deliverables
## Learnings (core) ← context-INDEPENDENT lessons; arrive only by GRADUATION, never direct append
## Learnings (solo) ← lessons from /roles:as runs (free-append)
The consumer rows (the "annexes")
Context-specific bindings and lessons are not sections of the shared file — they are each consumer’s own registry row, so the single-writer rule holds:
| Lane | Lives in | Holds |
|---|---|---|
Crew |
a row in |
model tier, tool scope, handoff contract, crew-specific learnings |
Panel |
a row in |
lens emphasis, pairing notes, panel-specific learnings |
Research |
a row in |
coverage angle, dedup / verification notes, research-specific learnings |
Solo |
the core file’s |
solo-run lessons |
A row with no role: link is a purely local role — that is exactly how an orchestrator behaves when the
roles plugin isn’t installed.
Why lanes — shared identity, lane-scoped evolution
Sharing everything would be a bug, because the two orchestrators teach a role different kinds of lessons:
-
Crew teaches procedural lessons: "write your handoff to the run dir, don’t return text", "implement the contract, flag don’t absorb scope." Useful inside a gated relay; meaningless or wrong elsewhere.
-
Panel teaches epistemic lessons: "judge by title + depicts, never the slug", "push back — disagreement is the point." Useful as a critique lens; directly contradicts crew’s "implement the contract" if applied in a relay.
Merged naively these contaminate each other (a solo run obeying run-dir procedures that don’t exist; a crew dev-phase adopting panel-style divergence that violates its contract). So procedural lessons stay in their lane. But context-independent knowledge — "title + depicts, never slug" is true everywhere — belongs to everyone. Moving that, and only that, to the shared core is the job of graduation.
Three evolution rules
-
Free-append only to your own lane. An invocation loads the shared core (if linked) plus its own row — never another consumer’s.
-
Core learnings arrive by graduation, never direct append. When a lesson appears in two lanes, or is plainly context-independent, it is promoted to
## Learnings (core)and struck from the rows. This is the same append → graduate → prune loop the evolving-claude-md skill uses for CLAUDE.md, one level down. Therolesplugin’s SessionStart hook surfaces candidates (a role used by 2+ of crew / panel / research, or a bloated solo-learnings section); it never rewrites a role file itself. -
Identity edits are deliberate. Either orchestrator may propose a Charter or Body change; only the user applies it. A panel run silently rewriting the persona that crew will execute tomorrow is the one genuinely dangerous channel, so it is gated — and everything is in git, so every change is reviewable.
The no-downgrade principle
The guarantee that makes partial installs safe: a capability gates on the shared registry only if it intrinsically requires sharing. Composing a roster from a task’s axes, the phase-gate hook, qa hardening, the escalation ladder — none of these need a shared pool, so they ship unconditionally in the 1.1.0 skills. The shared core’s exclusive value is only what sharing actually enables: cross-context learning, solo invocation, and one talent pool. Neither orchestrator is ever second-class standalone.
| Installed | Formation | Evolution | What the shared core adds when present |
|---|---|---|---|
crew alone |
✅ dynamic compose path mints into |
✅ full loop in |
cross-skill learning; one pool |
panel alone |
✅ dynamic, as before |
✅ |
seats gain shared, evolving identity |
research-sweep alone |
✅ dynamic angle composition into |
✅ |
cross-context learning + the shared verifier ( |
roles alone |
— |
per-role solo annex + graduation audit |
solo invocation of any role |
Prompt Library anchors (optional enrichment)
Each engineering persona maps to a category of Anthropic’s
Claude Code Prompt Library — the canonical,
slot-templated prompt shapes for that kind of work. When the prompt-coach plugin is
installed, a role can consult its matching category to ground its opening in a gold-standard shape;
/roles:as does this automatically (step 2.5), and each role’s Body names its category.
| Persona | Prompt Library category |
|---|---|
|
Plan (+ Design) |
|
Implement (+ Prototype) |
|
Debug (+ Incident) |
|
Debug / Refactor (performance) |
|
Refactor |
|
Review (+ Understand) |
|
Review (adversarial lens) |
Pull a category’s templates with config.py library --category <Category> (or --role <org-role>
for the library’s team tags: pm / design / security / ops / docs / data / marketing). This is a
one-way, optional link — the roles plugin never hard-depends on the coach; the anchor degrades
silently when the coach isn’t present. The library snapshot + matcher live in prompt-coach
(single source), so there’s no duplicated data.