Graphban for Cursor (generated)
Generated by
scripts/gen_subagents.py(AL-213) — do not hand-edit. Regenerate after changing the roster or AGENTS.md so the fleet can't drift. Emitted natively per toolchain — Cursor & Claude Code get Markdown + their own frontmatter; Codex gets a TOML role file. One source, native output per tool.
Cursor stores one MCP config and reuses it across every agent. That used to make a fleet impossible here: a role lived in the credential, so every agent shared one role.
Enrolment seats split those apart. The credential says who you are; a SEAT says what role you hold for this run. So the config is written once and never again, and the fleet is provisioned by pasting codes into prompts.
Install
ln -s "$(pwd)/.cursor/plugins/graphban" ~/.cursor/plugins/local/graphban
Then restart Cursor. This ships the role agents.
Once, ever — the credential
Settings -> API Keys -> create one, and put it in ~/.cursor/mcp.json:
{
"mcpServers": {
"graphban": {
"url": "http://localhost:8000/api/mcp",
"headers": { "X-API-Key": "<your key>" }
}
}
}
One server, one key. You do not rewrite this per wave, and End wave never touches it — it expires the seats and leaves the credential authenticating.
There is no environment-variable form: Cursor does not interpolate ${env:VAR}, ${VAR} or
$VAR here. Probed against 3.16.2 with the variables present in the process, and the entry is
silently dropped rather than sent as a literal — a config that looks right and connects
nothing.
Each wave — the seats
Fleet view -> Provision a whole wave. Add one seat per agent (two workers means two seats) and issue them. Each row copies a filled prompt with the code already in it; paste one per agent.
A seat is not a credential. It grants one role on one project for one session and expires in half an hour, which is what makes it safe to paste into a prompt.
Two workers need two seats. Agents that redeem the same code share a session, and the server treats a shared session as one opinion — so they could not review each other.
If an agent dies, Reissue that seat. Codes are single-use by design: reusing one would silently disable review between the agents that shared it.
Without seats
An agent that registers with no code gets all-in-one: unrestricted, no role gate, you are the
reviewer. That is the correct default for one developer and one agent, and it costs nothing.
For a fleet on one credential with no seats issued, each agent must declare who it is:
register_agent(label=..., capabilities={"instance": "<unique per agent>"}, role_hint=...)
On one credential an agent that declares nothing that differs is refused review — absence is not a difference, or omitting a field would launder a self-review.
What this does and does not guarantee
Roles are enforced. The server issued the seat, so a worker reaching for sign_off is
refused — it cannot promote itself, because it has nothing to promote itself with.
Independence is decided by the server, not declared by the agent: two agents that redeemed different seats are two sessions, so a reviewer signing a worker's item means something.
It is not an adversarial boundary. An agent handed two codes can use either. Enrolment makes the ACCIDENT impossible — which is the failure that actually happens — and does not defeat intent.