Turn fuzzy intent into hardened, machine-readable specifications.
CHARTER is an upstream companion to acig that turns half-written GitHub issues, Slack threads, and "hey can you…" messages into versioned, machine-readable contracts that coding agents consume as specifications. Where acig verifies output after an agent finishes work, CHARTER hardens intent before the agent starts.
# macOS / Linux (arm64)
curl -sSL https://github.com/helloodokai/charter/releases/latest/download/charter_darwin_arm64.tar.gz \
| tar -xz -C /usr/local/bin charter
# Linux (amd64)
curl -sSL https://github.com/helloodokai/charter/releases/latest/download/charter_linux_amd64.tar.gz \
| tar -xz -C /usr/local/bin charter
# Homebrew
brew tap helloodokai/charter-tap
brew install charter
# Or build from source:
git clone https://github.com/helloodokai/charter.git
cd charter && make build && cp dist/charter /usr/local/bin/Set up your repo and draft your first charter:
# Initialize Charter in your repo
charter init
# Set your API key
export OLLAMA_API_KEY=your-key-here
# Just run it — you'll be prompted for your goal
charter draft
# Or pass your goal directly
charter draft "Add rate limiting to the public API"
# Or start from a GitHub issue
charter draft --issue https://github.com/your-org/your-repo/issues/42
# Or from a file
charter draft --from requirements.mdAfter drafting a charter, generate a spec for your coding agent:
# Generate an agent-consumable SPEC.md from the latest charter
charter spec
# Or write it to your project root for easy access
charter spec --out SPEC.mdCHARTER runs an interactive Socratic dialogue — it asks you one question per field, you answer in your own words, and the system progressively hardens the spec. Press Enter to skip a field, or type stop to end the interview early. When the dialogue finishes, a synthesis pass consolidates your answers and a counter-spec review flags ambiguities.
When the dialogue finishes, you get a charter YAML and a human-readable transcript in .charters/:
# .charters/ch-2026-05-04-a1b2c3.yaml
schema_version: "1"
id: ch-2026-05-04-a1b2c3
created_at: 2026-05-04T12:00:00Z
updated_at: 2026-05-04T12:08:00Z
authors:
- you
source:
type: github_issue
url: https://github.com/org/repo/issues/42
goal: Add a rate limiter to the public API
context: The API currently has no rate limiting and is vulnerable to abuse
non_goals:
- This charter does NOT change the authentication layer
- This charter does NOT add caching
acceptance_criteria:
- id: ac-1
statement: API returns 429 when rate limit is exceeded
verification: test
- id: ac-2
statement: Rate limits are configurable per route
verification: test
edge_cases:
- What happens when a burst exceeds the limit by 10x?
blast_radius:
files:
- src/api/**"
constraints:
performance:
- p99 latency must stay under 100ms
risk: medium
risk_rationale: Touches public API surface but scoped to one concern
status: ready
transcript_file: ch-2026-05-04-a1b2c3.transcript.md
spec_file: ch-2026-05-04-a1b2c3.spec.mdThe transcript (.transcript.md) is a full Markdown record of the Socratic dialogue — every question and answer, timestamped and labelled. It's useful for auditing how the charter was formed, and it feeds directly into spec generation.
The spec (.spec.md) is an agent-consumable specification generated from the charter + transcript (see charter spec below).
CHARTER uses Ollama Cloud as its primary LLM backend. Get an API key at ollama.com:
export OLLAMA_API_KEY=ollama-your-key-hereOptional — for the frontier counter-spec pass (recommended):
export ANTHROPIC_API_KEY=sk-ant-your-key-hereVerify your setup:
charter doctorcharter init
charter draft [goal] [--issue URL] [--from FILE] [--stdin] [--out PATH] [--non-interactive] [--turn-budget N] [--profile cloud|local] [--resume ID] [--no-transcript]
charter spec [charter-id] [--out PATH] [--profile cloud|local]
charter validate <charter.yaml>
charter conformance <charter.yaml> --diff REF..REF [--format json|md|both] [--out PATH]
charter ls [--status draft|ready|approved|archived]
charter approve <charter.yaml>
charter schema
charter doctor
charter app serve [--addr :8080]
Initialize a repo for Charter. Creates .charter.toml with sensible defaults and a .charters/ directory. Safe to re-run — won't overwrite an existing config.
The workhorse. Starts an interactive Socratic dialogue to produce a charter.
If no source is provided, you'll be prompted to describe your goal.
| Flag | Description |
|---|---|
[goal] |
Describe what you want to build (positional arg) |
--issue URL |
Source from a GitHub issue |
--from FILE |
Source from a local file |
--stdin |
Source from stdin |
--out PATH |
Output path (defaults to .charters/<id>.yaml) |
--non-interactive |
Run in CI mode without interactive prompts |
--turn-budget N |
Override default turn budget (default: 8) |
--profile cloud|local |
Model profile to use |
--resume ID |
Resume an interrupted dialogue |
--no-transcript |
Omit transcript from output (no .transcript.md saved) |
The killer feature. Generates a complete, unambiguous SPEC.md that an autonomous coding agent can execute without any additional human context.
# Generate a spec from the most recent charter
charter spec
# Generate a spec from a specific charter
charter spec ch-2026-05-04-abc123
# Write to a custom path (e.g. your project root)
charter spec --out SPEC.mdThe spec is produced by synthesizing the charter YAML together with the Socratic dialogue transcript, so it captures nuances and clarifications that the structured fields alone might miss. It uses the Frontier-tier model for the highest quality output.
The spec includes:
- Overview — what and why, in the human's own words
- Functional Requirements — numbered, using RFC 2119 language (MUST/SHOULD/MAY)
- Non-Functional Requirements — performance, security, compatibility constraints
- Acceptance Criteria — each with a pass/fail verification method
- Scope — explicit in-scope and out-of-scope boundaries
- Boundaries — affected files, services, and data
- Edge Cases — with expected behavior
- Open Questions — blocking status and resolution needs
- Risk Assessment — level, rationale, rollback plan
- Counter-Spec Resolution — how ambiguities are resolved in this spec
The spec is saved as .charters/<id>.spec.md and referenced from the charter's spec_file field.
| Flag | Description |
|---|---|
[charter-id] |
Charter to generate spec from (defaults to most recent) |
--out PATH |
Write spec to a custom path |
Checks a charter for completeness and internal consistency. Reports field-level errors with helpful messages. Exit code 0 = valid, 1 = issues found.
Grades a git diff against a charter. Produces structured findings in the same format acig consumes, so integration is seamless:
charter conformance .charters/ch-2026-05-04-abc123.yaml --diff main..featureGraders:
- Goal alignment — does the diff implement the goal?
- Acceptance criteria coverage — are all criteria met?
- Non-goal violations — does the diff touch excluded areas?
- Blast radius compliance — does the diff stay within declared paths?
- Unknown gating — any blocking unknowns block conformance
Transitions a charter from ready to approved. Approved charters are immutable — they represent a contract.
List charters, optionally filtered by status.
Emit the JSON schema for charter.yaml. Useful for IDE integration and validation tooling.
Check backend reachability and configuration. Verifies API keys and connectivity to all configured LLM backends.
CHARTER can run as a GitHub App that automates the dialogue inside issue threads.
# .github/workflows/charter.yml or your app environment
secrets:
OLLAMA_API_KEY: ${{ secrets.OLLAMA_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} # optional
GITHUB_APP_ID: ${{ secrets.CHARTER_APP_ID }}
GITHUB_APP_PRIVATE_KEY: ${{ secrets.CHARTER_APP_PRIVATE_KEY }}charter app serve --addr :8080The app listens for issues webhooks. When an issue is labeled needs-charter, it starts a dialogue in the issue thread. When the dialogue completes, it opens a PR with the charter file and tags the issue with has-charter.
The reusable workflow at .github/workflows/charter.yml runs charter draft --issue <url> --non-interactive when an issue is labeled needs-charter. It creates a PR with the draft charter for human review.
CHARTER and acig are siblings in the same pipeline:
Issue ──► CHARTER ──► charter.yaml + spec.md ──► Agent ──► PR ──► acig
(harden) (contract + spec) (code) (diff) (verify)
In acig, reference a charter in your PR body or commit message:
Charter: .charters/ch-2026-05-04-abc123.yaml
acig loads the charter, runs charter conformance, and merges the findings into its verdict.
The schema is versioned (schema_version: "1"). Key fields:
| Field | Description |
|---|---|
id |
Human-friendly ID: ch-YYYY-MM-<hex> |
goal |
One-sentence statement of intent |
context |
Background an agent needs |
non_goals |
Explicit scope exclusions |
acceptance_criteria |
Testable conditions for success |
edge_cases |
Scenarios the agent must handle |
constraints |
Performance, security, compatibility, style, dependency limits |
blast_radius |
Files, services, data stores the change may touch |
unknowns |
Open questions (blocking or not) |
counter_spec |
Ways an agent could misinterpret the goal |
risk |
low / medium / high / critical |
status |
draft / ready / approved / archived |
transcript_file |
Path to the .transcript.md dialogue record |
spec_file |
Path to the generated .spec.md agent specification |
If you're building an agent that reads charter.yaml, here's what to focus on:
goalis the single source of truth. Everything else elaborates on it.non_goalsare hard constraints. If your diff touches areas listed here, conformance will fail.acceptance_criteriaare your test plan. Each criterion has averificationmethod (test, manual, or metric).blast_radiusdefines your allowed scope. Stay within it.unknownswithblocking: truemust be resolved before work starts.counter_specdocuments known misinterpretation risks — read these before starting.constraintsare non-negotiable. Violating them fails conformance.- If
spec_fileis set, read the.spec.mdfile — it contains the full agent-consumable specification with resolved ambiguities, RFC 2119 language, and testable requirements. It's more detailed and less ambiguous than the charter YAML alone. - If
transcript_fileis set, the.transcript.mdfile contains the original Socratic dialogue. Use it for context on intent, but the spec file takes precedence.
The JSON schema is available at schema/charter.schema.json or via charter schema.
Create .charter.toml in your repo root (optional, sensible defaults exist):
[dialogue]
turn_budget = 8
ask_for_rollback_at = "high"
require_counter_spec = true
[storage]
charters_dir = ".charters"
[models]
default_profile = "cloud"
fallback_to_local = true
[models.profiles.cloud]
cheap = { provider = "ollama_cloud", name = "gpt-oss:20b" }
mid = { provider = "ollama_cloud", name = "qwen3-coder:480b" }
frontier = { provider = "anthropic", name = "claude-sonnet-4-6" }
[models.profiles.local]
cheap = { provider = "ollama_local", name = "qwen2.5-coder:7b" }
mid = { provider = "ollama_local", name = "qwen2.5-coder:32b" }
frontier = { provider = "anthropic", name = "claude-sonnet-4-6" }
[models.ollama_cloud]
host = "https://ollama.com"
api_key = "${OLLAMA_API_KEY}"
[github]
app_id_env = "GITHUB_APP_ID"
private_key_env = "GITHUB_APP_PRIVATE_KEY"
needs_label = "needs-charter"
has_label = "has-charter"
[paths]
critical = ["src/auth/**", "src/payments/**", "migrations/**"]Charters touching paths.critical are auto-bumped to at least risk = high, which forces a rollback plan.
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Validation/conformance issues found, non-blocking |
| 2 | Charter rejected (incomplete, or diff materially violates charter) |
| ≥10 | Tool error |
git clone https://github.com/helloodokai/charter.git
cd charter
make buildRun tests:
make test
make vet
make lint # requires golangci-lintMIT

