Charter#
Charter is a Jazz-native workspace for spec-driven development.
The invariant is intentionally blunt: the spec is the product surface, and Jazz is the coordination truth. Humans edit documents. Charter turns meaningful document changes, spans, comments, prompt changes, and agent lifecycle activity into project events, durable work items, consumer packets, and inspectable agent runs.
This repo's spec/ directory is Charter's own local Markdown projection. The database is the canonical coordination surface for sync, cursors, work queues, consumers, packets, provenance, optional APIs, future UI, and runners.
Current contents#
spec/- local filesystem projection of Charter's product spec.src/markdown.ts- Markdown/frontmatter parser.src/spec-files.ts-spec/**/*.mdscanner and import-plan builder.src/db/jazz.ts- default Charter database adapter; mutates Jazz CoValues and saves a local projection mirror.src/db/json.ts- local JSON projection adapter for tests/fallback (CHARTER_DB_ADAPTER=json).src/jazz/schema.ts- Jazz CoValue schema for the currently implemented database mapping.src/server.ts- shared runtime/watch helpers plus optional local HTTP inspection API/status page.src/cli.ts- CLI withwatch,serve,start,frontend,scan,index,search,changes,events,work,agent,queue,report,requests, andsynccommands.
Target product#
The desired first-class product command is:
charter watch
That starts the local runtime:
- watches
spec/**/*.md. - ingests filesystem edits into the Jazz-backed database.
- writes semantic project events and durable work items.
- matches registered consumer agents.
- emits structured JSONL terminal logs.
- runs agents as subordinate processes when invoked.
- records packets, reports, failures, stdout, stderr, and provenance.
A browser/editor UI is optional future surface. It is not the product center right now. The product center is the runtime, the database, the spec files, and the event stream.
Commands#
npm install
npm run watch
npm run scan
npm run index
npm run search -- agent runtime
npm run changes
npm run events
npm run work
npm run agent
npm run report -- --request <request-id> --status done --message "Implemented and checked."
npm run requests
npm run sync -- --dry-run
npm run sync
npm run sync -- --jazz-values
npm run check
npm test
After build, the binary is charter:
npm run build
node dist/src/cli.js scan
npm run watch starts the local runtime and emits structured JSONL logs while it ingests spec file changes. npm run serve is only an optional local HTTP inspection API/status page over the same state. npm run sync writes through the configured CharterDatabase. The CLI now defaults to JazzCharterDatabase: document rows, versions, project events, work items, registered consumers, and agent requests are mutated through Jazz CoValues. .spec/state/spec-db.json is a local projection mirror used for process bootstrap/debugging, not the active database adapter. npm run sync -- --jazz-values prints the active CoValue ids and writes .spec/state/jazz-values.json for inspection. npm run index writes .spec/state/index.json as a disposable local cache. npm run work lists durable work items derived from project events. npm run agent creates and optionally executes an agent request row from queued work items. npm run report is the agent-facing completion hook. npm run requests inspects request status, reports, exit codes, and captured output. Prompt files are only temporary runner compatibility exports when {promptFile} is used.
State files are ignored by git because they are adapter/cache artifacts, not the canonical coordination object.
Project spec#
Start with spec/index.md and spec/product-vision.md. Root README is operational. Product intent lives in database-backed spec documents; Markdown is the local projection in this repo.
Document identity#
A Markdown file may declare a stable id:
---
id: runtime-architecture
title: Runtime Architecture
kind: architecture
---
If id is omitted, the importer derives one from the relative file path without .md. Example: spec/runtime/architecture.md becomes runtime/architecture.
Pin id before renaming a spec file if the rename should preserve identity.
Watch loop#
The current default loop is:
- run
charter watchornpm run watch. - edit spec documents in Zed, Obsidian, or another filesystem editor.
- watch the runtime ingest changes and emit JSONL events.
- inspect projection changes, events, queue state, registered consumers, requests, and packets with CLI commands.
- create and run a consumer-scoped request packet with
charter agent next --exec ...when a subordinate runner should execute.
The manual CLI loop is still available:
- edit spec documents through Markdown, a database-native client, or another adapter.
- run
charter changesto see what changed against the current database state. - run
charter syncto accept projection edits into database state, append project events, and queue durable work items. - run
charter workorcharter queueto inspect queued work. - run
charter agentto create a database-backed agent request from queued work items. - run
charter agent --exec --agent-command <command>when a runner should actually execute. For Codex, usecodex exec -because Codex reads the prompt from stdin. - the agent calls
charter report --request "$CHARTER_REQUEST_ID" --status done|failed|blocked|ignored --message <summary>before exit. - run
charter requeststo inspect the structured report, exit code, stdout, and stderr captured from the run. - run
charter eventsto inspect the project event feed.
Agent context is attached through spec document ids, spans, comments, prompt documents, and packets. There is no separate memory primitive; durable context belongs in one or more spec documents or explicit activity/provenance objects. Completion is written back through Charter, not inferred from prose alone; stdout/stderr capture is the fallback audit trail.
Running agents#
Create work from spec changes:
npm run changes
npm run sync
npm run work
Inspect and run one queued work item at a time:
npm run queue
npm run queue -- next
npm run agent -- next --exec --letta-agent agent-0ddda04a-3d4c-410a-9fb7-d1940281a93f
queue shows only unclaimed queued work by default; use npm run work -- --all for the full ledger. queue next and agent next select the oldest queued item. Creating an agent request without --exec does not claim work; work moves to running only when the runner starts. Old planned claims remain explicit: inspect them with npm run queue -- next --status claimed or run one with npm run agent -- next --status claimed --exec ....
Run queued work with Codex instead:
npm run agent -- next --exec --agent-command 'codex exec -s workspace-write -'
The prompt is sent on stdin. Tools that need a file can use {promptFile} in the command string, but Codex does not support --prompt-file. Codex also needs a writable sandbox for tests/build caches; otherwise Vitest can fail before collecting tests because it cannot write temp/cache files. The Letta convenience runner uses {promptFile} internally as letta --agent <id> --new -p "$(cat {promptFile})".
Agent completion contract:
npm run report -- --request "$CHARTER_REQUEST_ID" --status done --message "Implemented the requested work and checks pass."
npm run report -- --request "$CHARTER_REQUEST_ID" --status failed --message "Failed because ..."
npm run report -- --request "$CHARTER_REQUEST_ID" --status blocked --message "Blocked because ..."
npm run report -- --request "$CHARTER_REQUEST_ID" --status ignored --message "Ignored because ..."
The runner captures stdout, stderr, and exit code automatically. An explicit report is canonical; captured output is the audit trail and fallback report when the agent exits without reporting.
Inspect runs:
npm run requests
npm run requests -- --request <request-id>
Jazz status#
The executable CLI path now uses JazzCharterDatabase by default. It upserts the same row shapes into CharterProject.documents, creates SpecDocumentVersion CoMaps, appends ProjectEvent entries into the CharterProject.events CoFeed, syncs mutable WorkItem CoMaps through CharterProject.workItems, and syncs AgentRequest CoMaps through CharterProject.requests.
The remaining gap is cross-process Jazz durability: this adapter starts an in-process Jazz account and uses the JSON projection mirror to bootstrap the next CLI process. The next step is wiring a worker account/sync server/storage configuration so the same CharterProject CoValue graph loads durably across processes and devices without the projection mirror doing bootstrap duty.