Author an ASSEMBLY.md (workspace root or view) for AIP-24
Use this skill when the user asks to draft, extend, or revise an
assembly.workspace/v1 manifest under AIP-24. The skill
produces a valid manifest (workspace-root or view) for one of the four
collaboration modes — advisory, voting, peer, hierarchy — with
the right member roster, synthesis rules, locked-trait floor, audit policy, and
cross-AIP refs, ready for defineAssemblyWorkspace to load.
An ASSEMBLY.md manifest is the machine-readable contract for an
AIP-24 multi-agent collective — its identity, which mode it
operates in, who its members are (referenced as AIP-25
personas), how their outputs combine, what the safety floor is, how artifacts
are persisted. The same doctype is used in two modes: a workspace root at
the assembly root (no extends:), and a view in any consumer folder (with
extends: pointing at a parent). Authoring either is the same flow, with one
branch on step 1.
Critical: AIP-24 delegates ALL persona-level concerns (system prompt, voice
register, persona fragments) to AIP-25. Do NOT inline persona
content in ASSEMBLY.md — declare member refs, then let AIP-25 own the persona
shape.
When to use
- "Set up a new council / voting board / peer panel / hierarchy — write its
ASSEMBLY.mdfrom scratch." - "Add a per-operator view that tightens the locked-trait floor or swaps a member's persona."
- "Bind an AIP-7 governance policy and an AIP-20 work workspace to this assembly."
- "Configure the synthesis rules for the assembly's mode."
- "Add a sentinel pre-filter to an existing advisory council."
When NOT to use
- The user wants to author a persona (system prompt, voice, fragments) —
that's AIP-25's
author-personaskill. - The user wants to change the AIP-24 spec itself — manifest shape changes are governance, not authoring.
- The user wants to swap an assembly's mode mid-chain — modes are one-way
across the
extends:chain. Author a NEW workspace-root manifest if a different mode is required. - The user wants to drop a parent's locked trait — locked traits are
union-only across descendants. The HARD refusal
assembly_locked_trait_removedmakes this impossible without re-rooting.
Process
Follow these steps in order. Composition and one-way switches are the central mechanics; steps 1-2 set up the right mode, steps 3-11 fill in the body, step 12 validates.
1. Decide: workspace root or view?
Two questions:
- Is there an existing
ASSEMBLY.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 / work workspace / skill)? If yes → view (set
appliesTo); if no → workspace root.
Workspace-root mode declares the BASE shape. View mode adapts the base for one
or more consumers. 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, set extends:, understand the four one-way switches
For a view, the extends: field is a RELATIVE path from the new manifest's
directory to the parent ASSEMBLY.md. The host resolves it bottom-up; recursion
is allowed.
extends: ../../<parent-folder>/ASSEMBLY.md
Before writing the body, read the parent and trace the four one-way switches up the chain:
mode— once set at any ancestor, descendants MUST keep the same value. If the user wants a different mode, refuse and explain that they should author a new workspace-root manifest. Trying to switch tripsassembly_mode_change(HARD).audit.consultations.enabled/audit.overlays.enabled— oncetrueat any ancestor, descendants MUST keeptrue(or omit, inheritingtrue). Setting either tofalsetripsassembly_audit_disable(HARD).audit.signing— oncerequiredat any ancestor, descendants MUST keeprequired. Downgrading tooptionalornonetripsassembly_signing_downgrade(HARD).lockedTraits— once a trait is present at any ancestor, descendants MUST include it. Removing tripsassembly_locked_trait_removed(HARD). Children MAY add new traits.
If the chain has any of these locked, plan for them: the new view inherits the constraint and CANNOT relax it.
3. Identity (workspace name, title, description, version)
Fill in the workspace identity:
schema: assembly.workspace/v1
name: <kebab-case-id>
title: <Human Readable Assembly Name>
description: |
One paragraph: what this assembly does, who it serves, why this
mode is the right pattern.
version: 1.0.0
name MUST be kebab-case and unique within its registry. version is the
WORKSPACE shape version — bump it on member-roster / synthesis-rule /
locked-trait / audit-policy changes. It's independent of the assembly's runtime
content version.
4. Pick the mode
The mode is the discriminating field. Pick by the question the assembly answers:
| Question | Mode |
|---|---|
| "Is the agent's behavior drifting? Should it modulate?" | advisory |
| "Should this proposal be approved?" | voting |
| "What do these critics think when they argue?" | peer |
| "How does severity roll up the management chain?" | hierarchy |
If the user asks for "a council", it's almost always advisory. If they ask for
"a board" or "approval body", it's voting. If they ask for "critique", it's
usually peer. If they ask for "reporting", it's hierarchy.
For a view, the mode is INHERITED from the parent. Do NOT set mode: to a
different value — the skill MUST refuse with the explanation that mode is
one-way across the extends: chain.
5. Members — pick personas and assign role config
Members are the bridge between the assembly and AIP-25. Each member is a persona ref with assembly-specific role config layered on top.
members:
- persona: ws://personas/<slug> # AIP-25 ref (REQUIRED)
id: <kebab-role-id> # required, stable role id
role: <Human Label> # required
# MODE-SPECIFIC FIELDS:
phase: session # advisory only
weight: 2.0 # voting only
voteClass: [budget] # voting only
parent: <member-id> # hierarchy only
timeout_ms: 30000
triggers: [sample]
gatherInput:
strategy: working-memory
Mode-appropriate field rules:
- advisory:
phaseSHOULD be set (session/standing/sentinelare the built-ins; custom is permitted). Avoidweight,voteClass,parent— they have no meaning. - voting:
weightSHOULD be set (default 1.0);voteClassMAY be set (default = all classes). Avoidphase,parent. - peer: none of the mode fields are required.
- hierarchy:
parentSHOULD be set on every non-root member. The host detects cycles. Avoidphase,weight,voteClass.
If the user has personas in mind by name, build the refs from the persona
registry's slug convention. If they don't have personas yet, surface this — the
personas MUST exist before the assembly can load
(assembly_member_persona_unresolvable HARD on missing refs). Suggest using
AIP-25's author-persona skill first.
6. Synthesis rules — match the mode's idiomatic rules
Synthesis rules combine member outputs into a single result. Pick rules typical of the mode:
Advisory — typical rule stack:
synthesis:
rules:
- id: <safety>-wins
kind: terminal
appliesTo: [<safety-member-id>]
params: { triggerSeverity: 9, priority: 100 }
- id: <critic>-priority
kind: priority
appliesTo: [<critic-member-id>]
params: { triggerKind: <pattern>, priority: 80 }
- id: severity-eight-unilateral
kind: aggregate
appliesTo: "*"
params: { minSeverity: 8, priority: 70 }
- id: moderate-aggregation
kind: aggregate
appliesTo: "*"
params: { minSeverity: 5, maxSeverity: 7, topN: 2 }
Voting — typical rule stack:
synthesis:
rules:
- id: <veto-member>-veto
kind: terminal
appliesTo: [<veto-member-id>]
params: { triggerVote: no }
- id: quorum
kind: quorum
appliesTo: "*"
params: { threshold: 0.66 }
- id: tie-break
kind: majority
appliesTo: "*"
params: { tieBreaker: chair-vote, chair: <chair-id> }
Peer — typical (degenerate) rule:
synthesis:
rules:
- id: collect-messages
kind: aggregate
appliesTo: "*"
params: { topology: fully-connected, maxRounds: 3 }
Hierarchy — typical rule per non-leaf node:
synthesis:
rules:
- id: aggregate-up
kind: escalate-on-severity
appliesTo: "*"
params: { severityFn: max, evidenceFn: union }
Add a riskLevels mapping if the mode uses severity (advisory, hierarchy):
synthesis:
riskLevels:
- { range: [0, 3], label: ok }
- { range: [4, 6], label: watch }
- { range: [7, 8], label: intervene }
- { range: [9, 10], label: escalate }
The four labels are the built-ins; ranges MUST be monotonic and non-overlapping.
7. Locked traits — define the safety floor
lockedTraits is the assembly's non-negotiables — substrings (or regexes /
semantic patterns) that NO output may contain.
lockedTraits:
- warmth
- honesty
- refuse harm
matchMode: substring # default; rarely changed
For a workspace-root, pick traits that, if eroded, would make the underlying
agent a different agent rather than a slightly-tuned one. Simone's six
(warmth, honest, voice register, refuse harm, kindness,
core persona) are a reasonable starter for an advisory council on a
companion-shaped agent.
For a view, REPEAT all of the parent's locked traits in the array, then add
new ones. The merge is a UNION across the chain, but a child that omits an
ancestor's trait trips assembly_locked_trait_removed (HARD). Repeating is the
safer authoring posture — explicit consent to keeping the floor.
Avoid matchMode: semantic unless the host advertises support; the substring
fallback is permissive (assembly_locked_trait_match_mode_unsupported warning).
8. Audit policy — consultations, overlays, signing
audit:
consultations:
enabled: true # ONE-WAY: cannot disable in descendants
retention: forever
overlays:
enabled: true # ONE-WAY: cannot disable in descendants
maxActive: 10
defaultTtl: P14D # ISO 8601 duration
signing: optional # ONE-WAY on downgrade if 'required' at ancestor
For workspace-root: enabled: true is the safe default — the audit trail is the
spec's third-party-verifiability posture, and disabling it later is
HARD-refused. Set signing: required only when the host implements signing
(assembly_signing_unsupported HARD if not).
For views: omit fields you don't need to override. Do NOT set enabled: false
(HARD refusal). Do NOT downgrade signing (HARD refusal).
9. Cross-AIP bindings (identity, governance, work, executor)
identity: ws://identities/<slug> # AIP-23
governance: <path-or-ref> # AIP-7
work: ws://workspaces/<slug> # AIP-20
executor: ws://operators/<slug> # AIP-9
executor is the runtime that executes the assembly. For single-agent shaped
assemblies (Simone Council), it's the agent's own operator. For org-shaped
assemblies (voting board, hierarchy), it's typically a clerk operator.
identity is the base identity the assembly modulates (advisory) or attributes
to (voting / peer / hierarchy). For a Simone-shaped council, it's
ws://identities/simone.
governance and work are optional but conventional. Bind to a governance
policy when signing or approval gates apply; bind to a work workspace when the
assembly's artifacts attach to work items.
A workspace whose binding does not resolve at load time refuses with
assembly_xref_unresolvable (HARD).
10. Display / UX defaults
display:
defaultGrouping: phase # advisory: 'phase'; others: 'role' or 'severity'
defaults:
triggerHeuristic: every-n-messages
Pick defaultGrouping by what makes sense for the mode:
phase— advisory (group by session / standing / sentinel)role— voting / peer (each member has a labeled role)severity— hierarchy (group by severity level)
For defaults.triggerHeuristic, pick by mode:
every-n-messages— advisory (Simone Council on conversation flow)manual— voting (proposals submitted explicitly)on-mode-change— peer (kicks in when a campaign state changes)manual— hierarchy (review cycles)
11. Body prose
The frontmatter ends; write the body in markdown. Conventional sections:
## Purpose— what this assembly is for, who it serves.## Mode rationale— why advisory (or voting / peer / hierarchy) is the right pattern. (Eliminate the other three.)## Member roster— human-readable rendering of the members, their phases (advisory) / weights (voting) / topology (peer) / tree (hierarchy).## Synthesis rationale— why these rules in this order.## Threat model— what the locked-trait floor defends against.## When to extend vs replace— guidance for downstream view authors.
The body is free-form prose. The contract lives in the frontmatter.
12. Validate
Before declaring the manifest done:
- Schema-validate against
./ASSEMBLY.schema.json. All required fields present?modeis one of the four enum values? Member ids are unique? - If view: dry-run the merge. Walk the chain in your head: what is the
effective
mode(must match the parent's)? What is the effectivelockedTraits(must INCLUDE every parent trait)? What is the effectiveaudit.{consultations,overlays}.enabled(must betrueif any ancestor sets it true)? What isaudit.signing(must berequiredif any ancestor sets it required)? - Check no one-way switch is relaxed. Surface a diff vs the parent's effective config. Any field that's a one-way switch relaxation is a HARD refusal — fix before persisting.
- Validate cross-AIP refs. Every
members[].persona,identity,governance,work,executor,appliesToelement MUST resolve in the host's registries. - Sanity-check synthesis. Are the rule
appliesTomember ids present in the mergedmembers[]? Are the rulekindvalues registered with the host's rule registry? Is there at most oneterminalrule with overlappingappliesToper phase? (Two trip theassembly_synthesis_terminal_chainwarning.) - Run the host's
validate(assemblyRoot)helper if the host exposes one. Report any failures with file + field path.
If validation passes, write the manifest to disk. Otherwise, fix the issues and re-validate.
Output format
A single ASSEMBLY.md file at workspaceDir/ASSEMBLY.md. The content:
---
<frontmatter, validated against ASSEMBLY.schema.json>
---
# <title>
## Purpose
...
## Mode rationale
...
## Member roster
...
## Synthesis rationale
...
## Threat model
...
## When to extend vs replace
...
The frontmatter is the contract; the body is free-form context for human reviewers.
Common pitfalls
- Mixing mode-specific fields. A member with both
phaseandweightis suspicious — most modes use only one set. The schema permits it, but the host SHOULD warn. If you're authoring an advisory member, dropweight/voteClass/parent. - Forgetting to repeat parent's locked traits. The merge is a UNION;
children MUST repeat ancestor entries or trip
assembly_locked_trait_removed. Authors who think "the parent already has it" are wrong — the validator runs the array literally. - Setting
modein a view. Views inheritmode. Setting it to the SAME value is redundant; setting it to a DIFFERENT value is HARD-refused. Skipmodeentirely in views. - Inlining persona content. Resist the temptation to write the persona's
system prompt in
ASSEMBLY.md. That's AIP-25's job. Reference the persona byws://URI and let AIP-25 own the prompt. - Inflating
audit.overlays.maxActive. A high cap (100+) makes the agent's instructions fan out into many simultaneous overlays. Most advisory councils want 6 or fewer. - Using
matchMode: semanticblindly. Hosts that don't implement semantic match silently fall back to substring; the warning surfaces but the floor is looser than the author thought. Stick withsubstringunless the host advertises semantic. - Picking a mode for the wrong question. Advisory is for "should the agent modulate?". Voting is for "should this be approved?". Peer is for "what do critics think when they argue?". Hierarchy is for "how does severity roll up?". Picking the wrong one means the synthesis rules don't fit the artifacts the consumer expects.
See also
- AIP-24 — agentassembly/v1 spec
- AIP-25 — agentpersona/v1 — the unit of identity each member references
- AIP-23 — agentidentity/v1 — base identity advisory overlays modulate
- AIP-7 — governance, approval, audit — one-way-switch convention; signing posture
- AIP-20 — agentwork/v2 — work workspace the assembly attaches to
- AIP-9 — agentoperators/v1 — runtime executor
./ADAPTER.md— implementer's guide./ASSEMBLY.schema.json— frontmatter validator./EXAMPLES.md— reference manifests for all four modes