Roles // and the board they imply
agent-compose
eval driven agent roles and personas
You wrote seven personas. Which one has ever been tested?
compose {
role "platform"
delivery "native-skills"
source "aos-public"
}
That is the whole request. What comes back is a directory of plain files, and you can diff it against the last one before anything runs.
One seat, selected out of the roster
one seat and the two traits it melds composed 14 others never enter this bundle
The thirteen cases that one selection implies
8 boundary halves from four boundaries, in and out 3 role-fit targets from itself and its two likeliest absorptions 2 personality cases from the meld it carries 13 per seat, 91 across the roster, and the roster picks them
The problem, and what it costs to leave alone
Who an agent is and what an agent may do end up in the same blob.#
The usual shape is one long system prompt carrying the voice, the job, the house rules, the tool list, and a few sentences that are really an authority claim. It is edited by whoever is closest to the problem that week. Nothing about it is versioned in a way a reviewer can read, and a change to the persona is indistinguishable from a change to what the agent is allowed to reach.
The expensive failure is not a dramatic one. It is that the persona is the least tested artifact in the stack, so nobody can say whether a seat still refuses the thing it was written to refuse. Two roles drift into each other, one quietly absorbs the other's work, and the only evidence is a transcript somebody has to read by hand.
What it does about it
agent-compose compiles the context a harness loads, and nothing else.#
It selects a role, the personality meld that role carries, the skills that role can see, and the tool inventory it gets, then materializes one immutable bundle of plain files. Claude Code, Codex, Goose, and OpenCode all take the same bundle. Execution permissions, runtime facts, and lifecycle stay with whatever launches the agent, and a role slug shared with a launch consumer transfers no authority back into agent-compose.
What you can do to a bundle before you trust it
- describe
- Renders the stored decision tree.
--whyfollows one item from consideration to outcome. - diff
- Reports the semantic change between two bundles, rather than the textual one.
- verify
- Checks that entry points, delivery, traces, and selected identities are complete.
- read it
- It is a directory of files. No format stands between you and the answer.
Selection is exclusive rather than additive. An external person package brings its own roles, seats, personalities, and evaluation context, and it replaces the default roster wholesale instead of merging with it, so there is no state in which a seat inherits half of somebody else's charter.
Why the tagline leads with eval
The test board is derived from the roster, not written beside it.#
Boundaries and their owners produce the pairs. Adjacency produces the role-fit targets. Each role's meld produces the personality cases. Add a boundary, flip an adjacency edge, or swap a personality, and the challenge list moves on its own. You cannot write a case that does not correspond to the roster, and you cannot change the roster without changing what gets tested.
The hard cases are generated on purpose. Role adjacency names each role's two likeliest absorptions, and those reasons become the descriptors a generator uses to build exactly the confusion a seat is most at risk of.
Note
Three parties, and none of them holds two seats. A generator authors the cases, a subject answers them, and a human grades them. The grading half ships separately, so it holds no runner and no model client, and grading never spends a token or touches a deployed system.
What it looks like in use
The reviewable surface is the request and the bundle it produced.#
Four lines name a seat, the shape the harness wants it in, and where the
role-scoped skills are allowed to come from. Everything downstream of that is
derived and recorded, which is why describe has something to render.
compose { 1
role "platform" 2
delivery "native-skills" 3
source "aos-public" 4
}
- 1 compose
- One request produces one bundle. Re-running it with the same inputs produces the same bundle.
- 2 role
- The seat, chosen from the roster. It carries a charter, a boundary set, and a personality meld, and it carries no permission.
- 3 delivery
- The shape the target harness wants. The selected context does not change with it.
- 4 source
- A skill-provider repository the role is allowed to see. What it does not name, the seat never reads.
What it does not do
agent-compose is not a permission system.#
A role is context, never permission. It has no opinion about what an agent may execute, and it cannot stop anything. A composed seat that says it defers an action will still run that action if the runtime hands it the tool, because prose is not a control.
The bundle carries no credential, no mount, no command, no network reach, and no lifecycle, on any role. Those are absent by construction rather than by configuration, so there is no setting that turns one back on. Treating a role briefing as the boundary is the one misreading this page exists to prevent.
| Layer | Who owns it |
|---|---|
| Context | agent-compose. What the seat knows, believes it is for, and can read. |
| Authority | A guardfile, enforced before execve. See umbra. |
| Isolation | A container's job, and nothing here substitutes for it. |
| Lifecycle | Whatever launches the agent. Credentials, mounts, and network reach live there. |
The bundle is the evidence for exactly one of those four rows. That is a smaller claim than a persona file usually makes, and it is one you can check.
One boundary, four proofs
Constrain what an agent can do, and prove what it did.#
- umbra v0.170.0 Writes the policy.
- mcp-beaver Preview Renders that same guardfile into a guarded MCP server.
- agent-compose v2.61.0 Composes the context around it, carrying no authority. You are here.
- sirens-echo Live The whole thing deployed, answering real people.
Repository and docs