--- id: consumer-agents kind: architecture title: Consumer Agents status: active depends_on: - product-vision - data-model - work-queue - agent-runtime - document-interactions --- # Consumer Agents A Charter agent is a database-registered consumer over the project graph. The consumer model is deliberately small: subscribe to events, receive a packet, run code or a model, and report an outcome. This gives Charter agent-native behavior without turning every background process into a haunted intern with write access. ## Consumer registration A consumer registers with the database before it handles work. Registration fields should include: - consumer id. - display name. - status: active, paused, archived. - runner kind: Letta, Codex, Claude Code, local script, CI worker, or custom. - runner command or adapter reference. - subscribed event types. - subscribed document ids, folders, tags, or query selectors. - prompt document ids. - default context document ids. - max packet size or context budget. - created and updated timestamps. The basic consumer can say: consume all actionable project events. A documentation consumer can say: consume documentation folder events. A prompt-review consumer can say: consume prompt document changes. ## Current implementation slice The first runtime slice materializes a consumer registry in the local API and database snapshot. Implemented endpoints: - `GET /api/consumers` lists registered consumers. - `POST /api/consumers` creates or updates a consumer and returns a compact registration result, not the entire project snapshot. - `GET /api/consumers/:id` reads one consumer. - `PATCH /api/consumers/:id` updates one consumer. - `POST /api/consumers/:id/match-queued` rematches existing queued work against that consumer. - runner paths accept `consumerId`; when omitted, Charter picks the first active matched consumer for the selected work item. - `GET /api/packets`, `GET /api/packets/:id`, and `GET /api/requests/:id/packet` expose the durable packet created for a request. - Passing `exec: true` to runner paths executes the selected consumer as a subordinate process, captures stdout/stderr/exit code, updates the request and packet status, and mirrors the result onto the selected work items. Current consumer fields: `id`, `name`, `status`, `runnerKind`, `runnerCommand`, `runnerConfigJson`, `eventTypes`, `documentSelectors`, `promptDocumentIds`, `defaultContextDocumentIds`, `cursorJson`, `createdAt`, and `updatedAt`. Current packet fields: `id`, `status`, `consumerId`, `requestId`, `command`, `workItemIds`, `eventIds`, `affectedDocumentIds`, `promptDocumentIds`, `attachedDocumentIds`, `documentVersionIds`, `prompt`, `promptSha256`, `outputContract`, raw output fields, and timestamps. Consumer registration can optionally include `matchExistingQueuedWork: true`. When enabled, Charter immediately checks currently queued work items against the new or updated consumer subscription and adds the consumer id to matching work items. The same behavior is available explicitly through `POST /api/consumers/:id/match-queued` so registering the consumer and backfilling queued work are visible, repeatable operations rather than an invisible side effect. The registration response is intentionally small: consumer row, registration event id, matched work item ids, and match event count. Returning the full database snapshot from a write route is product theater disguised as convenience. Snapshot reads belong on explicit read routes. Still missing: cursor advancement, long-running/background execution, consumer-authored comments/spans, retry policy, and richer subscription queries. ## Subscriptions Subscriptions can be simple at first: - all project events. - a fixed list of event types. - one or more document ids. - path or folder prefixes. - manually created work items. - comments or span action requests assigned to the consumer. Later subscriptions can become query-shaped, but the first version should stay inspectable. A user should be able to answer why an agent saw an event without reverse-engineering a rules engine wearing a tiny cape. ## Context packets A work packet is the consumable unit handed to an agent. The proposed context-subscription model separates subscription, packet inclusion, and prompt residency so this contract remains usable across heterogeneous runners. See `context-subscriptions.md`. A packet should include: - packet id. - consumer id. - source event ids. - work item ids. - affected document ids. - selected document spans when applicable. - comment or user query text when applicable. - prompt document ids and their version ids. - attached context document ids and version ids. - current document versions for affected documents. - prior relevant agent activity, if requested. - expected output contract. The packet is what makes agent behavior reviewable. If an agent received context, Charter should be able to show that context to the user. ## Prompt documents Prompts are ordinary spec documents. A consumer can be composed from one or more prompt documents under a prompts folder or any other part of the spec. When a prompt document changes, that change creates a normal document event. Consumers that depend on the prompt should be invalidated, queued for review, or explicitly restarted depending on policy. This keeps prompts versioned, reviewable, and editable through the same workspace as the rest of the project. No secret second prompt system unless the product earns one. ## Consumer outcomes Every consumer run must report one of: - `seen`: the consumer observed the event and chose no action. - `done`: the consumer completed the requested work. - `failed`: the consumer tried and failed. - `blocked`: the consumer cannot continue without external input. - `ignored`: the event was intentionally not relevant. Failure and blocked outcomes should create follow-up events and, when appropriate, follow-up work items. A failed run is not dead terminal output. It is another object in the graph with provenance. ## Cascades A consumer may create new events, proposals, document edits, comments, or work items. That can trigger other consumers. Cascades must remain bounded and inspectable: - each generated object points to its source event or run. - each run has a packet and report. - each write has an authority. - retry loops need explicit limits. - no consumer should silently mutate documents outside its authority class. Charter should make automation feel powerful without making it feel like the office printer developed agency and a grudge.