Author a GOVERNANCE.md (workspace root or view) for AIP-7
Use this skill when the user asks to draft, extend, or revise a
governance.workspace/v1 manifest under AIP-7. The skill
produces a valid manifest (workspace-root or view), with the right cross-AIP
refs, policy registry, approvers, and composition fields, ready for
defineGovernanceWorkspace to load.
A workspace manifest is the machine-readable contract for an
AIP-7 governance scope — autonomy ceiling, default approval
class, signing keyring, audit retention, the registry of policies and approvers.
The same doctype is used in two modes: a workspace root at the scope root
(no extends:), and a view in any operator/company/skill folder (with
extends: pointing at a parent). Authoring either is the same flow, with one
branch on step 1 and an EXTRA invariant check on step 11 for views.
When to use
- "Set up org-wide governance — write its
GOVERNANCE.mdfrom scratch." - "Add a per-operator lens on top of the org root — drop autonomy for an onboarding flow."
- "Add a per-company tenancy view that binds Acme's work and knowledge workspaces."
- "Bind an AIP-13 work workspace to this scope so audit events produce work-item updates."
- "Refactor the registry: move three policies from the org root to a per-team view that needs them stricter."
When NOT to use
- The user wants to author an individual policy, signature, or audit entry
(the per-event/per-rule layer) — that's the
author-governanceskill. - The user wants to change the AIP-7 spec itself — manifest shape changes are governance, not authoring.
- The user wants to edit an existing
GOVERNANCE.mdin place without considering the chain — read the parent first, run the merge in your head (especially the one-way switches), then edit. Skipping the merge produces views that override fields the parent already locks correctly, OR views that try to relax invariants and HARD-REFUSE at load.
Process
Follow these steps in order. Composition is the central mechanism; steps 1–2 set up the right mode, steps 5–9 fill in the body, steps 10–12 validate with the one-way switch check.
1. Decide: workspace root or view?
Two questions:
- Is there an existing
GOVERNANCE.mdupstream that this manifest should adapt? If yes → view; if no → workspace root. - Does the user want the manifest to bind to a specific consumer (operator /
company / skill)? If yes → view (set
appliesTo); if no → workspace root.
Workspace-root mode declares the BASE posture. View mode adapts the base for one
or more consumers — but only by ratcheting stricter. There is no third mode
— the schema rejects manifests that mix workspace-root and view properties (e.g.
appliesTo without extends).
If the answer is workspace root, skip step 2 and proceed to step 3.
2. If view: locate parent, reference via extends:, understand one-way switches
For a view, the extends: field is a RELATIVE path from the new manifest's
directory to the parent GOVERNANCE.md. The host resolves it bottom-up;
recursion is allowed (the parent may itself have extends:).
# Operator view at /repo/operators/junior-eng/GOVERNANCE.md
extends: ../../governance/GOVERNANCE.md
Rules:
- Use POSIX path separators in
extends:even on Windows. Hosts normalize before resolving. - Maximum chain depth is eight. Two-to-three levels is the common case.
- Cycle detection and depth-overflow are runtime warnings, not errors. The host degrades gracefully.
ONE-WAY SWITCHES — read carefully before authoring a view:
Two fields cannot be relaxed by any descendant of a parent that locks them:
| Field | Lock direction | Hard refusal code |
|---|---|---|
audit.appendOnly |
Parent true → child MUST be true (or omit) |
governance_append_only_relaxation |
signing.required |
Parent true → child MUST be true (or omit) |
governance_signing_downgrade |
Rule of thumb: do NOT redeclare these fields in a view unless you are
intentionally TIGHTENING (changing false → true) or matching the parent. If
you redeclare to a value the parent already provides, that's harmless. If you
redeclare to a weaker value, the host refuses the merge. The view fails to
load entirely — not a warning, not a degraded state. Hard refusal.
The safe pattern is: omit the field in the view, let it inherit. Only override a one-way field when ratcheting up.
3. Identity (name, title, description, version)
Every manifest, root or view, declares its identity. These fields are NOT inherited (each manifest has its own).
schema: governance.workspace/v1
name: junior-eng-view # kebab-case, stable
title: Junior engineer governance lens
description: |
Tight-leash posture for the junior-engineer operator. Read-only
autonomy, narrow keyring, the same locked append-only audit chain
as the org root.
version: 1.0.0 # semver of the SHAPE, not content
Bump version whenever you change autonomy, policies, approvers,
signing, or audit. Patch bumps for cosmetic edits to description or
metadata.
4. Cross-AIP bindings — executor, escalateTo, work, knowledge, appliesTo
executor: ws://operators/governance # AIP-9 operator that runs governance
escalateTo: ws://operators/founder # AIP-9 operator on escalation
work: ws://workspaces/org/WORK.md # AIP-13 binding
knowledge: ws://wikis/org/KNOWLEDGE.md # AIP-10 binding
appliesTo:
- ws://operators/junior-eng # AIP-9 (view only)
| Field | Required | When to set |
|---|---|---|
executor |
optional | Set when a specific AIP-9 operator runs governance flows (apply policies, collect signatures, append audit entries). |
escalateTo |
optional | Set when autonomy.approvalEscalation fires; the host routes to this operator. Distinct from executor: executor runs governance, escalation operator decides outcomes. |
work |
optional | Set to bind an AIP-13 WORK.md workspace. Audit events emitted in this scope produce work-item updates in the bound workspace. |
knowledge |
optional | Set to bind an AIP-10 KNOWLEDGE.md workspace. Schema and source mutations in the wiki flow through this scope's approval gate. |
appliesTo |
conditional | REQUIRED in view mode when the view binds to a consumer. MUST NOT be set in workspace-root mode (the schema rejects roots with appliesTo). |
The host MUST refuse a view whose appliesTo references a non-existent consumer
(governance_appliesto_unresolvable) — verify the consumer's workspace exists
before declaring the binding.
5. Autonomy + approval defaults
autonomy:
level: 1 # 0 = read-only, 1 = suggest, 2 = bounded auto, 3 = irreversible
defaultApproval: on-mutate # auto | always | on-mutate | policy:<ref>
approvalEscalation:
from: operator
to: founder
autonomy.level is the CEILING for the scope. Individual policies MAY further
restrict; nothing CAN exceed this ceiling. autonomy.defaultApproval is the
fallback approval class when no policy matches the action. policy:<ref>
delegates to a named policy in the registry.
A view typically lowers the ceiling (org level: 1 → operator level: 0).
Raising the ceiling in a view is allowed by the schema but reviewers SHOULD push
back — a view that grants more autonomy than its parent is the inverse of the
registry-of-policies pattern.
6. Signing + audit — the one-way switches live here
signing:
algo: ed25519 # ed25519 | ecdsa-p256 | rsa-pss-sha256
keyring: ./.well-known/governance-keys.json # path to public-key bundle
required: true # ONE-WAY SWITCH
audit:
retention: forever # forever | days:<n>
hashAlgo: sha256 # sha256 | sha512 | blake3
appendOnly: true # ONE-WAY SWITCH
storage: file://./audit/audit-log.jsonl # vendor-neutral URI
headPointerSign: true # publish signed head-pointer
Workspace-root authoring: decide whether to lock appendOnly: true and
signing.required: true. Once locked, every descendant view inherits the lock
and cannot relax it. The vast majority of production governance roots SHOULD
lock both; only sandbox / scratch scopes leave them unlocked.
View authoring: OMIT both fields unless intentionally matching the parent or
ratcheting up (false → true). NEVER write appendOnly: false or
required: false in a view that extends a parent with the corresponding lock —
the host HARD-REFUSES the merge.
audit.retention and audit.hashAlgo are NOT one-way; views can extend or
shorten retention freely (subject to runtime policy).
signing.keyring is rebindable but emits governance_keyring_drift as a
warning if the new keyring contains keys not present in the parent's keyring.
Workspace-root authors SHOULD review keyring rebindings — drift is the most
common silent privilege escalation.
7. Policies registry
policies:
- id: write-protected-paths # stable id, merge key
ref: ./policies/write-protected/POLICY.md
appliesTo: workspace.write # AIP-7 action class
severity: error # error | warn | info
- id: external-network
ref: ./policies/external-network/POLICY.md
appliesTo: tool.call
severity: warn
Rules:
idis kebab-case and stable; it is the merge key.refis a workspace-relative path to aPOLICY.mdfile. Policies are ALWAYS file-referenced, never inlined; this keeps them editable through the same governance gate as any artifact.appliesTois an AIP-7 action class (workspace.write,tool.call,mutates,deploy.scheduled, etc.) or*for all actions.severity:errorblocks;warnsurfaces;infologs only.
View authoring: redeclare a parent policy by id to override its severity,
params, or ref. Add new policies by using a fresh id. To REVOKE a parent
policy in a view, redeclare it with severity: info and a ref pointing at a
no-op POLICY.md (or narrow the appliesTo to a non-matching action class).
8. Approvers registry
approvers:
- id: founder # kebab-case, merge key
role: ws://operators/founder # human name OR AIP-9 ref
canApprove: [workspace.write, deploy.scheduled, mutates]
quorum: "1" # "1" | "n-of-m"
- id: cfo
role: morgan@example.com
canApprove: [workspace.write, deploy.scheduled]
quorum: "1"
Rules:
idis kebab-case; merge key.roleis either a human-readable name (resolved against the workspace's identity map) or aws://operators/<slug>ref to an AIP-9 operator.canApproveis the set of approval classes this approver is authorized for. The host refuses a signature whose action is not in this set.quorum:"1"for single-signer;"n-of-m"(e.g."2-of-3") for quorum among a group.
View authoring: redeclare by id to widen or narrow canApprove. To REVOKE
an approver in a view, redeclare with canApprove: [] — the host treats an
empty list as a revocation.
9. Body prose (purpose, threat model, conventions)
The frontmatter ends; the body is markdown. Conventional sections:
# <title>
## Purpose
What this scope governs, who uses it, what it deliberately excludes.
## Threat model
What the workspace defends against. For a root: append-only + signing-required
as the floor. For a view: what the view ratchets up and why.
## What's inherited / overridden / locked
For views: a short table noting what the view inherits unchanged, what it
overrides, and what it cannot relax (the locked fields).
## When to extend vs replace
For workspace roots: guidance on whether teams should ship a view or author a
separate root. The rule is: a view inherits the locks; a separate root is the
right answer when the consumer genuinely needs DIFFERENT (not just stricter)
posture.
Keep the body short. The frontmatter is the contract; prose explains the choices.
10. Validate against GOVERNANCE.schema.json (workspace branch)
Validate the new manifest's frontmatter against the workspace $def in
AIP-7's schema:
npx ajv validate \
-s apps/agentik/sites/content/docs/agentproto/resources/aip-7/draft/GOVERNANCE.schema.json \
-d "<workspaceDir>/GOVERNANCE.md"
Common errors:
appliesToset butextendsmissing → addextends(a view binding to a consumer must extend a parent).policies[].idcollisions inside one manifest → ids must be unique per manifest; merge happens across manifests, not within one.approvers[].idcollisions → same rule.versionnot semver →1.0.0, not1orv1.extendspath not ending inGOVERNANCE.md→ schema enforces the suffix.
Fix every error before declaring success.
11. If view: dry-run merge against parent, CHECK no one-way switch is relaxed
For a view, run the host's resolution algorithm in dry-run mode and present the diff between the parent's effective config and the merged config. The user reviews:
- Hard-refusal check FIRST — does the merged result violate any one-way switch? If yes, the merge fails entirely, and the view cannot be authored as written. Walk every ancestor, not just the immediate parent: a level-3 view that relaxes a lock the level-1 root declared is still a relaxation.
- Which fields the view OVERRIDES (and is that intentional?).
- Which fields the view INHERITS (anything missing that should override?).
- Which fields the view ADDS (new policies, new approvers).
- Resolution chain length (under eight, no cycles).
- Keyring drift warning, if any.
Surface the diff in this shape:
## Merge diff: junior-eng-view (vs parent agentik-org)
ONE-WAY SWITCH CHECK: PASS
- audit.appendOnly: true (inherited from agentik-org, NOT redeclared) ✓
- signing.required: true (inherited from agentik-org, NOT redeclared) ✓
Inherited (no change):
- audit.retention, audit.hashAlgo, audit.storage, audit.headPointerSign
- signing.algo
- policies: write-protected-paths, production-deploy
- approvers: founder, cfo, security
- work, knowledge
Overridden:
- autonomy.level: 1 → 0 (ratchet down)
- autonomy.defaultApproval: on-mutate → always
- signing.keyring: ./.well-known/governance-keys.json →
./.well-known/junior-keys.json ⚠ governance_keyring_drift — junior keyring
contains 1 key not in org keyring
- escalateTo: founder → senior-eng
Added:
- policies.external-network.severity: warn → error (ratchet up by id)
- appliesTo: [ws://operators/junior-eng]
Resolution chain: 2 levels (agentik-org → junior-eng-view) Hard refusals: none
Warnings: 1 (governance_keyring_drift)
If the diff includes a one-way switch relaxation, EDIT THE VIEW: remove the offending field so it inherits. Do not attempt to "work around" the refusal — the lock is intentional.
If the diff includes an unintentional override, edit the view to remove it (deletion of a field reverts to parent's value via the merge).
12. (Optional) Stage the manifest through the workspace's own approval gate
Editing GOVERNANCE.md is itself a governed action. If the workspace declares a
meta-policy on governance.workspace/v1 writes, route the new manifest through
that gate before landing it on disk. Skipping the gate creates an audit gap
exactly where governance needs the strongest record.
Final checklist
Before declaring done:
-
schema: governance.workspace/v1is set. -
name,title,description,versionare present. - If view:
extends:is a valid relative path to an existingGOVERNANCE.mdending in/GOVERNANCE.md. - If view:
appliesTo:references existing consumers. - If workspace root:
extends:andappliesTo:are absent. - If view:
audit.appendOnlyandsigning.requiredare EITHER omitted (inherited) OR set to a value at least as strict as every ancestor's. This is the one-way switch check. -
autonomy.levelis in[0, 1, 2, 3]and within the parent's ceiling (a view typically lowers, not raises). -
policies[].idandapprovers[].idare unique within this manifest. -
policies[].refpaths point at existing POLICY.md files. -
signing.keyringchange reviewed for drift; if the new keyring widens the signer set, the change itself routed through approval. - Cross-AIP refs (
executor,escalateTo,work,knowledge) resolve at runtime (they MAY be unresolvable at load time but MUST resolve on first use). -
metadata.<vendor>.*is namespaced. - Frontmatter validates against the workspace
$definGOVERNANCE.schema.json. - Body is short and prose-only.
- If view: dry-run merge diff was reviewed and accepted by the user; one-way switch check passed.
Output
Reply to the user with:
- The path of the manifest written.
- Mode (workspace root vs view).
- Resolution chain (for a view): root → … → leaf, one path per level, with the version of each manifest.
- Effective config summary — the merged shape, in particular the active
policies, approvers, autonomy ceiling, and lock state of
audit.appendOnly/signing.required. - Bindings —
executor,escalateTo,work,knowledge,appliesTo, each with a one-line note on what it does. - One-way switch verification — explicit confirmation that no ancestor's locked invariant was relaxed.
- Validation result — schema clean, dry-run merge clean, hard refusals
(always zero, otherwise the manifest didn't land), soft warnings (e.g.
governance_keyring_drift). - Open assumptions — fields you guessed (
autonomy.defaultApproval, severities, retention) that the user might want to override.
Do NOT mutate the parent manifest, the workspace root, or any existing view as a side-effect. Authoring a new manifest is a LEAF operation — touch only the file you are creating.
See also
- AIP-7 — agentgovernance/v1 spec
- AIP-3 — SKILL.md
- AIP-6 — agentcompanies/v1
- AIP-9 — agentoperators/v1
- AIP-10 — agentknowledge/v1 — sibling KNOWLEDGE.md pattern
- AIP-13 — agentwork/v1 — sibling WORK.md pattern
../../ADAPTER.md— implementer's guide for hosts (workspace loading, merge strategy, one-way switch enforcement)../../EXAMPLES.md— reference manifests (workspace root, per-operator view, per-company view, multi-level chain)../../GOVERNANCE.schema.json— frontmatter validator (workspace branch)../author-governance/SKILL.md— sister skill for authoring signature/audit/policy artifacts on top of a workspace