Concepts · 2 of 7
Protocols and compositions
A protocol says what must be true. A composition says who, when and with which tools.
Governing engineering work takes two kinds of statement, and engineering protocols keep them apart.
- A protocol says what must be true before work counts, which evidence establishes it, which
actions exist and which of them need authority. It never names a person, a model, a tool or a
schedule. Engineering protocols are Canon
protocol/1documents. - A composition says, for one organization, who does the work, when a case opens and with which
tools: agents, triggers, policy, runtime bindings and projections. It never decides what counts as
done. A composition is its own document family,
composition/1(decision record 0087).
The split is what lets the same protocol run in another organization, with other people, other agents and other tools.
Shipped · runs today
- ShippedProtocols as Canon protocol/1 dataCanon validates, compiles and evaluates them; incident.response/1 is the first shipped engineering protocol.
Decided · recorded, not built
- DecidedTwo layers: protocol and compositionDecision record 0087.
- Decidedcomposition/1 as its own document familyRead by Commission, the intent router and the projector; none of them owns it. No format exists yet: its ESS domain comes first.
Planned · roadmap only
- PlannedTriggers in the compositionOpen: they may move to the intent router's own configuration.
- PlannedComposition validation and protocol pinningOpen: a composition may only reference capabilities its pinned protocols declare.
A protocol
incident.response/1 ships here. An excerpt: two claims, an urgent obligation, and the action
that leaves emergency mode once the service is healthy and the impact bounded, whatever is known of
the cause.
claims:
service.healthy:
true_when:
evidence: {kind: operational_observation, result: healthy, subject: service}
cause.identified:
true_when:
evidence: {kind: cause_analysis, result: identified}
obligations:
restore_service:
description: urgent; bring the affected service back to health
discharged_when: {claim: service.healthy, is: true}
actions:
release.rollback:
effect: write
requires:
- capability: release.rollback
emergency.leave:
precondition:
all:
- {claim: service.healthy, is: true}
- {claim: impact.bounded, is: true}
Nothing in it says who rolls back, which deployment tool does it, or who approves. The protocol only
says that release.rollback needs the capability release.rollback.
Protocol · revision 1
incident.response/1Respond to an incident through two obligations that progress independently: restore_service, on which emergency mode is left, and investigate_cause, which stays open after emergency mode ends until a cause analysis of a current revision of the service or the release identifies the cause. A rollback of the release is verified only on a complete rollback result from a verifier the case lists as another principal than the one who rolled it back. The service is healthy only on an observation at most 30 minutes old.
- Actions6
- Evidence kinds4
- Claims4
- Obligations2
- Precondition, traced on hover
- Needs authority
Hover or focus a node to trace what it rests on and what rests on it. Press Enter to pin it, Escape to clear.
Protocol as text
| Name | Description | Rule | Leads to |
|---|---|---|---|
emergency.leave | leave emergency mode; admissible once restore_service is discharged and the impact is bounded, whatever is known of the cause | all of claim impact.bounded claim service.healthy | — |
logs.search | search the system's logs | effect read | produces cause_analysis |
metrics.inspect | read the system's metrics | effect read | produces impact_assessment; produces operational_observation |
release.inspect | read what a release contains | effect read | produces cause_analysis |
release.rollback | return to a previous release | needs release.rollback effect write | produces rollback_result |
traffic.shift | move traffic between deployments | needs traffic.shift effect write | — |
More columns: swipe horizontally, or focus the table and use the arrow keys.
| Name | Description | Rule | Leads to |
|---|---|---|---|
cause_analysis | an analysis of why an incident happened | — | establishes cause.identified (identified) |
impact_assessment | an assessment of who and what an incident affects | — | establishes impact.bounded (bounded about service) |
operational_observation | an observation of the running system; its result is healthy or unhealthy, and it applies for 30 minutes after it is observed, after which it no longer says anything | — | establishes service.healthy (healthy about service) |
rollback_result | the result of returning a release to the one before it; its result is complete or partial | — | establishes rollback.verified (complete about release, independent on different_principal) |
More columns: swipe horizontally, or focus the table and use the arrow keys.
| Name | Description | Rule | Leads to |
|---|---|---|---|
cause.identified | the incident's cause is known | evidence = identified: cause_analysis | requires investigate_cause |
impact.bounded | the incident's impact is known and contained | evidence = bounded: impact_assessment | gates emergency.leave |
rollback.verified | the release's rollback is complete, by a rollback result from a producer the case lists as another principal than the one who rolled it back | evidence = complete: rollback_result | — |
service.healthy | the service is running healthily | evidence = healthy: operational_observation | requires restore_service; gates emergency.leave |
More columns: swipe horizontally, or focus the table and use the arrow keys.
| Name | Description | Rule | Leads to |
|---|---|---|---|
investigate_cause | establish why the incident happened; stays open after emergency mode ends until a cause analysis of a current revision of the service or the release identifies the cause | claim cause.identified | — |
restore_service | urgent; bring the affected service back to health | claim service.healthy | — |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Source: protocols/incident-response/1.yaml
A composition
There is no composition/1 format yet. The sketch below is illustrative: it shows the five sections
decision record 0087 names, for an organization running incident.response/1.
format: composition/1
id: example-operations
protocols: # pinned protocol sources
- els/incident.response@1
triggers: # what opens a case
- on: {event: alert.fired, where: {severity: page}}
open: {protocol: incident.response, subject: {service: $event.service}}
agents: # who takes which cases
responder:
executor: harness
model: example-model
takes: [incident.response]
policy: # capability → who, and how
release.rollback: {require_approval: [human:operator]}
traffic.shift: {require_approval: [human:operator]}
metrics.read: {allow: [agent:responder]}
bindings: # capability → data contract → connection
metrics.read: {contract: series/v1alpha1, connection: metrics-prod}
logs.read: {contract: logs/v1alpha1, connection: logs-prod}
projections: # where case state is mirrored
- from: incident.response
to: {connection: chat, channel: incidents}
| Section | Answers | Read by |
|---|---|---|
triggers | A schedule or an event opens a case of protocol X | the intent router |
agents | Executor, model, budget, and which protocols each takes | Commission |
policy | For each capability: allow, require approval or deny, per principal, plus limits | Commission |
bindings | Which connection implements a capability (Capabilities and bindings) | Commission |
projections | Where case state is mirrored, such as a tracker or a chat channel | the projector |
More columns: swipe horizontally, or focus the table and use the arrow keys.
A rule that today lives in prose, such as "only the operator decides" or "never force-push", lands in exactly one place: a protocol claim or outcome when it is about what counts, or a composition policy line when it is about who may act.