5 _roles/*.toml per locked §Initial role inventory:
- read-only → tools::read-only + output::report-format + severity-grade
- explorer → read-only caps + tools::cargo-only-bash
- edit-local → no-git-ops + scope::files-{white,deny}list + quality::*
+ safety::no-dep-bump + output::report-format
- edit-shared → edit-local caps + relaxed SSoT whitelist (task-time param)
+ escalation tightened to orchestrator-notify
- git-ops → spawnable = false, documentation-only
All 11 capability names referenced match phase-1 deliverable path
_capabilities/<cat>/<slug>/ (cross-ref verified before commit).
docs/AGENT-ROLES.md (223 LOC) — human-readable matrix: per-role sections
+ cross-role capability matrix + explicit non-spawnable-git-ops block.
Drift note for orchestrator integration review: edit-local/edit-shared
use inline bash-patterns-allowed = ['^cargo( |$)', '^mkdir( |$)',
'^rm -rf /tmp/'] instead of composing with tools::cargo-only-bash
capability (extra patterns not in that atom). Agent footnoted —
resolution deferred to post-integration (either parameterize the cap
or introduce tools::cargo-plus-basic-bash variant).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
10 KiB
Agent Roles — Human-Readable Matrix
SSoT: _roles/*.toml (5 files).
Schema: AGENT-SUBSTRATE-SCHEMA.md §Role.
Lock marker: AGENT-SCHEMA-LOCKED.md.
Five roles compose locked capability atoms from _capabilities/<category>/<slug>/ into prompt bundles for the Agent tool. Each role is a declarative TOML; the kei-agent-runtime compose step concatenates the listed capability text.md fragments in order to produce the final prompt.md for an agent invocation. Tool and bash-pattern allowlists are enforced at PreToolUse by kei-capability check; verify-class capabilities are enforced on agent return by kei-capability verify.
This document is derived from the 5 role TOMLs by hand. When kei-agent-runtime ships (phase 3), a kei-agent-runtime doc-roles subcommand will regenerate this file mechanically.
1. read-only
Display name: explorer (read-only analyst)
Spawnable: yes
Escalation: ask-via-return
Pure inspection agent. Reads code and docs, optionally fetches a URL, emits a structured report with severity grades. No shell, no edits, no git. Cheapest and safest role.
Capabilities bundled:
tools::read-only— deniesEditandWriteentirely at PreToolUseoutput::report-format— verify: parse report, assert required fields presentoutput::severity-grade— verify: each finding tagged with E1-E6 evidence grade
Tools allowed:
| Tool | Allowed | Notes |
|---|---|---|
| Read | yes | — |
| Glob | yes | — |
| Grep | yes | — |
| WebFetch | yes | external references |
| Edit | no | blocked by tools::read-only |
| Write | no | blocked by tools::read-only |
| Bash | no | not in allowlist |
Typical use cases:
- Code audit / critic passes (anti-pattern sweep, Constructor Pattern compliance)
- Prior-art search, docs survey, dependency research
2. explorer
Display name: explorer + cargo-check (read-only analyst with build probe)
Spawnable: yes
Escalation: ask-via-return
Read-only baseline plus a single permitted shell family: cargo invocations. Use when an audit needs cargo check, cargo test, cargo tree, cargo metadata to ground findings in actual build state — still cannot edit, still cannot git.
Capabilities bundled:
tools::read-onlytools::cargo-only-bash— PreToolUse:Bash denies unless command matches^cargo( |$)output::report-formatoutput::severity-grade
Tools allowed:
| Tool | Allowed | Notes |
|---|---|---|
| Read | yes | — |
| Glob | yes | — |
| Grep | yes | — |
| WebFetch | yes | — |
| Bash | yes | only `^cargo( |
| Edit | no | blocked by tools::read-only |
| Write | no | blocked by tools::read-only |
Typical use cases:
- Build-state-grounded audits (test counts, compile errors, workspace graph)
- Reproduction of integration-test failures without risk of edits
3. edit-local
Display name: code-implementer (local edit scope)
Spawnable: yes
Escalation: ask-via-return
The default code-writing role. Writes to task-whitelisted files, runs cargo-family commands, emits a required-field report. Cannot touch git, cannot bump deps, cannot edit files outside its whitelist or inside its denylist. On return, four verify-class capabilities run: Constructor Pattern limits, workspace cargo check, per-crate tests, and lock-file stability.
Capabilities bundled:
policy::no-git-ops— blocksgit,gh repo,gh api /reposat PreToolUse:Bashscope::files-whitelist— PreToolUse:Edit|Write denies paths outside whitelist; on-return git diff checkscope::files-denylist— denies paths in denylist (overrides whitelist)quality::constructor-pattern— verify: no file > 200 LOC, no fn > 30 LOCquality::cargo-check-green— verify:cargo check --workspacefrom MAIN passes (simulated-merge)quality::tests-green— verify:cargo test -p <crate>passes, count ≥ task minsafety::no-dep-bump— PreToolUse:Edit on Cargo.toml denies unless task opts inoutput::report-format
Tools allowed:
| Tool | Allowed | Notes |
|---|---|---|
| Read | yes | — |
| Write | yes | scope-gated |
| Edit | yes | scope-gated |
| Glob | yes | — |
| Grep | yes | — |
| Bash | yes | patterns: `^cargo( |
Typical use cases:
- Implement a new crate / feature within a bounded file whitelist
- Refactor inside one crate with dep-lock stability guaranteed
4. edit-shared
Display name: code-implementer (shared-SSoT edit scope)
Spawnable: yes
Escalation: orchestrator-notify
Same capabilities as edit-local. The difference is operational, not declarative: for edit-shared, the orchestrator parameterizes scope::files-whitelist in task.toml to include one or more SSoT paths (e.g. workspace Cargo.toml, a registry file, a cross-crate type definition). Escalation is tightened from ask-via-return to orchestrator-notify so SSoT edits surface immediately.
Capabilities bundled: identical to edit-local — the SSoT relaxation rides on per-task scope::files-whitelist parameterization, not on a different capability set.
Tools allowed: identical to edit-local.
Typical use cases:
- Workspace-level edits (add a member crate, bump a shared version)
- Cross-crate API changes where one type SSoT must be edited alongside its consumers
Difference from edit-local at a glance:
| Dimension | edit-local |
edit-shared |
|---|---|---|
| Capability set | identical | identical |
| Whitelist (task.toml) | local crate paths only | local crate + one SSoT path |
| Escalation | ask-via-return |
orchestrator-notify |
| Typical use | inside one crate | crosses a crate or workspace boundary |
5. git-ops — NON-SPAWNABLE (orchestrator-only)
Display name: git operator (orchestrator-only, NOT spawnable)
Spawnable: no
Escalation: fail-fast (not reachable at runtime)
Documented boundary of git authority — not a live role. Present in the inventory so that "who can run git" has an explicit declarative answer.
Per RULE 0.13 — ORCHESTRATOR BRANCH FIRST, only the orchestrator (main session) holds git power:
- branch creation (
git checkout -b …) - commit (
git add <paths> && git commit -m …) - push (
git push <remote> <branch>) - merge (
git merge --no-ff,git merge --squash) - rebase, reset, tag
Agents running inside .claude/worktrees/<agent>/ cannot invoke git — the sandbox denies Bash inside the worktree path. This role exists to make that boundary visible in the capability substrate, not to enable spawns.
kei-agent-runtime spawn MUST refuse any task.toml whose [task].role = "git-ops" with a pointer to RULE 0.13. The refusal is a hard error, not a warning.
Rationale (why documented at all):
- Future contributors see "git is a role" and "that role is unreachable" in the same place
kei-agent-runtime doc-rolesregeneration will surface the non-spawnable notice so it never goes stale- Matches how
_roles/git-ops.tomlholdsspawnable = falseexplicitly — declarative, greppable
Cross-role capability matrix
Capabilities as rows, roles as columns. A ✓ means the role lists the capability in [capabilities].required; ✗ means it does not.
| Capability | read-only |
explorer |
edit-local |
edit-shared |
git-ops |
|---|---|---|---|---|---|
policy::no-git-ops |
✗ | ✗ | ✓ | ✓ | ✗ |
scope::files-whitelist |
✗ | ✗ | ✓ | ✓ | ✗ |
scope::files-denylist |
✗ | ✗ | ✓ | ✓ | ✗ |
quality::constructor-pattern |
✗ | ✗ | ✓ | ✓ | ✗ |
quality::cargo-check-green |
✗ | ✗ | ✓ | ✓ | ✗ |
quality::tests-green |
✗ | ✗ | ✓ | ✓ | ✗ |
safety::no-dep-bump |
✗ | ✗ | ✓ | ✓ | ✗ |
output::report-format |
✓ | ✓ | ✓ | ✓ | ✗ |
output::severity-grade |
✓ | ✓ | ✗ | ✗ | ✗ |
tools::read-only |
✓ | ✓ | ✗ | ✗ | ✗ |
tools::cargo-only-bash |
✗ | ✓ | ✗ (¹) | ✗ (¹) | ✗ |
(¹) edit-local and edit-shared do not compose tools::cargo-only-bash as a capability atom; instead they carry an inline bash-patterns-allowed list in [tools] that encodes the same restriction. Both routes converge at the PreToolUse:Bash gate. Phase 3 runtime may later collapse the inline list into tools::cargo-only-bash-plus-mkdir-and-tmp capability atoms — non-breaking.
Tool allowlist matrix
| Tool | read-only |
explorer |
edit-local |
edit-shared |
git-ops (²) |
|---|---|---|---|---|---|
| Read | ✓ | ✓ | ✓ | ✓ | ✓ |
| Glob | ✓ | ✓ | ✓ | ✓ | ✓ |
| Grep | ✓ | ✓ | ✓ | ✓ | ✓ |
| WebFetch | ✓ | ✓ | ✗ | ✗ | ✓ |
| Edit | ✗ | ✗ | ✓ | ✓ | ✓ |
| Write | ✗ | ✗ | ✓ | ✓ | ✓ |
| Bash | ✗ | cargo-only | cargo+mkdir+tmp | cargo+mkdir+tmp | any |
(²) git-ops values are documentation only — the role is non-spawnable.
Escalation policy matrix
| Role | Policy | Meaning |
|---|---|---|
read-only |
ask-via-return |
Surface questions in the final report; orchestrator reads them |
explorer |
ask-via-return |
Same |
edit-local |
ask-via-return |
Same |
edit-shared |
orchestrator-notify |
Touching SSoT ⇒ notify orchestrator before completing |
git-ops |
fail-fast |
Unreachable; any spawn attempt errors |
Maintenance
- Changes to any
_roles/*.tomlrequire updating this file in the same commit. - New roles are added as new sections 6+ with the same structure, and new columns added to the two matrices above.
- When
kei-agent-runtime doc-rolesships in phase 3, it replaces the hand-authored matrix; the top-of-file "derived by hand" note is removed then.