Understanding Charter: Synthesis, DRG, and Governed Context
This document explains the Charter synthesis model and the DRG-backed context system. For a practical walkthrough, see How Charter Works. For step-by-step how-to instructions, see How to Synthesize and Maintain Doctrine.
What the charter bundle is
The charter bundle is the machine-readable synthesis of your charter.md governance document.
It is not a simple copy of the prose — it is a structured set of YAML artifacts that the runtime
can traverse, merge, and inject as context for specific workflow actions.
The core bundle lives in .kittify/charter/ and consists of:
governance.yaml— testing, quality, performance, branch, and doctrine-selection configdirectives.yaml— extracted directive list with IDs, descriptions, and severitymetadata.yaml— bundle metadata: charter hash, last-sync timestamp, provenance
references.yaml, context-state.json, synthesis manifests, and provenance sidecars are also
Charter-era files, but they are outside the narrow CharterBundleManifest v1.0.0 core scope.
Why is the bundle needed rather than raw prose? Because the runtime context injection requires a
structured artifact. When spec-kitty next prepares a prompt for the implement action, it
needs to select the directives that apply specifically to implement (not to specify or
review). A flat prose document cannot serve that purpose efficiently. The bundle provides the
structure for action-scoped context injection.
How synthesis works
The synthesis pipeline has four logical phases:
Parse:
charter synthesizereadscharter.mdand the interview answers. It also reads any agent-generated YAML from.kittify/charter/generated/(artifacts the LLM harness has written).DRG edge computation: The synthesizer constructs the Directive Relationship Graph (DRG) by resolving typed relationships between actions, directives, tactics, procedures, profiles, templates, and glossary terms.
Directive resolution: With the DRG computed, the synthesizer determines which artifacts need to be generated or updated. Artifacts whose provenance points to unchanged inputs are left intact (this is what makes
charter resynthesize --topic <selector>work — only affected artifacts are regenerated).Promote artifacts: The synthesizer writes resolved artifacts to
.kittify/doctrine/(project-local doctrine) and records synthesis state under.kittify/charter/. The--dry-runflag stops after validation, before promotion.
The authoritative file throughout is always charter.md. The synthesizer reads it; it does not
write to it. Doctrine artifacts are outputs, not inputs.
DRG edge computation
The Directive Relationship Graph (DRG) is a directed graph with typed nodes such as actions, directives, tactics, procedures, profiles, templates, and glossary terms. Edges use these relations:
scope: action-to-artifact scopingrequires: hard dependencies between artifactssuggests: softer recommendations traversed to a bounded depthvocabulary: links from resolved artifacts to glossary scope/term contextinstantiates,replaces,delegates_to: additional graph relations used by specific doctrine surfaces
When the runtime prepares context for a specific mission action (e.g., implement), it traverses
the DRG from the action's entry node. It follows scope edges first, then transitive requires
edges, bounded-depth suggests edges, and one-hop vocabulary edges from the resolved nodes.
That keeps implementation prompts focused on implementation-relevant doctrine instead of
specification-phase concerns.
The DRG is not stored as a standalone file that you can inspect directly. It is computed by the synthesizer and manifests as the structured content of the bundle artifacts.
Bootstrap vs compact context
The DRG traversal for a given action can produce large payloads for complex governance structures. Two modes handle this:
Bootstrap mode: On the first load for an action (or after a fresh synthesis), the full relevant DRG subgraph is injected into the governed profile invocation. The agent sees all applicable directives, tactics, and glossary terms for its current action, plus the full doctrine library references.
Compact-context mode: When the DRG context payload exceeds the size threshold for inclusion, the runtime falls back to compact-context mode. In this mode, the agent receives only the resolved paradigm list, directive list, and tool list — without the full doctrine library text. This is a known limitation (see issue #787 in the project issue tracker; check that issue for current resolution status). Do not assume full-context behavior unconditionally on large governance layers.
First-load state is tracked per action in .kittify/charter/context-state.json. Each action
(specify, plan, implement, review) has an independent first-load timestamp.
Why the authoritative vs generated distinction matters
Charter governance is built on a strict read/write boundary:
- Authoritative policy source:
.kittify/charter/charter.md— human-edited, the source of truth for project governance policy. - Derived config and runtime state:
governance.yaml,directives.yaml,metadata.yaml,references.yaml,context-state.json, synthesis manifests, and provenance sidecars — owned by their respective CLI commands. - Project-local doctrine overlay:
.kittify/doctrine/— promoted bycharter synthesizeand read alongside shipped doctrine. - Agent-generated synthesis input:
.kittify/charter/generated/— written by the harness and validated bycharter synthesize.
If you edit a derived file (for example, add a directive to governance.yaml directly), the edit
can be lost on the next charter sync or charter generate run because those files are
re-derived from charter.md. There is no merge step for derived config.
charter status detects drift between charter.md and the bundle hash. charter lint detects
decay within the DRG (orphaned artifacts, contradictions, staleness). Both tools exist precisely
because the authoritative/generated boundary creates a risk of divergence if synthesis is not run
after charter edits.
Known limitations
Compact-context mode (issue #787): Large governance layers may trigger compact-context fallback, causing agents to receive summarized rather than full doctrine context. The workaround is to reduce governance scope or break the project into smaller governance domains.
Fresh-project synthesis: On a project where
.kittify/charter/generated/is missing or empty (no agent-generated artifacts),charter synthesizeproduces only the minimal artifact set (directory marker and PROVENANCE.md). The runtime falls back to shipped doctrine until a full synthesis run with agent-generated content completes.Synthesis requires
charter.md:charter synthesizewill exit non-zero ifcharter.mddoes not exist. Runcharter interviewandcharter generatefirst.