SANDSCOPE / CHARTER

Your coding agent, working as a team that can tell you no

Claude Code, Cursor and Codex are competent generalists. On a real build, one voice writes the code, reviews the code, tests the code, and declares it done. Charter makes that voice work as named specialists instead — and enforces the separation rather than suggesting it.

A role may not sign off its own work.

That rule governed this repository first. Charter is that discipline extracted into an MCP server, where the checks are executed instead of asked for. It is open source, runs entirely on your machine, and has no accounts, telemetry or paid tier.

Install

In Claude Code, one step — it installs the server and the skill that drives it:

/plugin marketplace add 224Sand/charter
/plugin install charter@charter

Both halves matter. An MCP server only answers when asked; it cannot push. Something has to tell your agent to keep calling charter_next until the build is done, and that is the bundled skill. Install the server alone and you get four tools nobody calls.

Cursor, Codex, or any MCP client

{ "mcpServers": { "charter": { "command": "uvx", "args": [
    "--from", "git+https://github.com/224Sand/charter", "charter", "serve" ] } } }

Then generate the skill yourself, because nothing else will:

charter gen-skill --dest .claude/skills/charter

The skill is rendered from the same role definitions the server enforces, so the instructions your agent reads and the rules it is held to cannot drift apart. That is checked in CI, not asserted.

Using it

charter init "Fix SQL injection in login()"   # derives the roster
charter status                                 # who signed off, who is outstanding

Then your agent runs the loop:

Order is red before green: QA proves the defect exists, the developer answers it, AppSec reviews the result. A reviewing role must run from its own charter session — charter refuses a review submitted by the process that produced the work.

What a role owes

Prose can be copied and faked. A contract cannot: charter validates the artifact, and refuses the sign-off when it does not hold.

RoleContractCharter rejects when
QAfailing_testruns the named test and rejects it unless it genuinely failsA test that passes is not evidence of a defect.
Developerchange_summaryrejects a summary citing files that do not existThe change has to point at real code.
AppSecthreat_entryrequires a CWE identifier and a concrete attack path“Consider validating input” has never stopped an exploit.

Three roles today, and more coming. These three shipped first because their contracts are the sharpest to check mechanically — a test either fails or it does not. Business Analyst, Architect and others are next, each with a contract of its own rather than a job title. The roster is plain YAML and it keeps growing.

The build record lives in .charter/ — human-readable, git-diffable, append-only. A session with no prior context resumes the build from those files alone, which is what makes a build survive across days and compaction.

What it proves, and what it does not

Charter stamps every server connection with an id the caller cannot set, records it on each sign-off, and refuses a review submitted from the same connection that produced the work.

That proves a sign-off came from a separate process, and that it carries its own checkable artifact. It does not prove independent reasoning. A server restart, an agent deliberately restarting it, or a person clicking through two sessions without reading all satisfy the mechanism.

The artifact contract carries the weight. Identity raises the cost of collapsing the roles; it does not make it impossible. Charter says this in its own status output, its skill and its README, because a governance tool that overstates its guarantee is the first thing that should not be trusted.

It was run against its own codebase. Twice.

A tool that governs code review is easy to demo and easy to fake. Both runs are published with the rejections left in.

3
defects found in charter itself
2
filed by roles the author did not control
121
tests, each guard verified by removing it

Both records: docs/self-audit. The governance trail of this repository, which charter was extracted from, is on the council page.

The roster keeps growing, and updates reach you

Charter ships with QA, Developer and AppSec because those three have the sharpest checkable contracts. The roster is not the product — the enforcement is. Roles are plain YAML, and the kernel enforces whatever they declare.

# src/charter/kernel/definitions/roles/architect.yaml
id: architect
name: Solutions Architect
contract: decision_record
evidence: tree
activates_on: [scrum, cicd]
brief: >-
  Owns the shape of the system across components. Suspicious of a decision
  record that lists only advantages.

New roles ship inside a released version, so you pick them up the same way you picked up charter — by updating the plugin. Nothing phones home to fetch them, and nothing executes a role definition you did not install: the library is read from the package on disk, which is why the roster can grow without becoming a remote-code channel.

uvx --refresh --from git+https://github.com/224Sand/charter charter --help

Fork it and the same applies to your own roster — a Legal reviewer on a fintech repo, a Localization lead on a multi-region product. Write the brief and the contract; the gates, the record and the independence check work unchanged.

Source

MIT. Fork it, add roles, point it at your own process — the role library is plain YAML and the kernel enforces whatever it declares.

github.com/224Sand/charter