From b6df1d16647a8ff9d933e4dac78756dcce8c8711 Mon Sep 17 00:00:00 2001 From: Jorge Vidaurre Date: Sat, 25 Apr 2026 21:39:32 -0400 Subject: [PATCH 1/2] feat(governance): block agent edits to goals/priorities/directives MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Agents now cannot Edit/Write/MultiEdit governance files. Today the authority rule is documented as convention but unenforced — agents have been observed resetting goals to fit their own logic and contradicting directives. Drift accumulates over runs. Layer 1 of the governance epic (#764): - templates/guardrail.json: PreToolUse matcher for Edit|Write|MultiEdit blocks paths matching */goals.md, */priorities.md, */directives.md, */SQUAD.md. Exit code 2 with a clear message redirecting to the proposal channel. - templates/proposed/README.md: documents the proposal channel pattern. Agents write suggestions to .squads/proposed/--.md; founder reviews and merges accepted ones into canonical files. - docs/governance.md: authority-by-file table, why the split, how enforcement works, founder override. The founder's own Claude Code sessions don't pass through the agent guardrail, so direct edits work normally for governance owners. Tested locally: hook blocks goals.md (exit 2), allows state.md (exit 0). Co-Authored-By: Claude --- docs/governance.md | 49 ++++++++++++++++++++++++++++++++++ templates/guardrail.json | 10 +++++++ templates/proposed/README.md | 51 ++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 docs/governance.md create mode 100644 templates/proposed/README.md diff --git a/docs/governance.md b/docs/governance.md new file mode 100644 index 0000000..6d4c9e8 --- /dev/null +++ b/docs/governance.md @@ -0,0 +1,49 @@ +# Squad governance model + +Squads are autonomous within bounds. Governance files set those bounds — and the founder owns them. + +## Authority by file + +| File | Owner | Updated by | Frequency | +|------|-------|-----------|-----------| +| `directives.md` | Founder + Cofounder | Founder | When strategy shifts | +| `goals.md` (per squad) | Founder + Cofounder | Founder | Per release / quarter | +| `priorities.md` (per squad) | Founder + Cofounder | Founder | Weekly review | +| `SQUAD.md` | Founder | Founder | Rarely (atemporal identity) | +| `state.md` | Squad agents | Workers + lead | Every run | +| `learnings/` | Squad agents | Workers | Every run | +| GitHub issues (tasks) | COO + agents | Anyone | Continuously | + +## Why the split + +Governance files set the **target**. Memory files capture the **trajectory**. If agents could rewrite both, they'd drift away from the founder's intent run by run — and fast. Letting agents write memory but not governance is the minimum viable separation. + +## How it's enforced + +The bundled `templates/guardrail.json` includes a PreToolUse hook that blocks `Edit`, `Write`, and `MultiEdit` to: +- `**/goals.md` +- `**/priorities.md` +- `**/directives.md` +- `**/SQUAD.md` + +When an agent tries to write one of these, the hook exits with code 2 and a message redirecting to `.squads/proposed/`. + +The founder's own Claude Code sessions don't pass through the agent guardrail, so direct edits work normally for governance owners. + +## How agents propose changes + +Instead of editing the canonical file, agents write to `.squads/proposed/--.md`. See `.squads/proposed/README.md` for the format. + +The founder reviews proposals on a cadence (weekly, or per release) and merges accepted ones into the canonical files. + +## Coherence checks + +Run `squads coherence` (coming in the next release) to surface drift: +- Are squad goals aligned with `directives.md`? +- Are priorities grounded in goals? +- Are governance files stale (>14 days)? +- Are there pending proposals awaiting founder review? + +## Override + +In emergencies (security incident, broken release) the founder can edit governance files without going through proposals. There's no audit trail beyond git history — keep that as the source of truth. diff --git a/templates/guardrail.json b/templates/guardrail.json index f56bb9b..24f9a24 100644 --- a/templates/guardrail.json +++ b/templates/guardrail.json @@ -10,6 +10,16 @@ "timeout": 5 } ] + }, + { + "matcher": "Edit|Write|MultiEdit", + "hooks": [ + { + "type": "command", + "command": "bash -c 'path=$(echo \"$CLAUDE_TOOL_INPUT\" | python3 -c \"import sys,json; d=json.load(sys.stdin); print(d.get(\\\"file_path\\\",\\\"\\\"))\" 2>/dev/null || true); case \"$path\" in */goals.md|*/priorities.md|*/directives.md|*/SQUAD.md) echo \"BLOCKED: $path is a governance file. Only the founder can edit goals/priorities/directives/SQUAD identity. Propose changes by writing to .squads/proposed/-$(date +%Y%m%d).md instead — the founder reviews and merges.\" >&2; exit 2;; esac'", + "timeout": 5 + } + ] } ] } diff --git a/templates/proposed/README.md b/templates/proposed/README.md new file mode 100644 index 0000000..c5182f8 --- /dev/null +++ b/templates/proposed/README.md @@ -0,0 +1,51 @@ +# Proposed governance changes + +Agents cannot edit governance files directly (`goals.md`, `priorities.md`, `directives.md`, `SQUAD.md`). The PreToolUse guardrail blocks those writes. + +When an agent believes a governance file should change, it writes a proposal here instead. + +## Naming convention + +``` +.squads/proposed/--.md +``` + +Examples: +- `goals-engineering-20260425-add-cross-platform.md` +- `priorities-marketing-20260425-deprioritize-outbound.md` +- `directives-20260425-shift-to-inbound-only.md` + +## Proposal format + +```markdown +# Proposal: + +**Target file:** `.agents/memory//goals.md` +**Source agent:** `/` +**Reason:** + +## Proposed change + + +## Impact + + +## Founder decision +- [ ] Accepted — merged to canonical file on YYYY-MM-DD +- [ ] Rejected — reason: ... +- [ ] Deferred — revisit on YYYY-MM-DD +``` + +## Founder workflow + +Weekly (or per-release), the founder reviews proposals: + +```bash +ls .squads/proposed/ # see what's queued +squads coherence # check for drift before deciding +# review each proposal, decide +# accepted: merge into canonical file, then move proposal to .squads/proposed/accepted/ +# rejected: move to .squads/proposed/rejected/ with reason in the file +``` + +The proposal channel is a **defer**, not a **block** — agents keep contributing ideas, the founder keeps governance authority. From 124e8b71c6d0a23a706838aee3a1d0756c07bb8e Mon Sep 17 00:00:00 2001 From: Jorge Vidaurre Date: Sun, 26 Apr 2026 12:39:21 -0400 Subject: [PATCH 2/2] docs(governance): require evidence refs on goals.md entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Empirical: a one-shot audit across 19 squads found 3 outright false "Achieved" claims (referencing PRs/issues that don't exist) and 66 entries with no checkable reference at all. Two-thirds of goals.md content is unverifiable today. Layer 1 (the guardrail) blocks unauthorized writes. This commit adds the format spec the founder will enforce on accepted proposals: - docs/governance.md: new section "goals.md format — every claim must cite evidence" with required ref types (PR / commit / file / issue), good examples, anti-patterns, and validation pointer. - templates/proposed/README.md: callout that goals.md proposals without refs will be rejected. Validator script lives in hq for now (scripts/validate-goals.sh); graduates to "squads coherence" in a later release (Layer 3 of #764). Co-Authored-By: Claude --- docs/governance.md | 39 ++++++++++++++++++++++++++++++++++++ templates/proposed/README.md | 6 ++++++ 2 files changed, 45 insertions(+) diff --git a/docs/governance.md b/docs/governance.md index 6d4c9e8..cd6eb1c 100644 --- a/docs/governance.md +++ b/docs/governance.md @@ -36,6 +36,44 @@ Instead of editing the canonical file, agents write to `.squads/proposed/` (7+ chars) or `→ org/repo@` +- **File:** `→ path/to/file.ts:42` (line number optional) +- **Issue closed by PR:** `→ closes #123` or `→ fixed in #456` + +### Examples +```markdown +## Achieved +- Conversation protocol shipped → #733 +- Telemetry restored after March outage → #739, src/lib/telemetry.ts +- v0.3.1 published to @latest → 2383ab2 + +## In Progress +- Windows smoke test → #761 (open) +- Governance guardrail → #765 (open) + +## Active +- Tier 2 public images → epic #762 (no work started) +``` + +### Anti-patterns (will be flagged by `squads coherence`) +```markdown +- 13/13 Docker tests pass # ❌ no PR/commit/file +- Marketing pipeline working # ❌ unverifiable claim +- Achieved telemetry coverage # ❌ what proves it? +``` + +### Validation +Two layers: +1. **Convention** — agents writing proposals to `.squads/proposed/` follow this format. +2. **Tooling** — `squads coherence` (next release) walks every `goals.md`, checks each ref against git/gh state, flags contradictions. Until then, `scripts/validate-goals.sh` in `hq` does the same job. + ## Coherence checks Run `squads coherence` (coming in the next release) to surface drift: @@ -43,6 +81,7 @@ Run `squads coherence` (coming in the next release) to surface drift: - Are priorities grounded in goals? - Are governance files stale (>14 days)? - Are there pending proposals awaiting founder review? +- Do `Achieved` entries cite verifiable refs (PR, commit, file)? ## Override diff --git a/templates/proposed/README.md b/templates/proposed/README.md index c5182f8..31e130d 100644 --- a/templates/proposed/README.md +++ b/templates/proposed/README.md @@ -36,6 +36,12 @@ Examples: - [ ] Deferred — revisit on YYYY-MM-DD ``` +## When proposing `goals.md` changes + +Every entry under `Achieved`, `In Progress`, or `Active` **must cite a verifiable ref** — PR, commit, file path, or issue. See `docs/governance.md` for the format spec and examples. + +Proposals that add `Achieved` entries with no ref will be rejected on review. The validator (`scripts/validate-goals.sh` in `hq`, `squads coherence` in a future CLI release) catches the same issue automatically. + ## Founder workflow Weekly (or per-release), the founder reviews proposals: