--- id: data-model kind: architecture title: Data Model status: active --- # Data Model Charter's database model should make the spec workspace, event stream, consumer agents, packets, and provenance explicit in Jazz. The code currently implements the first core slice: project root, documents, versions, events, work items, registered agent consumers, durable agent packets, and agent requests. The target product still adds spans, comments, and richer activity records beyond the current request-prompt compatibility layer. ## CharterProject One root per repository or logical project. Current fields: - `projectId`: stable project identity. - `name`: display name. - `documents`: map of document id to current `SpecDocument`. - `versions`: map of version id to immutable `SpecDocumentVersion`. - `events`: Jazz CoFeed of append-only `ProjectEvent` entries. - `workItems`: map of mutable `WorkItem` CoMaps keyed by work item id. - `consumers`: map of consumer id to `AgentConsumer`. - `packets`: map of packet id to durable `WorkPacket` / `AgentPacket`. - `requests`: map of request id to database-backed `AgentRequest`. - `updatedAt`: last materialization time. Target fields: - `spans`: map of span id to `DocumentSpan`. - `comments`: map of comment id to `DocumentComment`. - `activity`: feed or map of `AgentActivity` records. ## SpecDocument Current materialized state for a spec document. Fields: - `id`: stable document id. - `path`: POSIX path relative to `spec/`. - `title`: frontmatter title or first H1 fallback. - `kind`: normalized broad category. - `status`: lifecycle state. - `body`: Markdown body without frontmatter. - `frontmatterJson`: normalized JSON string for frontmatter. - `headingsJson`: extracted heading outline. - `sha256`: content hash of the raw file or equivalent Markdown projection. - `sizeBytes`: raw content byte length. - `mtimeMs`: filesystem modification time when the source is a file. - `importedAt`: import timestamp. Target document rows should support rich editor state without losing Markdown projection. The minimal path can keep Markdown body as text. A richer path can add editor/co-rich-text state once the front end earns it. ## SpecDocumentVersion Immutable content snapshot keyed by document id and hash. Version rows let agents compare old and new requirements without pretending the current row is the whole history. The Jazz adapter creates a `SpecDocumentVersion` CoMap for each new `documentId:sha256` it sees and leaves prior versions addressable through `CharterProject.versions`. ## DocumentSpan A span points to a region inside a document. Fields: - `id`: stable span id. - `documentId`: target document. - `documentVersionId`: version or hash at creation time. - `startOffset` / `endOffset`: text offsets for the first version. - `anchorJson`: optional richer Markdown-aware anchor. - `quotedText`: text snapshot at creation time. - `status`: active, resolved, stale, archived. - `createdBy` / `createdAt`. Spans are how a user highlights part of a spec and asks Charter to do something with that exact region. ## DocumentComment A comment attaches to a document or span. Fields: - `id`. - `documentId`. - `spanId` when applicable. - `body`. - `kind`: comment, action-request, resolution-note. - `status`: open, resolved, archived. - `assignedConsumerId` when applicable. - `createdBy` / `createdAt` / `updatedAt`. Action comments should create project events and, when actionable, work items. ## ProjectEvent Append-only semantic event entry in the `CharterProject.events` CoFeed. Raw field-level provenance lives in Jazz edit history via `$jazz.getEdits()`; ProjectEvent is the agent/UI-facing classification layer over that history. Initial event types: - `spec.document.upserted` - `spec.document.deleted` - `spec.span.created` - `spec.comment.created` - `spec.comment.action_requested` - `consumer.registered` - `consumer.updated` - `agent.packet.created` - `agent.request.created` - `agent.request.executing` - `agent.request.executed` - `agent.request.failed` - `agent.request.blocked` - `agent.request.ignored` Authority values: - `human.file`: direct edit to a Markdown spec file. - `human.ui`: direct edit through the front end. - `importer.sync`: materialization from filesystem into database. - `agent.proposal`: agent-authored suggested change. - `agent.applied`: accepted agent change written back into the source spec. - `charter.agent`: agent request lifecycle activity. - `charter.system`: system classification, packet construction, or queue transition. A project event should carry source pointers: document id, span id, comment id, work item id, request id, source Jazz row id, and source field/path when available. ## WorkItem Mutable CoMap representing agent-consumable work derived from a project event. Fields: - `id`: stable work item id, usually derived from source event id. - `kind`: `spec-change`, `span-action`, `comment-action`, `agent-request`, or `manual`. - `status`: `queued`, `claimed`, `running`, `done`, `ignored`, `failed`, or `blocked`. - `eventId`: source event feed entry. - `documentId` / `path` / `title`: affected spec document. - `spanId` / `commentId` when applicable. - `matchedConsumerIds`: consumers eligible to handle the work. - `attachedDocumentIds`: spec documents supplied as agent context. - `sourceJazzRowId` / `sourceField`: Jazz provenance pointer when available. - `claimedBy` / `claimedAt`: worker claim metadata. - `requestId`: linked `AgentRequest` once running. - `resultText`: optional completion summary. ## AgentConsumer Database-registered consumer specification. Fields: - `id`. - `name`. - `status`: active, paused, archived. - `runnerKind`: Letta, Codex, Claude Code, script, CI, custom. - `runnerCommand`: optional default command or adapter command. - `runnerConfigJson`: non-secret runner configuration. - `eventTypes` / `eventTypesJson`: subscribed event types. - `documentSelectors` / `documentSelectorsJson`: subscribed document ids, folders, tags, or query selectors. - `promptDocumentIds` / `promptDocumentIdsJson`: prompt/spec documents composing behavior. - `defaultContextDocumentIds` / `defaultContextDocumentIdsJson`. - `cursorJson`: last seen event ids or timestamps. - `createdAt` / `updatedAt`. Secrets do not belong in the consumer row. Store references to secret names or host-side config, not credential material. Consumer registration is a write operation with a bounded response shape. Charter should return the created or updated `AgentConsumer`, the registration/update event id, any matched queued work item ids, and a match event count. Full snapshots belong to explicit inspection commands or read endpoints like `charter consumers`, `GET /api/project`, `GET /api/consumers`, and `GET /api/work-items`. When a consumer is registered after work already exists, Charter can rematch existing queued work by re-evaluating each queued work item's source event against that consumer's subscriptions. Rematching updates `matchedConsumerIds`; it does not recreate the source event or duplicate the work item. ## WorkPacket The exact packet handed to a consumer run. Fields: - `id`. - `consumerId`. - `requestId` when created for execution. - `workItemIds`. - `eventIds`. - `documentVersionIds`. - `affectedDocumentIds`. - `promptDocumentIds`. - `attachedDocumentIds`. - `documentVersionIds`: document id to content hash/version id for attached context. - `prompt`: rendered prompt for simple runner compatibility. - `promptSha256`. - `outputContract`. - `status`: planned, executing, executed, failed, blocked, or ignored. - raw output fields and result text after execution. - `createdAt` / `updatedAt`. Packets make runs inspectable and reproducible. The packet is not the whole world; it is the bounded work context Charter chose to hand over. ## AgentRequest Database-backed request for an implementation agent or other consumer runner. Fields: - `id`: stable request identity derived from the packet or prompt hash. - `status`: `planned`, `executing`, `executed`, `failed`, or `blocked`. - `createdAt` / `updatedAt`: lifecycle timestamps. - `requestedBy`: request authority, initially `charter.agent`. - `consumerId`: registered consumer handling the request. - `packetId`: linked packet. - `command`: optional runner command used for execution. - `changeIds`: spec document ids that changed. - `workItemIds`: durable work items attached to this request. - `attachedDocumentIds`: spec document ids attached as request context. - `prompt`: rendered runner prompt for simple runner compatibility. - `promptSha256`: prompt content hash. - `resultText`: optional runner summary. - `exitCode`: optional runner exit code. Agent context is document/span/comment attachment plus prompt documents. If an agent needs more durable context, attach or create spec documents rather than writing to a separate memory table. ## Agent output capture `AgentRequest` records should store both structured completion and raw execution output. Structured fields: - `status`: planned, executing, executed, failed, or blocked. - `reportStatus`: done, failed, blocked, ignored, or seen when explicitly reported by the consumer. - `resultText`: human-readable completion report. - `reportedAt`: explicit report timestamp. Raw audit fields: - `stdoutText` - `stderrText` - `outputText` - `exitCode` `WorkItem` records mirror the actionable status and report text so queue consumers do not need to inspect the parent request for common routing decisions. ## AgentActivity Agent activity is optional at first, but the model should have a place for it. Examples: - consumer saw event and chose no-op. - consumer constructed packet. - consumer requested more context. - consumer failed while resolving a span. - consumer produced a proposal. - selected reasoning trace or diagnostic was recorded. Activity records can enter the project event stream when they are meaningful to other consumers. They should not become a dumping ground for every token unless the UI has a reason to expose that much machine weather.