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.
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:
- nextCharter names the role. It returns that role’s brief, the artifact under review, and the contract owed — about a kilobyte, never a tour of your repository.
- workYour agent does the job with its own tools, in that role, and opens the cited files itself.
- submitCharter checks the evidence. Not the prose — it runs the test, resolves the paths, reads the CWE. Three failures escalate to you rather than looping.
- doneOnly when the defect actually stops. Charter re-runs the test QA filed before it will close a build.
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.
| Role | Contract | Charter rejects when |
|---|---|---|
| QA | failing_test | runs the named test and rejects it unless it genuinely failsA test that passes is not evidence of a defect. |
| Developer | change_summary | rejects a summary citing files that do not existThe change has to point at real code. |
| AppSec | threat_entry | requires 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.
- The first run did not finish. Charter refused a submission it could not verify, then refused a test that proved nothing. That rejection exposed a dependency bug that would have broken every fresh install, and its QA pass found a flaw in charter’s own loop ordering.
- The second run completed — three distinct connections, zero rejections — and its AppSec pass filed a CWE-94 against the change the developer had just written. The build closed with that finding accepted, because the contract requires a finding be produced, not that it be empty. It was fixed rather than shipped.
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.