What the graph models
A traditional architecture model says what contains what. An Architecture Graph says what the parts mean to each other: who owns a responsibility, which part is authoritative for a shared meaning, which contracts hold at a boundary, and what must not be silently changed.
The examples on this page are taken from the task-manager example and use the real authored format, so you can copy them into a graph that ag validate accepts.
Meaning, not structure
Folder layouts, package diagrams and call graphs already describe structure, and a coding agent can read them from the code. What the code does not say is intent: that the task service is the only part allowed to change a task, that reminders depend on an event announced only after a change is saved, or that how repeating tasks are stored is still undecided. Those are the facts that keep a change from quietly breaking something elsewhere, and they are what the graph records.
The node kinds
Each node has a kind, a name, a description, a status and references to the files that support it. The kinds fall into six roles.
- Who takes part
actorPeople, teams or outside systems that use or act on the software.- Where behavior lives
componentsurfaceadaptertransformParts of the software that run: services and modules, the surfaces people use, adapters to other systems, and steps that turn one thing into another.- What the system does
capabilityworkflowResponsibilities and the sequences of work that deliver them.- What crosses boundaries
contractartifactdata_objectObligations between parts, such as an event or API response, and the files and data shapes they exchange.- The rules
boundarypolicyconstraintWhat must stay true: who may change what, and the limits every change has to respect.- The record of design thinking
decisionevidence_surfaceChoices made and questions still open, and where evidence about the design is recorded. An evidence surface names a concept; it does not run or certify anything.
Component and capability
A component is structure: where behavior lives. A capability is a responsibility: what the system does. Keeping them apart lets the graph say which component owns a responsibility, and lets that answer change when code moves without rewriting what the system does.
nodes:
- id: component:task-service
kind: component
name: Task service
description: The only writer of task state. Validates and saves changes, then announces each saved
change as a task-changed event.
status: proposed
references:
- kind: design
path: requirements.md
module: module:tasks
- id: capability:manage-tasks
kind: capability
name: Manage tasks
description: Create, read, update, complete, reopen and delete tasks and lists.
status: proposed
references:
- kind: design
path: requirements.md
module: module:tasks
relationships:
- id: relationship:task-service-owns
kind: owns
from: component:task-service
to: capability:manage-tasks
description: The task service owns task management.
status: proposed
references:
- kind: design
path: requirements.md
Relationships that carry meaning
Every relationship has a kind and a description that says why the connection matters. These carry the most meaning:
owns- An actor, component or capability is responsible for an idea. Each idea has at most one declared owner, and ownership has no cycles.
authority_for- Decides what a capability, contract or artifact means. Others preserve that meaning instead of keeping their own copy. At most one authority per idea.
provides- A component, surface or transform supplies a capability to the rest of the system.
consumes- An idea relies on another, typically a contract. The description says what it does with it.
preserves- An idea keeps a contract or artifact intact: the guarantee a change must not break.
constrained_by- An idea must respect a boundary, contract or policy.
Ownership and authority are checked for conflicts because they answer the question a change most needs answered: which part decides. Two declared owners, or two authorities for the same contract, means nobody can tell which one a change should follow. Competing proposals can still be recorded as unresolved alternatives until one is chosen.
relationships:
- id: relationship:task-changed-authority
kind: authority_for
from: component:task-service
to: contract:task-changed
description: Defines the event announced after each saved change.
status: proposed
references:
- kind: design
path: requirements.md
- id: relationship:task-changed-after-commit
kind: preserves
from: component:task-service
to: contract:task-changed
description: Publishes only after saving, with a unique event ID per change.
status: proposed
references:
- kind: design
path: requirements.md
- id: relationship:scheduler-task-changes
kind: consumes
from: component:reminder-scheduler
to: contract:task-changed
description: Schedules, moves or cancels reminders when due times change or tasks are completed.
status: proposed
references:
- kind: design
path: requirements.md
- id: relationship:scheduler-task-authority
kind: constrained_by
from: component:reminder-scheduler
to: boundary:task-state-authority
description: Never writes task state directly, even when snoozing.
status: proposed
references:
- kind: design
path: requirements.md
Other kinds such as depends_on, produces, governed_by and affects are described in the reference.
Status as honesty
Every node and relationship says how sure it is:
proposed: intended design; nothing is claimed about the code.implemented: the author says it is built, and references a real implementation file.unresolved: a question or alternative is still open.
An open question stays visible instead of being guessed. When an agent reaches an unresolved decision, the right move is to leave it alone or ask, not to settle it as a side effect of another change.
nodes:
- id: decision:events-after-commit
kind: decision
name: Announce changes only after saving
description: "Chosen: task-changed events are published after the change is durably saved, so no
consumer reacts to a change that was rolled back."
status: proposed
references:
- kind: design
path: requirements.md
module: module:tasks
- id: decision:recurrence-model
kind: decision
name: How are repeating tasks stored?
description: "Open: one record whose due time moves forward on completion, or one record per
occurrence. This changes the task shape, history and how reminders are scheduled."
status: unresolved
references:
- kind: design
path: requirements.md
module: module:tasks
Modules and contracts
Modules are logical boundaries inside one graph. Each lists the nodes it exports to other modules and the nodes it imports from them; a relationship that crosses modules must match those lists, so every dependency between modules is visible and reviewable. Modules do not have to match packages or folders.
Contract sidecars show the data crossing a boundary: a contract can reference a JSON Schema and example payloads, and validation checks that the examples match the schema. That shows the files agree with each other, not that the code sends that data. Sidecars arrive in the next release.
nodes:
- id: contract:task-changed
kind: contract
name: Task changed
description: Announced after a change is saved, never before. Carries the task after the change. May
be delivered more than once, so consumers ignore events they have already seen.
status: proposed
references:
- kind: design
path: requirements.md
- kind: schema
path: contracts/task-changed.schema.json
- kind: example
path: contracts/examples/task-changed.json
module: module:tasks
modules:
- id: module:notifications
name: Notifications
description: Delivers push and email notifications.
exports: []
imports:
- contract:reminder-due
- contract:task-changed
Why this helps agents
A coding agent starts each session without the history behind the code. Without a blueprint, it re-derives intent from whatever files it happens to read, and an assumption that looks reasonable locally can break a guarantee another part relies on. The graph gives it a compact, authoritative starting point: ag context returns the owners, consumers, rules and open questions around the code it is about to change, within a fixed size limit. After the change, the agent updates the graph, so the next session starts from the current design instead of rediscovering it.