Applied Part 3. Project Constitution: First Rules Referendum
Status: Recommendation. Splitting immutable_principles and mutable_rules with explicit ttl, max_scope, rollback_condition is a stable practice. An automatic agents referendum with a deterministic tie-breaker rule is a frontier: its shape depends on the specific team and models.
For the learning pass it is enough to manually fill in constitution.md and verify that mutable rules have ttl, max_scope, and rollback_condition. An automatic referendum and an external arbiter belong to the full production track.
"Project constitution" here is a versioned set of invariants, mutable rules, and the amendment procedure. The set is verified before dangerous actions are performed.
One Word — Two Different Files
In the first volume, the project constitution is distributed across three files: mission.md (why we are doing this), tech-stack.md (what we are building on), roadmap.md (what and in what order). This contract describes the product.
In the second volume, under the same word, a fourth file appears — constitution.md. It describes not the product, but the safe-automation contour: which agent actions are forbidden, which are allowed with restrictions, who and how changes the rules. This is a layer on top, not a replacement. The first volume's files stay in place; constitution.md is added next to them and is read before any dangerous action.
If you want a one-line division: mission/tech-stack/roadmap answer the question "what we are building", constitution.md answers "what the agent is not allowed to do with it, even if it really wants to".
For the learning minimum, a small constitution.md with two immutable prohibitions and one mutable rule is sufficient. An agents referendum, an external arbiter, and automatic playbook verification are needed only for the full track. The chapter relies on part 6 of the first volume (where mission.md, tech-stack.md, roadmap.md come from) and part 18 (where the idea of SDD process safety comes from).
Before Reading
- Foundation from the first volume: part 6 introduces
mission.md,tech-stack.md,roadmap.md; part 18 explains SDD safety.
- Local learning case:
node_not_ready, because it clearly shows the difference between an allowed soft action and the prohibition of dangerous operations. - Trace for
capstone/: twoimmutable_principles, onemutable_rule, and a shortgovernance_protocolforhigh_memory_usage. - Key terms of the first pass:
immutable_principlesandmutable_rules. The third layer —governance_protocol— is reference material, needed only when the team introduces a voting rule. - What to postpone: the agents referendum, the external arbiter, and automatic playbook verification.
The reason for a separate production layer is simple: scenarios like node_not_ready or autoscale_200pct leave no time for chat. A dangerous action must either pass a formal gate or be blocked. We will deal with the safety of that gate in the foundation on part 18. SDD Safety. The connection to interacting with already running code is in part 13. Supporting an Existing Project.
Chapter Roadmap
The chapter is long, and you do not need to read it linearly. The map of movement:
- Minimal learning scenario. You fill in
constitution.mdby hand: two immutable prohibitions, one mutable rule with six fields. That is all that is needed to pass. - Key ideas. They explain why the minimum looks the way it does.
- Interview via Qwen Code. One way to speed up filling in
constitution.md. You can skip it on the first pass — manual filling also works. - Full track.
governance_protocol,change_log,decision_hash, referendum. Not required reading on the first pass: they become necessary when the team gets an automatic gate.
If you are reading for the first time, stop after the "Key Ideas" section and go do the exercise. Return to the full track after you close capstone/constitution.md with the minimal fragment.
Goal
By the end of the section you will have designed a working constitution.md for auto-remediation. Invariants and mutable norms will become clear, evolving through an agents referendum and fully traceable in the genealogy of edits.
What this gives in practice. The agent no longer acts on scattered hints. It checks every decision against a formal project contract. Such a contract helps speed up the response to recurring incidents, but does not turn speed into the right to automatically bypass backups, audit, blast-radius limits, and safe-rollback conditions.
Minimal Learning Scenario
Learning Case
For node_not_ready you need to allow a soft agent restart in the triage phase, but prohibit dangerous actions on the production database, backups, and audit. The goal is to get a small constitution.md that can be checked by eye before any production action.
Preparation
book2/examples/templates/proposal.md— the amendment form.- One list of dangerous actions that cannot be performed automatically.
- One recurring unknown pattern that can become a mutable rule.
For the first pass you can take this starter set:
dangerous_actions:
- delete_namespace
- restart_database
- bypass_audit_trace
candidate_mutable_rule:
incident_type: node_not_ready
pipeline_phase: triage
permitted_actions: ["soft_restart_agent"]
max_scope: "single_node"
ttl: "30d"
rollback_condition: "repeat_incidents_same_node>=2 or Safety veto"
If you adapt the chapter to your own project, replace the action names, but do not remove max_scope, ttl, and rollback_condition.
Steps
- Write down at least two
immutable_principlesas prohibitions, not advice. - Add one
mutable_rulewithincident_type,pipeline_phase,permitted_actions,max_scope,ttl,rollback_condition. - Describe
governance_protocol: roles, quorum, Safety veto, and the tie-breaker rule. - Fill in a short
proposal.md: why the rule appeared, who voted, when it activates, and how it rolls back. - Check the file with the question: "what action will the agent not be able to perform, even if it reduces MTTR?". *Expectation: the answer is in
immutable_principles, not in the chat.* - Compare with the runnable analogue from [
examples/spec-ci/](examples/spec-ci/README.md): the idea is the same — a verifiable gate must come before the action.
Checkpoint Fact
Every mutable rule has ttl, max_scope, and rollback_condition. If at least one field is missing, the rule is not admitted to the constitution and remains a proposal draft.
You can check the file with the same runnable analogue as in capstone/:
cd book2/examples/constitution
python3 scripts/check.py \
--constitution specs/constitution.yaml \
--proposal proposals/valid_proposal.md
You will get verdict: PASS. Then repeat with proposals/missing_evidence.md and proposals/conflict_with_immutable.md — you will get verdict: BLOCK with reasons. This is the learning gate before a dangerous action.
Transfer to high_memory_usage
The local case of the chapter is node_not_ready, but the graded one is high_memory_usage. The transfer is done with one line of a principle, not by copying the rule.
What to take from node_not_ready | What to write in capstone/constitution.md for high_memory_usage |
|---|---|
| immutable "do not close an incident without two OKs in a row" | immutable "do not close high_memory_usage without confirmation that RSS has returned below 80% twice in a row" |
mutable soft_restart_agent with ttl: 30d, max_scope: single_node | mutable restart_pod with ttl: 14d, max_scope: single_pod, rollback_condition: 5xx_increase OR memory_percent>=90% after 2 windows |
| Safety veto when expanding the radius | Safety veto when trying to expand restart_pod to the namespace |
If this line cannot be formulated, the local case has not yet yielded a transferable principle — return to it before moving to capstone/.
How This Gets Into capstone/
Transfer two immutable_principles, one mutable_rule, and a short governance_protocol to capstone/constitution.md. If you made a proposal.md, leave one line in capstone/README.md with the reason the rule appeared. Do not transfer the full agents referendum if it was not run.
Minimal fragment:
immutable_principles:
- "Do not perform auto-remediation without audit_trace."
- "Do not touch stateful workload without a confirmed backup."
mutable_rules:
- incident_type: high_memory_usage
pipeline_phase: recovery
permitted_actions: ["restart_pod"]
max_scope: "single_pod"
ttl: "14d"
rollback_condition: "memory_percent>=90% after 2 windows or 5xx increases"
governance_protocol: "Any expansion of max_scope requires a separate proposal."
Reviewable Trace
In the learning package, keep constitution.md together with proposal.md or a change_log record. An amendment without provenance is not considered part of production SDD.
Key Ideas
The first layer of constitution.md is immutable_principles. By immutable_principles (immutable principles) we mean rules that can never be disabled automatically. These include safety-level prohibitions and obligations:
- do not restart a production database without an up-to-date backup;
- do not delete backups to free up space;
- do not move an incident to
resolvedwithout confirmed stabilization; - do not perform a bypass in a security-critical namespace.
Formulate these norms as invariants, not as recommendations. They are the ones that constrain the agent at the moment of pressure, when the shortest path to reducing MTTR may create a larger cascade of failures.
The second layer is mutable_rules. These are mutable norms with an exact blast radius (unlike immutable_principles, such a rule can be cancelled or rewritten through a formal procedure). For each such rule, specify at least six fields. What they mean:
incident_type— the class of incident for which the rule is applicable;pipeline_phase— the response phase (triage,recovery, etc.);permitted_actions— the list of allowed actions;
max_scope— the blast-radius limit (for example,single_node);ttl(time to live) — the lifetime of the rule, after which it must be reviewed or extended;rollback_condition— the condition under which the rule is rolled back automatically.
Without these fields an amendment becomes too broad and starts competing with invariants. Compare the two variants.
Bad:
- id: node_not_ready_soft_restart
incident_type: "NodeNotReady"
permitted_actions: ["soft_restart_agent"]
Problem: no ttl, no max_scope, no rollback_condition. The rule is indefinite and has no radius bounds. Half a year later no one will review it anymore.
Good:
- id: node_not_ready_soft_restart
incident_type: "NodeNotReady"
pipeline_phase: "triage"
permitted_actions: ["soft_restart_agent"]
max_scope: "single_node"
ttl: "30d"
rollback_condition: "repeat_incidents_same_node>=2 or Safety veto"
For example, allow a soft restart for incident:NodeNotReady in the triage phase, but prohibit it for incident:DBWriteLag in the recovery phase. The same action in different contexts has a different risk to data and availability.
Stop for the First Pass
If you are here for the first time, by this point you already have everything for the chapter's pass: two immutable prohibitions, one mutable rule with six fields, an understanding of the difference between it and the first volume's mission/tech-stack/roadmap. What follows is the full track — governance_protocol, change_log, decision_hash, referendum. These mechanisms become necessary when the team gets an automatic gate and three or four human roles around it. They are not required for the graded capstone/constitution.md.
If your project does not yet have a single automatic action, go straight to the section "Artifacts and Readiness Criteria", and finish the full track after chapter 8 (there roles resurface in file arbitrage).
Full Track: governance_protocol
Make the evolution trigger observable: three or more repeated unpredictable incidents with one pattern_id trigger a mandatory referendum on the amendment. Such a threshold separates a single anomaly from a stable gap in the rules and does not allow the constitution to be changed after every noisy alert.
Fix the aggregation window, for example 48 hours. In the candidate amendment (the very proposal.md that is brought to the referendum) include:
- input events;
- the current
unknownclassification; - the assumed risk;
- the expected effect;
- the cancellation condition.
Why several roles are needed here at once, if in the first volume one person did the review. In part 16 of the first volume one reviewer was enough, because the subject of the review was feature code in the learning AgentClinic. The cost of a mistake is to redo the feature. In a production scenario the subjects of the review are different: an automatic dangerous action on a live service. The cost of a mistake is lost data, an expanded blast radius, a hidden closure of a P0. One reviewer cannot cope not because they are not smart enough, but because it is hard for a person to simultaneously keep in mind the correctness of the invariant, the applicability of the playbook, and the risk to production. Therefore the review is split across roles, each with its own narrow question. In minimal form these can still be three models of one agent, reading the same file in turn — but the questions are different.
Describe the voting procedure in governance_protocol. It includes agent roles, vote weights, quorum, convening time, and deterministic tie resolution. The minimum composition is three roles:
Verifierlooks for violations of invariants;Implementorassesses applicability in the playbook;Safetychecks the blast radius, privacy, and rollback conditions.
For adoption, set a quorum of two votes, the rule 2 approve + no Safety-veto, convening within 15 minutes of the trigger, and the tie-breaker rule safety-first. With such a tie-breaker, a critical risk from Safety always leads to rejection.
The fourth role, Coordinator, does not vote in governance_protocol. It appears at the next level — in file arbitrage (part 8), where it leads judgment.md and the order of rounds. Here, in the constitution, the Coordinator only records the voting outcome in change_log.
Record every update as an immutable trace, not as an edit without provenance. In the record include:
versionandparent_version— the current and previous versions of the constitution;reason— the reason for the amendment;votes— the voting results by role;
decision_hash— a cryptographic hash of the decision, by which it can be recomputed and verified later;incident_context— the events that triggered the trigger;activation_time— the moment from which the amendment is in effect;- a link to the diff inside the repository.
Such a log turns the history of edits into a chain of evidence. If later the question arises why the agent was allowed to perform an action, the answer will be found not in the team's chat, but in a reproducible genealogy of decisions.
Examples and Application
The basic structure of constitution.md can look like this:
immutable_principles:
- id: prod_db_no_restart_without_backup
rule: "Production database restart is forbidden unless a verified backup exists."
enforcement: "always_on"
- id: backups_are_protected_assets
rule: "Backup deletion, overwrite, or quarantine bypass cannot be executed automatically."
enforcement: "always_on"
mutable_rules:
- id: node_not_ready_soft_restart_triage
incident_type: "NodeNotReady"
pipeline_phase: "triage"
permitted_actions:
- "cordon_node"
- "soft_restart_agent"
max_scope: "single_node"
ttl: "30d"
rollback_condition: "increase in repeat incidents or Safety veto"
governance_protocol:
roles:
verifier:
vote_weight: 1
implementor:
vote_weight: 1
safety:
vote_weight: 1
veto: "critical_risk"
quorum: 2
pass_rule: "at_least_2_approve_and_no_safety_veto"
convene_after: "3_unknown_incidents_same_pattern"
convene_within: "15m"
tie_breaker: "safety_first_then_latest_matching_precedent"
change_log:
- version: "1.2.0"
parent_version: "1.1.0"
reason: "3 unknown NodeNotReady incidents in 48h"
votes:
verifier: "approve"
implementor: "approve"
safety: "abstain"
decision_hash: "sha256:..."
activation_time: "2026-05-17T12:00:00Z"
Connect the constitution to gate checks before executing a playbook, not after it. The order of steps is:
- a local script checks
immutable_principlesandmutable_rules; - Qwen Code in Plan Mode explains the risk and gaps;
- the executor gets the right to act.
The /constitution and /tasks commands are not built-in Qwen Code commands. If you need them, design them as project custom commands.
Interview via Qwen Code
Before writing constitution.md by hand, conduct the same interview as in part 6 of the first volume. The production layer adds two contours to the classic trio mission/tech-stack/roadmap, and these contours cannot be entered without explicit human decisions: which actions the agent is allowed to perform without confirmation, who gets the veto, what maximum blast radius is allowed in the triage phase.
Request:
/clear
We are expanding the AgentClinic-production constitution.
Look at @specs/mission.md, @specs/tech-stack.md, @specs/roadmap.md
and @specs/playbooks/node-not-ready.md.
Create a draft of @specs/constitution.md with three sections:
- immutable_principles
- mutable_rules
- governance_protocol
Before writing to disk, ask me exactly three grouped questions:
1. Which agent actions in production are always forbidden (backups, audit, secrets).
2. Which actions can be delegated in the triage phase with a blast-radius limit and a time to live (ttl).
3. Who votes, who has the veto, at what threshold the referendum is convened.
Do not write files yet. After my answers, show the change plan and wait for approval.
If Qwen Code immediately starts writing YAML without questions, stop it:
Stop. Do not write files before the interview.
First ask the three grouped questions, as specified in QWEN.md.
A good human answer to the interview contains decisions, not wishes:
Immutable principles:
No auto-restarts of the production database without a verified backup.
No automatic deletion of backups, audit, and secrets — even under pressure to free up space.
An incident does not move to resolved without two consecutive OKs.
Mutable rules:
In the triage phase for NodeNotReady, soft_restart_agent is allowed with max_scope=single_node and ttl=30d.
Rule rollback — on two repeat incidents on the same node or a Safety veto.
It is forbidden to expand max_scope without a referendum.
Governance:
Verifier, Implementor, Safety vote. Each vote is 1.
Quorum — 2 approves and no Safety veto.
The referendum is convened after three unknown incidents with one pattern_id in 48 hours.
The tie-breaker rule is safety_first.
Then ask Qwen to check its own draft:
Check @specs/constitution.md.
Find immutable rules formulated as recommendations.
Find mutable rules without ttl, max_scope, or rollback_condition.
Find governance_protocol without a tie-breaker rule.
Do not change the files, return the list of inconsistencies.
Typical mistakes at this step:
- an immutable rule is written as "avoid if possible" — that is a recommendation, not a prohibition;
- a mutable rule has no
rollback_condition, and on an incident it remains indefinite; governance_protocoldoes not describe the tie-breaker rule — on a tied score the system hangs;change_logis missing, and the very first change to the constitution loses its provenance.
Only after going through this list, fix the draft in your project. In the learning book2/, this step does not require git commands: what matters is a readable constitution.md with the rule's provenance.
> Constitution gate: runnable analogue and project interface. The runnable check lives in [examples/constitution/](examples/constitution/README.md) — it reads the constitution YAML and a Markdown with YAML frontmatter (the amendment proposal), returns verdict: PASS|BLOCK and a list of blockers. At the exam, that is enough. In a real project this gate is supplemented with two more steps: a query to Qwen Code in Plan Mode and a check of the playbook's max_scope against the rule's max_scope. All three steps go as one block.
# [runnable] — check the proposal against the constitution
python3 book2/examples/constitution/scripts/check.py \
--constitution book2/examples/constitution/specs/constitution.yaml \
--proposal book2/examples/constitution/proposals/valid_proposal.md
# [project script] — the same checks on your constitution and playbook
python3 scripts/constitution/check.py \
--constitution specs/constitution.yaml \
--proposal proposals/<your-proposal>.md
# [project script] — Qwen in Plan Mode, separate gate
qwen -p "Check @specs/constitution.yaml and @specs/playbooks/node-not-ready.md.
Mode: planning only. Say whether the remediation plan violates immutable_principles
and which mutable_rules are needed for admission." \
--approval-mode plan \
--output-format json \
> out/node-not-ready-constitution-review.json
flowchart TD A[Incident] --> B[Plan Mode and scripts against immutable] --> C[Check mutable rules] --> D[Admit / Block] --> E[Executed action] C --> F[Unknown incident] --> G[Unknown threshold reached] --> H[Forming proposal] --> I[Referendum] --> J[Commit] --> K[New constitution]
It is convenient to practice the referendum on a replay scenario. Three identical unknown incidents create proposal.md, agents vote, and the accepted amendment goes into change_log with a decision hash.
Example: a temporary rule hotfix_ticketing_flood may allow simplified ticket routing for 12 hours. The condition is a checkpoint and the preservation of the immutable prohibition on audit loss. After adoption, check that the amendment has not become indefinite. Make sure that ttl, rollback_condition, decision_hash, and activation_time are visible in the repository together with the change record.
Summary
constitution.md sets, for auto-remediation, the boundary between what the agent can adapt and what it has no right to disable for the sake of local optimization.
The roles of the layers in this boundary are:
- invariants protect backups, audit, data, and critical zones;
- the mutable layer allows refining playbooks for recurring incidents;
- the agents referendum makes the change of rules verifiable;
- the genealogy of edits preserves the reason, the votes, the decision hash, and the moment of activation.
Next, these norms will be tested in an LLM duel: Verifier vs Implementor.
Artifacts and Readiness Criteria
| Artifact | Ready when |
|---|---|
specs/constitution.md | immutable rules are formulated as prohibitions, not advice; from the file it is clear which action the agent will not be able to perform even to improve MTTR |
One mutable_rule | all six fields are filled in — incident_type, pipeline_phase, permitted_actions, max_scope, ttl, rollback_condition |
proposal.md or a record of the rule's provenance | the amendment has a reason for appearing, otherwise it is not part of the SDD package |
The full track adds several amendments with different blast radii, a change_log record with parent_version, votes, and decision_hash, and a project gate that checks the constitution before executing the playbook. Consider it ready if the gate actually blocks a violation of the immutable layer before execution, the referendum has a quorum, a Safety veto, and a deterministic tie-breaker, and the accepted amendment is traceable from incident context to diff.
Practice
- Open
book2/examples/templates/proposal.mdand fill it in for one dangerous domain (deployment, migrations, incidents, secrets): at least twoimmutable_principles(as prohibitions) and onemutable_rulewithincident_type,pipeline_phase,permitted_actions,max_scope,ttl,rollback_condition. Expectation: every mutable rule contains all six fields; the checkpoint fact from the learning scenario holds. - Write
governance_protocol: roles, quorum, Safety veto, and the tie-breaker rule; ask the question "what action will the agent not be able to perform, even if it reduces MTTR?". *Expectation: the answer is inimmutable_principles, not in the chat.*
- Transfer two
immutable_principles, onemutable_rule, and a shortgovernance_protocoltocapstone/constitution.md(the format is a fragment in the chapter's learning scenario); if you ranproposal.md, add one line tocapstone/README.mdwith the reason the rule appeared. Expectation: an amendment without provenance does not get into the SDD package.
Check Questions
- Which project rules should be immutable, and which should not?
- Why does a mutable rule need
ttl, and what will happen without it in a year? - What should happen on a Safety veto, and why can it not be bypassed with two
approves? - After three identical
NodeNotReadys in 48 hours the referendum trigger fired, but at that moment an active incident is underway. What will you do with the amendment — accept, postpone, or roll back the trigger?