charter-intent 0.4.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- charter_intent-0.4.2/LICENSE +21 -0
- charter_intent-0.4.2/MANIFEST.in +5 -0
- charter_intent-0.4.2/PKG-INFO +312 -0
- charter_intent-0.4.2/README.md +287 -0
- charter_intent-0.4.2/charter.py +1270 -0
- charter_intent-0.4.2/charter_intent.egg-info/PKG-INFO +312 -0
- charter_intent-0.4.2/charter_intent.egg-info/SOURCES.txt +14 -0
- charter_intent-0.4.2/charter_intent.egg-info/dependency_links.txt +1 -0
- charter_intent-0.4.2/charter_intent.egg-info/entry_points.txt +2 -0
- charter_intent-0.4.2/charter_intent.egg-info/top_level.txt +1 -0
- charter_intent-0.4.2/demo/ARCHITECTURE.md +23 -0
- charter_intent-0.4.2/demo/fake_annotator.py +30 -0
- charter_intent-0.4.2/demo/run_demo.sh +47 -0
- charter_intent-0.4.2/pyproject.toml +37 -0
- charter_intent-0.4.2/setup.cfg +4 -0
- charter_intent-0.4.2/tests/test_charter.py +614 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Charter contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: charter-intent
|
|
3
|
+
Version: 0.4.2
|
|
4
|
+
Summary: Executable design intent for AI-coded repos: the design document becomes the charter.
|
|
5
|
+
Author: cspergel
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/cspergel/Charter
|
|
8
|
+
Project-URL: Issues, https://github.com/cspergel/Charter/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/cspergel/Charter/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: ai-agents,governance,adr,traceability,claude-code,intent
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# charter — the design document becomes the charter
|
|
27
|
+
|
|
28
|
+
Your design doc says:
|
|
29
|
+
|
|
30
|
+
> Auth tokens are HMAC, never JWT.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
$ charter annotate SPEC.md # LLM turns prose into enforceable decisions
|
|
34
|
+
$ cat CHARTER.md
|
|
35
|
+
[D-001] Auth tokens are HMAC, never JWT -> assert: ! grep -rqE "jwt|jsonwebtoken" src
|
|
36
|
+
$ charter approve --why "initial review"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Weeks later, an AI agent adds JWT code.
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
$ charter check
|
|
43
|
+
FAIL D-001 "Auth tokens are HMAC, never JWT" — assert FAILED
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The agent fixes it. Nobody was interrupted, nothing was forgotten, and
|
|
47
|
+
`charter trace D-001` shows every file that implements the decision.
|
|
48
|
+
|
|
49
|
+
That's the whole idea: **executable design intent for AI-coded repos** —
|
|
50
|
+
ADRs + linter + traceability, in one file with almost no state.
|
|
51
|
+
|
|
52
|
+
The doctrine in one sentence: **a decision with no jurisdiction is not
|
|
53
|
+
governed.** Every decision names an enforcer; a supervise-only decision with
|
|
54
|
+
neither code citations nor an `@` watch scope fails check. CHARTER.md is the
|
|
55
|
+
constitution, `check` is the court, `audit` is the judge for gray areas, and
|
|
56
|
+
`[D-xxx]` citations are the map.
|
|
57
|
+
|
|
58
|
+
Try it in 30 seconds: `sh demo/run_demo.sh` (on Windows, run it from Git
|
|
59
|
+
Bash) — an agent adds Supabase to a local-first app and check catches it.
|
|
60
|
+
No API key needed.
|
|
61
|
+
|
|
62
|
+
## Quick start
|
|
63
|
+
|
|
64
|
+
See it work first — the demo is offline and needs no API key (on Windows,
|
|
65
|
+
run it from Git Bash):
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
git clone https://github.com/cspergel/Charter
|
|
69
|
+
cd Charter
|
|
70
|
+
sh demo/run_demo.sh # an agent adds Supabase to a local-first app; check catches it
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Then use it on your own repo. There are two ways to run it:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Option A — zero install. It's one file, zero dependencies (Python 3.10+).
|
|
77
|
+
python /path/to/charter.py check
|
|
78
|
+
|
|
79
|
+
# Option B — install the `charter` command.
|
|
80
|
+
pip install charter-intent # the command is `charter`; `charter` was taken on PyPI
|
|
81
|
+
# — or from a local checkout: pip install .
|
|
82
|
+
charter check
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`annotate` (turning a prose doc into decisions) needs an LLM backend; point it
|
|
86
|
+
at Claude Code with no API key required:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
export CHARTER_LLM_CMD="claude -p" # or set ANTHROPIC_API_KEY
|
|
90
|
+
charter annotate SPEC.md
|
|
91
|
+
charter approve --why "initial review"
|
|
92
|
+
charter check
|
|
93
|
+
charter doctor # checks your setup is sound
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
State on disk: `CHARTER.md` (yours), `.charter/ledger.jsonl` (append-only
|
|
97
|
+
journal), and `.charter/charter.sha` (approval hash — commit it). Permission to
|
|
98
|
+
*execute* asserts is recorded in a per-user trust store **outside** the repo
|
|
99
|
+
(`~/.charter/trust`, keyed by repo path), so nothing a repo ships can grant
|
|
100
|
+
itself execution.
|
|
101
|
+
|
|
102
|
+
## Security, in one paragraph
|
|
103
|
+
|
|
104
|
+
`charter check` executes shell commands defined in CHARTER.md (the assert
|
|
105
|
+
enforcers). A freshly cloned repo will **not** execute its asserts — even if it
|
|
106
|
+
ships an approval hash, and even if it ships a forged trust marker — until you
|
|
107
|
+
review CHARTER.md and run `charter approve` yourself, because the trust record
|
|
108
|
+
lives in a per-user store outside the repo. CI opts in explicitly with
|
|
109
|
+
`CHARTER_TRUST_ASSERTS=1`. `annotate`/`audit` send doc and file contents to
|
|
110
|
+
your configured LLM backend; nothing else makes network calls. Details and
|
|
111
|
+
threat model: [SECURITY.md](SECURITY.md).
|
|
112
|
+
|
|
113
|
+
## The lifecycle
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
charter annotate SPEC.md # LLM reads your prose doc, extracts binding
|
|
117
|
+
# decisions, assigns [D-xxx] symbols, proposes
|
|
118
|
+
# the lowest viable enforcer per decision,
|
|
119
|
+
# writes CHARTER.md + SPEC.annotated.md
|
|
120
|
+
# (charter init creates an empty CHARTER.md
|
|
121
|
+
# if you'd rather write it by hand)
|
|
122
|
+
<review CHARTER.md once> # the only mandatory human moment: adjust
|
|
123
|
+
# enforcers, strengthen supervise items
|
|
124
|
+
charter approve --why "..." # the human gate: journaled, hash-stamped
|
|
125
|
+
charter check # deterministic, free — pre-commit + CI
|
|
126
|
+
charter audit # judged pass over supervise-tier (PR-time)
|
|
127
|
+
charter digest [--mark] # batch-review everything the system did
|
|
128
|
+
charter trace D-001 # everything that traces to a decision
|
|
129
|
+
charter graph [--json] # the derived graph (Mermaid / machine-readable)
|
|
130
|
+
charter explain D-001 # the full story of one decision
|
|
131
|
+
charter doctor # setup-health checks
|
|
132
|
+
charter install-hook # pre-commit hook + Claude Code settings block
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## The line syntax
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
[D-001] title -> assert: <must-pass> !! <proof-must-succeed> @ glob, glob
|
|
139
|
+
[D-002] title -> supervise @ src/db/**
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
- The enforcer kind is one of the ladder below.
|
|
143
|
+
- `!!` introduces an assert's **tripwire**: a probe that must succeed,
|
|
144
|
+
proving the detector can detect a known violation sample (a typo'd grep
|
|
145
|
+
path can't pass forever). The canonical pattern is
|
|
146
|
+
`echo <violation-sample> | <the-real-detector>`.
|
|
147
|
+
- `@` declares **watch scope**: a human-set jurisdiction floor. Audit reads
|
|
148
|
+
cited files ∪ watched files, so an uncited violating file is still seen.
|
|
149
|
+
|
|
150
|
+
## The five layers
|
|
151
|
+
|
|
152
|
+
1. **Annotate** — the bootstrap agent. Extraction is conservative
|
|
153
|
+
(contracts, not preferences — "keep the code simple" is correctly
|
|
154
|
+
ignored), capped at 15 by default (`--cap N`), dedupes against decisions
|
|
155
|
+
already indexed, and annotation of your original doc is non-destructive
|
|
156
|
+
(writes a `.annotated` copy with symbols inlined at the source sentences).
|
|
157
|
+
2. **Enforce** — the ladder, strongest first: `structure > type > test >
|
|
158
|
+
lint > assert > supervise`. During review, push supervise items toward
|
|
159
|
+
the stronger deterministic rungs. `check` fails on: aspirational
|
|
160
|
+
decisions (no enforcer), missing enforcer targets, **enforcer rot** (the
|
|
161
|
+
`#Symbol` vanished in a refactor), failing asserts, and **blind
|
|
162
|
+
decisions** (supervise-only with no citations and no watch scope). A
|
|
163
|
+
proposed enforcer that doesn't exist yet is a **build obligation** —
|
|
164
|
+
check stays red until the builder creates the type/test, which is
|
|
165
|
+
governance generating the skeleton of the system. `check --budget N`
|
|
166
|
+
warns when judgment-only decisions outgrow the budget (default 5).
|
|
167
|
+
3. **Trace** — builders leave `[D-xxx]` citations in comments and commits.
|
|
168
|
+
The graph is **derived from grep on every run, never stored** — so it can
|
|
169
|
+
never go stale.
|
|
170
|
+
4. **Supervise** — `audit` judges only the supervise tier, and **citations
|
|
171
|
+
are the scope**: the auditor reads exactly the files that claim to
|
|
172
|
+
implement the decision, plus watched files. Verdicts: COMPLIES (ok line,
|
|
173
|
+
exit 0), VIOLATES (exit 1 — fix the code), AMBIGUOUS (flagged for digest
|
|
174
|
+
review). All verdicts land in the ledger. No backend configured →
|
|
175
|
+
everything AMBIGUOUS, never crashes.
|
|
176
|
+
5. **Steer** — one optional SessionStart hook injects the whole index
|
|
177
|
+
(~15 one-liners, a few hundred tokens, once per session) plus the
|
|
178
|
+
citation protocol. No gates: agents stay in their native loop — cite the
|
|
179
|
+
symbol, keep `check` green.
|
|
180
|
+
|
|
181
|
+
## LLM backends
|
|
182
|
+
|
|
183
|
+
Resolution order for `annotate` and `audit`:
|
|
184
|
+
|
|
185
|
+
1. `CHARTER_LLM_CMD` — any command that reads the prompt on stdin and
|
|
186
|
+
prints the reply on stdout. Point it at Claude Code headless:
|
|
187
|
+
`export CHARTER_LLM_CMD="claude -p"` — rides your existing plan.
|
|
188
|
+
2. `ANTHROPIC_API_KEY` — direct API (Sonnet for annotation quality, Haiku
|
|
189
|
+
for cheap audit verdicts; override with `CHARTER_ANNOTATE_MODEL` /
|
|
190
|
+
`CHARTER_AUDIT_MODEL`).
|
|
191
|
+
3. Neither — `annotate` explains itself; `audit` degrades to AMBIGUOUS.
|
|
192
|
+
|
|
193
|
+
## Integration
|
|
194
|
+
|
|
195
|
+
`.git/hooks/pre-commit` (or just run `charter install-hook`):
|
|
196
|
+
```bash
|
|
197
|
+
python charter.py check || exit 1
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
CI on PRs (the judged layer) — note the explicit opt-in, and treat PRs that
|
|
201
|
+
modify CHARTER.md like PRs that modify your CI workflows:
|
|
202
|
+
```bash
|
|
203
|
+
CHARTER_TRUST_ASSERTS=1 python charter.py check && python charter.py audit
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
`.claude/settings.json` (optional steering):
|
|
207
|
+
```json
|
|
208
|
+
{
|
|
209
|
+
"hooks": {
|
|
210
|
+
"SessionStart": [
|
|
211
|
+
{ "hooks": [ { "type": "command", "command": "python charter.py hook" } ] }
|
|
212
|
+
]
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
For non-hook agents (Cursor, aider), put this in `AGENTS.md`/`.cursorrules`:
|
|
218
|
+
|
|
219
|
+
> This repo's binding decisions live in CHARTER.md. When your work implements
|
|
220
|
+
> or touches a decision, leave its `[D-xxx]` symbol in a nearby comment and
|
|
221
|
+
> your commit message. Run `python charter.py check` before finishing; a
|
|
222
|
+
> failure means an enforcer caught a violation — fix the code, never the
|
|
223
|
+
> enforcer. Conflicts between a request and a decision must be surfaced, not
|
|
224
|
+
> silently resolved.
|
|
225
|
+
|
|
226
|
+
## Liberties taken, and why
|
|
227
|
+
|
|
228
|
+
- **Citations replace scope globs.** The derived graph defines what each
|
|
229
|
+
decision governs. This deleted the lockfile, ack protocol, session
|
|
230
|
+
baselines, and per-edit hooks of earlier designs — the single largest
|
|
231
|
+
overhead reduction — at the cost of relying on builders to cite. The
|
|
232
|
+
steering hook + agent instructions make citing the path of least
|
|
233
|
+
resistance, and `check` fails supervise decisions that end up blind.
|
|
234
|
+
- **Stateless judgment.** `audit` judges *current* state, not drift-since —
|
|
235
|
+
so there is nothing to pin, ack, or reconcile. Run it whenever; the ledger
|
|
236
|
+
is the only memory, and it's append-only and reviewable.
|
|
237
|
+
- **The graph navigates; enforcers govern.** `graph --json` exists for
|
|
238
|
+
agents to ask "what connects to what," but no verdict ever comes from
|
|
239
|
+
graph topology — authority lives in things that can't be argued with.
|
|
240
|
+
|
|
241
|
+
## FAQ
|
|
242
|
+
|
|
243
|
+
**Isn't this just a pre-commit hook that runs grep?**
|
|
244
|
+
At the deterministic layer, yes — and that's the point. A grep that can't be
|
|
245
|
+
argued with beats an LLM that can be talked out of a verdict. Charter's value
|
|
246
|
+
isn't a cleverer check; it's turning prose decisions into checks at all,
|
|
247
|
+
keeping them in sync with the code via citations, and proving the checks aren't
|
|
248
|
+
vacuous (tripwires). The grep is a feature, not an embarrassment.
|
|
249
|
+
|
|
250
|
+
**Why not Spec Kit / OpenSpec / Kiro?**
|
|
251
|
+
Those govern code *generation* — write a spec, then generate from it. They're
|
|
252
|
+
out of the loop the moment a later change quietly contradicts the original
|
|
253
|
+
design, which is where drift actually accrues. Charter governs the repo from
|
|
254
|
+
then on, on every commit. They compose: scaffold with whatever you like, keep
|
|
255
|
+
it true with Charter.
|
|
256
|
+
|
|
257
|
+
**An LLM wrote my enforcement rules — why would I trust that?**
|
|
258
|
+
You don't trust it — you review it. `annotate` only *proposes*; nothing takes
|
|
259
|
+
effect until you read CHARTER.md and `approve` it, exactly like reading code
|
|
260
|
+
you're about to run. At enforcement time there's no LLM in the loop: `check` is
|
|
261
|
+
deterministic shell. The model proposes, you ratify, grep decides.
|
|
262
|
+
|
|
263
|
+
**What stops an agent from editing CHARTER.md, or weakening an enforcer, to make
|
|
264
|
+
check pass?**
|
|
265
|
+
Any change to CHARTER.md fails `check` until a human runs `approve` (a hashed,
|
|
266
|
+
journaled gate) — so an agent can't quietly rewrite the constitution. The agent
|
|
267
|
+
instructions say *fix the code, never the enforcer*, and a weakened assert trips
|
|
268
|
+
its tripwire (the proof that it can still catch a known violation). Tampering is
|
|
269
|
+
visible, not silent.
|
|
270
|
+
|
|
271
|
+
**Won't grep-based asserts be brittle and false-positive?**
|
|
272
|
+
Some will — which is why the ladder exists. Push fragile checks up to `type`,
|
|
273
|
+
`test`, or `lint`, where the language and your test runner do the work; reserve
|
|
274
|
+
`assert` for things that genuinely are a grep. Tripwires flag asserts that have
|
|
275
|
+
quietly stopped detecting anything, so a brittle check fails loudly rather than
|
|
276
|
+
passing forever.
|
|
277
|
+
|
|
278
|
+
**Does it lock me into Claude?**
|
|
279
|
+
No. Any backend that reads a prompt on stdin works (`CHARTER_LLM_CMD`), the
|
|
280
|
+
Anthropic API works, and you can skip the LLM entirely and write CHARTER.md by
|
|
281
|
+
hand — `check` never calls a model.
|
|
282
|
+
|
|
283
|
+
## Known limits
|
|
284
|
+
|
|
285
|
+
- **`check` executes shell from CHARTER.md.** The trust gate means a cloned
|
|
286
|
+
repo can't run code on your machine before you review it, but after you
|
|
287
|
+
approve, the asserts are exactly as trustworthy as your review of them.
|
|
288
|
+
Read them like code you are about to run — because they are.
|
|
289
|
+
- A builder that never cites makes citation-only supervise decisions blind —
|
|
290
|
+
check fails them rather than letting them silently un-govern. Decisions
|
|
291
|
+
with `@` watch globs are still audited via watched files. Deterministic
|
|
292
|
+
rungs are immune — prefer them.
|
|
293
|
+
- Annotation quality is bounded by the doc: vague prose yields supervise
|
|
294
|
+
proposals. The review-once step is where you strengthen enforcers.
|
|
295
|
+
- `assert` commands are POSIX-shell; on Windows they run under Git Bash
|
|
296
|
+
(auto-detected, `CHARTER_SHELL` overrides).
|
|
297
|
+
- A vacuous assert's `!! proof` is authored by the same source as the
|
|
298
|
+
assert, so the tripwire raises the bar but can't fully self-police —
|
|
299
|
+
`check` flags trivially-true probes (`!! true`, bare `echo`), but a
|
|
300
|
+
cleverly matched fake proof still needs the human review-once gate.
|
|
301
|
+
- `audit` judges at most the first 60 in-scope files per decision (chunked,
|
|
302
|
+
worst-verdict-wins) to bound LLM cost; broad `@ src/**` scopes over huge
|
|
303
|
+
trees are reported as truncated. Narrow watch globs audit completely.
|
|
304
|
+
- `audit` sends in-scope file contents to the model, and a determined
|
|
305
|
+
prompt-injection in governed code can still influence a verdict —
|
|
306
|
+
deterministic rungs carry the real authority; `supervise`+`audit` is the
|
|
307
|
+
soft, advisory tier.
|
|
308
|
+
|
|
309
|
+
## History
|
|
310
|
+
|
|
311
|
+
See [CHANGELOG.md](CHANGELOG.md). Charter was previously named governor;
|
|
312
|
+
v0.4.0 renamed it and added the local trust gate.
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# charter — the design document becomes the charter
|
|
2
|
+
|
|
3
|
+
Your design doc says:
|
|
4
|
+
|
|
5
|
+
> Auth tokens are HMAC, never JWT.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
$ charter annotate SPEC.md # LLM turns prose into enforceable decisions
|
|
9
|
+
$ cat CHARTER.md
|
|
10
|
+
[D-001] Auth tokens are HMAC, never JWT -> assert: ! grep -rqE "jwt|jsonwebtoken" src
|
|
11
|
+
$ charter approve --why "initial review"
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Weeks later, an AI agent adds JWT code.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
$ charter check
|
|
18
|
+
FAIL D-001 "Auth tokens are HMAC, never JWT" — assert FAILED
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The agent fixes it. Nobody was interrupted, nothing was forgotten, and
|
|
22
|
+
`charter trace D-001` shows every file that implements the decision.
|
|
23
|
+
|
|
24
|
+
That's the whole idea: **executable design intent for AI-coded repos** —
|
|
25
|
+
ADRs + linter + traceability, in one file with almost no state.
|
|
26
|
+
|
|
27
|
+
The doctrine in one sentence: **a decision with no jurisdiction is not
|
|
28
|
+
governed.** Every decision names an enforcer; a supervise-only decision with
|
|
29
|
+
neither code citations nor an `@` watch scope fails check. CHARTER.md is the
|
|
30
|
+
constitution, `check` is the court, `audit` is the judge for gray areas, and
|
|
31
|
+
`[D-xxx]` citations are the map.
|
|
32
|
+
|
|
33
|
+
Try it in 30 seconds: `sh demo/run_demo.sh` (on Windows, run it from Git
|
|
34
|
+
Bash) — an agent adds Supabase to a local-first app and check catches it.
|
|
35
|
+
No API key needed.
|
|
36
|
+
|
|
37
|
+
## Quick start
|
|
38
|
+
|
|
39
|
+
See it work first — the demo is offline and needs no API key (on Windows,
|
|
40
|
+
run it from Git Bash):
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
git clone https://github.com/cspergel/Charter
|
|
44
|
+
cd Charter
|
|
45
|
+
sh demo/run_demo.sh # an agent adds Supabase to a local-first app; check catches it
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Then use it on your own repo. There are two ways to run it:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Option A — zero install. It's one file, zero dependencies (Python 3.10+).
|
|
52
|
+
python /path/to/charter.py check
|
|
53
|
+
|
|
54
|
+
# Option B — install the `charter` command.
|
|
55
|
+
pip install charter-intent # the command is `charter`; `charter` was taken on PyPI
|
|
56
|
+
# — or from a local checkout: pip install .
|
|
57
|
+
charter check
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`annotate` (turning a prose doc into decisions) needs an LLM backend; point it
|
|
61
|
+
at Claude Code with no API key required:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
export CHARTER_LLM_CMD="claude -p" # or set ANTHROPIC_API_KEY
|
|
65
|
+
charter annotate SPEC.md
|
|
66
|
+
charter approve --why "initial review"
|
|
67
|
+
charter check
|
|
68
|
+
charter doctor # checks your setup is sound
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
State on disk: `CHARTER.md` (yours), `.charter/ledger.jsonl` (append-only
|
|
72
|
+
journal), and `.charter/charter.sha` (approval hash — commit it). Permission to
|
|
73
|
+
*execute* asserts is recorded in a per-user trust store **outside** the repo
|
|
74
|
+
(`~/.charter/trust`, keyed by repo path), so nothing a repo ships can grant
|
|
75
|
+
itself execution.
|
|
76
|
+
|
|
77
|
+
## Security, in one paragraph
|
|
78
|
+
|
|
79
|
+
`charter check` executes shell commands defined in CHARTER.md (the assert
|
|
80
|
+
enforcers). A freshly cloned repo will **not** execute its asserts — even if it
|
|
81
|
+
ships an approval hash, and even if it ships a forged trust marker — until you
|
|
82
|
+
review CHARTER.md and run `charter approve` yourself, because the trust record
|
|
83
|
+
lives in a per-user store outside the repo. CI opts in explicitly with
|
|
84
|
+
`CHARTER_TRUST_ASSERTS=1`. `annotate`/`audit` send doc and file contents to
|
|
85
|
+
your configured LLM backend; nothing else makes network calls. Details and
|
|
86
|
+
threat model: [SECURITY.md](SECURITY.md).
|
|
87
|
+
|
|
88
|
+
## The lifecycle
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
charter annotate SPEC.md # LLM reads your prose doc, extracts binding
|
|
92
|
+
# decisions, assigns [D-xxx] symbols, proposes
|
|
93
|
+
# the lowest viable enforcer per decision,
|
|
94
|
+
# writes CHARTER.md + SPEC.annotated.md
|
|
95
|
+
# (charter init creates an empty CHARTER.md
|
|
96
|
+
# if you'd rather write it by hand)
|
|
97
|
+
<review CHARTER.md once> # the only mandatory human moment: adjust
|
|
98
|
+
# enforcers, strengthen supervise items
|
|
99
|
+
charter approve --why "..." # the human gate: journaled, hash-stamped
|
|
100
|
+
charter check # deterministic, free — pre-commit + CI
|
|
101
|
+
charter audit # judged pass over supervise-tier (PR-time)
|
|
102
|
+
charter digest [--mark] # batch-review everything the system did
|
|
103
|
+
charter trace D-001 # everything that traces to a decision
|
|
104
|
+
charter graph [--json] # the derived graph (Mermaid / machine-readable)
|
|
105
|
+
charter explain D-001 # the full story of one decision
|
|
106
|
+
charter doctor # setup-health checks
|
|
107
|
+
charter install-hook # pre-commit hook + Claude Code settings block
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## The line syntax
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
[D-001] title -> assert: <must-pass> !! <proof-must-succeed> @ glob, glob
|
|
114
|
+
[D-002] title -> supervise @ src/db/**
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- The enforcer kind is one of the ladder below.
|
|
118
|
+
- `!!` introduces an assert's **tripwire**: a probe that must succeed,
|
|
119
|
+
proving the detector can detect a known violation sample (a typo'd grep
|
|
120
|
+
path can't pass forever). The canonical pattern is
|
|
121
|
+
`echo <violation-sample> | <the-real-detector>`.
|
|
122
|
+
- `@` declares **watch scope**: a human-set jurisdiction floor. Audit reads
|
|
123
|
+
cited files ∪ watched files, so an uncited violating file is still seen.
|
|
124
|
+
|
|
125
|
+
## The five layers
|
|
126
|
+
|
|
127
|
+
1. **Annotate** — the bootstrap agent. Extraction is conservative
|
|
128
|
+
(contracts, not preferences — "keep the code simple" is correctly
|
|
129
|
+
ignored), capped at 15 by default (`--cap N`), dedupes against decisions
|
|
130
|
+
already indexed, and annotation of your original doc is non-destructive
|
|
131
|
+
(writes a `.annotated` copy with symbols inlined at the source sentences).
|
|
132
|
+
2. **Enforce** — the ladder, strongest first: `structure > type > test >
|
|
133
|
+
lint > assert > supervise`. During review, push supervise items toward
|
|
134
|
+
the stronger deterministic rungs. `check` fails on: aspirational
|
|
135
|
+
decisions (no enforcer), missing enforcer targets, **enforcer rot** (the
|
|
136
|
+
`#Symbol` vanished in a refactor), failing asserts, and **blind
|
|
137
|
+
decisions** (supervise-only with no citations and no watch scope). A
|
|
138
|
+
proposed enforcer that doesn't exist yet is a **build obligation** —
|
|
139
|
+
check stays red until the builder creates the type/test, which is
|
|
140
|
+
governance generating the skeleton of the system. `check --budget N`
|
|
141
|
+
warns when judgment-only decisions outgrow the budget (default 5).
|
|
142
|
+
3. **Trace** — builders leave `[D-xxx]` citations in comments and commits.
|
|
143
|
+
The graph is **derived from grep on every run, never stored** — so it can
|
|
144
|
+
never go stale.
|
|
145
|
+
4. **Supervise** — `audit` judges only the supervise tier, and **citations
|
|
146
|
+
are the scope**: the auditor reads exactly the files that claim to
|
|
147
|
+
implement the decision, plus watched files. Verdicts: COMPLIES (ok line,
|
|
148
|
+
exit 0), VIOLATES (exit 1 — fix the code), AMBIGUOUS (flagged for digest
|
|
149
|
+
review). All verdicts land in the ledger. No backend configured →
|
|
150
|
+
everything AMBIGUOUS, never crashes.
|
|
151
|
+
5. **Steer** — one optional SessionStart hook injects the whole index
|
|
152
|
+
(~15 one-liners, a few hundred tokens, once per session) plus the
|
|
153
|
+
citation protocol. No gates: agents stay in their native loop — cite the
|
|
154
|
+
symbol, keep `check` green.
|
|
155
|
+
|
|
156
|
+
## LLM backends
|
|
157
|
+
|
|
158
|
+
Resolution order for `annotate` and `audit`:
|
|
159
|
+
|
|
160
|
+
1. `CHARTER_LLM_CMD` — any command that reads the prompt on stdin and
|
|
161
|
+
prints the reply on stdout. Point it at Claude Code headless:
|
|
162
|
+
`export CHARTER_LLM_CMD="claude -p"` — rides your existing plan.
|
|
163
|
+
2. `ANTHROPIC_API_KEY` — direct API (Sonnet for annotation quality, Haiku
|
|
164
|
+
for cheap audit verdicts; override with `CHARTER_ANNOTATE_MODEL` /
|
|
165
|
+
`CHARTER_AUDIT_MODEL`).
|
|
166
|
+
3. Neither — `annotate` explains itself; `audit` degrades to AMBIGUOUS.
|
|
167
|
+
|
|
168
|
+
## Integration
|
|
169
|
+
|
|
170
|
+
`.git/hooks/pre-commit` (or just run `charter install-hook`):
|
|
171
|
+
```bash
|
|
172
|
+
python charter.py check || exit 1
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
CI on PRs (the judged layer) — note the explicit opt-in, and treat PRs that
|
|
176
|
+
modify CHARTER.md like PRs that modify your CI workflows:
|
|
177
|
+
```bash
|
|
178
|
+
CHARTER_TRUST_ASSERTS=1 python charter.py check && python charter.py audit
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
`.claude/settings.json` (optional steering):
|
|
182
|
+
```json
|
|
183
|
+
{
|
|
184
|
+
"hooks": {
|
|
185
|
+
"SessionStart": [
|
|
186
|
+
{ "hooks": [ { "type": "command", "command": "python charter.py hook" } ] }
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
For non-hook agents (Cursor, aider), put this in `AGENTS.md`/`.cursorrules`:
|
|
193
|
+
|
|
194
|
+
> This repo's binding decisions live in CHARTER.md. When your work implements
|
|
195
|
+
> or touches a decision, leave its `[D-xxx]` symbol in a nearby comment and
|
|
196
|
+
> your commit message. Run `python charter.py check` before finishing; a
|
|
197
|
+
> failure means an enforcer caught a violation — fix the code, never the
|
|
198
|
+
> enforcer. Conflicts between a request and a decision must be surfaced, not
|
|
199
|
+
> silently resolved.
|
|
200
|
+
|
|
201
|
+
## Liberties taken, and why
|
|
202
|
+
|
|
203
|
+
- **Citations replace scope globs.** The derived graph defines what each
|
|
204
|
+
decision governs. This deleted the lockfile, ack protocol, session
|
|
205
|
+
baselines, and per-edit hooks of earlier designs — the single largest
|
|
206
|
+
overhead reduction — at the cost of relying on builders to cite. The
|
|
207
|
+
steering hook + agent instructions make citing the path of least
|
|
208
|
+
resistance, and `check` fails supervise decisions that end up blind.
|
|
209
|
+
- **Stateless judgment.** `audit` judges *current* state, not drift-since —
|
|
210
|
+
so there is nothing to pin, ack, or reconcile. Run it whenever; the ledger
|
|
211
|
+
is the only memory, and it's append-only and reviewable.
|
|
212
|
+
- **The graph navigates; enforcers govern.** `graph --json` exists for
|
|
213
|
+
agents to ask "what connects to what," but no verdict ever comes from
|
|
214
|
+
graph topology — authority lives in things that can't be argued with.
|
|
215
|
+
|
|
216
|
+
## FAQ
|
|
217
|
+
|
|
218
|
+
**Isn't this just a pre-commit hook that runs grep?**
|
|
219
|
+
At the deterministic layer, yes — and that's the point. A grep that can't be
|
|
220
|
+
argued with beats an LLM that can be talked out of a verdict. Charter's value
|
|
221
|
+
isn't a cleverer check; it's turning prose decisions into checks at all,
|
|
222
|
+
keeping them in sync with the code via citations, and proving the checks aren't
|
|
223
|
+
vacuous (tripwires). The grep is a feature, not an embarrassment.
|
|
224
|
+
|
|
225
|
+
**Why not Spec Kit / OpenSpec / Kiro?**
|
|
226
|
+
Those govern code *generation* — write a spec, then generate from it. They're
|
|
227
|
+
out of the loop the moment a later change quietly contradicts the original
|
|
228
|
+
design, which is where drift actually accrues. Charter governs the repo from
|
|
229
|
+
then on, on every commit. They compose: scaffold with whatever you like, keep
|
|
230
|
+
it true with Charter.
|
|
231
|
+
|
|
232
|
+
**An LLM wrote my enforcement rules — why would I trust that?**
|
|
233
|
+
You don't trust it — you review it. `annotate` only *proposes*; nothing takes
|
|
234
|
+
effect until you read CHARTER.md and `approve` it, exactly like reading code
|
|
235
|
+
you're about to run. At enforcement time there's no LLM in the loop: `check` is
|
|
236
|
+
deterministic shell. The model proposes, you ratify, grep decides.
|
|
237
|
+
|
|
238
|
+
**What stops an agent from editing CHARTER.md, or weakening an enforcer, to make
|
|
239
|
+
check pass?**
|
|
240
|
+
Any change to CHARTER.md fails `check` until a human runs `approve` (a hashed,
|
|
241
|
+
journaled gate) — so an agent can't quietly rewrite the constitution. The agent
|
|
242
|
+
instructions say *fix the code, never the enforcer*, and a weakened assert trips
|
|
243
|
+
its tripwire (the proof that it can still catch a known violation). Tampering is
|
|
244
|
+
visible, not silent.
|
|
245
|
+
|
|
246
|
+
**Won't grep-based asserts be brittle and false-positive?**
|
|
247
|
+
Some will — which is why the ladder exists. Push fragile checks up to `type`,
|
|
248
|
+
`test`, or `lint`, where the language and your test runner do the work; reserve
|
|
249
|
+
`assert` for things that genuinely are a grep. Tripwires flag asserts that have
|
|
250
|
+
quietly stopped detecting anything, so a brittle check fails loudly rather than
|
|
251
|
+
passing forever.
|
|
252
|
+
|
|
253
|
+
**Does it lock me into Claude?**
|
|
254
|
+
No. Any backend that reads a prompt on stdin works (`CHARTER_LLM_CMD`), the
|
|
255
|
+
Anthropic API works, and you can skip the LLM entirely and write CHARTER.md by
|
|
256
|
+
hand — `check` never calls a model.
|
|
257
|
+
|
|
258
|
+
## Known limits
|
|
259
|
+
|
|
260
|
+
- **`check` executes shell from CHARTER.md.** The trust gate means a cloned
|
|
261
|
+
repo can't run code on your machine before you review it, but after you
|
|
262
|
+
approve, the asserts are exactly as trustworthy as your review of them.
|
|
263
|
+
Read them like code you are about to run — because they are.
|
|
264
|
+
- A builder that never cites makes citation-only supervise decisions blind —
|
|
265
|
+
check fails them rather than letting them silently un-govern. Decisions
|
|
266
|
+
with `@` watch globs are still audited via watched files. Deterministic
|
|
267
|
+
rungs are immune — prefer them.
|
|
268
|
+
- Annotation quality is bounded by the doc: vague prose yields supervise
|
|
269
|
+
proposals. The review-once step is where you strengthen enforcers.
|
|
270
|
+
- `assert` commands are POSIX-shell; on Windows they run under Git Bash
|
|
271
|
+
(auto-detected, `CHARTER_SHELL` overrides).
|
|
272
|
+
- A vacuous assert's `!! proof` is authored by the same source as the
|
|
273
|
+
assert, so the tripwire raises the bar but can't fully self-police —
|
|
274
|
+
`check` flags trivially-true probes (`!! true`, bare `echo`), but a
|
|
275
|
+
cleverly matched fake proof still needs the human review-once gate.
|
|
276
|
+
- `audit` judges at most the first 60 in-scope files per decision (chunked,
|
|
277
|
+
worst-verdict-wins) to bound LLM cost; broad `@ src/**` scopes over huge
|
|
278
|
+
trees are reported as truncated. Narrow watch globs audit completely.
|
|
279
|
+
- `audit` sends in-scope file contents to the model, and a determined
|
|
280
|
+
prompt-injection in governed code can still influence a verdict —
|
|
281
|
+
deterministic rungs carry the real authority; `supervise`+`audit` is the
|
|
282
|
+
soft, advisory tier.
|
|
283
|
+
|
|
284
|
+
## History
|
|
285
|
+
|
|
286
|
+
See [CHANGELOG.md](CHANGELOG.md). Charter was previously named governor;
|
|
287
|
+
v0.4.0 renamed it and added the local trust gate.
|