Agent Card Partials
Handlebars partials, auto-attach, and version pinning.
Partials are reusable Markdown blocks that compose into an Agent Card's system prompt at dispatch time. They let you centralise cross-cutting instructions - coding conventions, security checklists, tool-use policies - and attach them to many cards without repeating text.
How composition works
When the platform materialises a card before a session starts, the partial resolver runs two passes:
- Explicit refs - resolves every
PartialRefdeclared inagent_card.partials[], in the declaredorder. - Auto-attach - for
systemandorgscope cards only, attaches every published partial atsystemororgscope whoseappliesTopredicate matches the agent's metadata.
The resulting prompt is: card.systemPrompt + (explicit partials, ordered) + (auto-attached partials, sorted by metadataId for determinism).
project and workflow scope cards never auto-attach. Only system and org scope cards receive automatic partial composition (ADR-2026-05-18 §2). Project/workflow cards must declare all partials explicitly.
Authoring a partial
Partials live in the partials table. Each partial has:
| Field | Description |
|---|---|
metadataId | Stable slug used in PartialRef.id (e.g. "code-intel") |
bodyMarkdown | Handlebars 4.7.9 template - rendered against the agent context |
inputs[] | Declared input slots; see Input variables |
scope | system / org / project / workflow |
scopeOwnerId | Org or project ID for non-system scope |
version | Monotonic integer; incremented on each publish |
appliesTo | { workType?, trustTier?, tags? } - auto-attach predicate |
trust.tier | Controls which card tiers this partial may attach to |
deprecatedAt | When set, the partial is deprecated but still resolves |
Example partial YAML
# code-style.partial.yaml
metadataId: code-style
scope: system
bodyMarkdown: |
## Code style conventions
- Follow the project's ESLint + Prettier config exactly.
- Prefer explicit return types on all public functions.
- {{#if agent.workType}}Work type: {{agent.workType}}.{{/if}}
inputs:
- name: project_language
type: string
defaultValue: TypeScript
description: Primary language for the project
appliesTo:
workType: [development, qa]
trustTier: [system, org, project, workflow]
trust:
tier: systemInput variables
Partials declare typed inputs[] to receive context from the agent or call-site. The interpolator resolves them at composition time using Handlebars:
inputs:
- name: repo_name
type: string
description: "The repository this agent is working on"
- name: strict_mode
type: boolean
defaultValue: falseIn bodyMarkdown:
{{#if strict_mode}}
Do NOT open a PR until all tests pass.
{{/if}}
Repo: {{repo_name}}Warn-and-skip semantics: A declared-but-unsupplied input emits a non-fatal PartialInputMissing warning and renders as empty string. Supplied-but-undeclared inputs are silently ignored (forward-compatible).
The Handlebars engine is isolated (not the global singleton), with prototype-property access disabled (allowProtoPropertiesByDefault: false) and a curated helper allowlist.
Partial refs
In an Agent Card
card:
partials:
# Bare metadataId - resolves to highest published version at the most-specific scope
- id: code-intel
# Version-pinned - exact integer match
- id: code-style@2
# Fully-qualified partial:// URI with explicit owner
- id: partial://org/acme-inc/security-checklist
# Explicit order (lower = earlier in the rendered prompt)
- id: compliance-header
order: 0
# Conditional ref (evaluated by the caller; not yet a platform gate)
- id: bfsi-output-constraints
condition: bfsiModePartialRef resolution order
For a bare metadataId, the resolver tries scopes from most-specific to least:
- Card's own scope (e.g.
workflow) orgscope (ifctx.orgIdis set)systemscope
The first matching published row wins. If no row matches, a PartialRefUnresolved warning is emitted and the ref is skipped.
For a fully-qualified partial:// URI, only the declared scope is tried.
Version resolution
| Ref form | Resolution |
|---|---|
code-intel | Highest published version for (metadataId, scope, ownerId) at compose time |
code-style@2 | Exact version 2 - throws PartialRefUnresolved if missing |
| Unpinned, no published rows | Highest version regardless of publish state (dev fallback) |
Version pinning is per-ref, not per-card. A card can mix live-latest and pinned refs.
Deprecated partials resolve under live-latest but emit a PartialDeprecated warning that appears in the admin partial detail view.
Auto-attach
The appliesTo predicate on a partial drives automatic attachment for system and org scope cards:
appliesTo:
workType: [development, qa] # card's workType must be in this list (OR match)
trustTier: [system, org] # card's trust.tier must be in this list (OR match)
tags: [security] # ctx.tags must have at least one match (OR match)All fields are ANDed across each other; within each field, values are ORed. An empty appliesTo: {} means "always attach."
The trust-tier gate runs independently of appliesTo:
- A
system-tier partial can attach to agents at any tier. - An
org-tier partial only attaches to agents atorgor narrower tier. projectandworkflowtier partials never surface in the auto-attach pass - they are only reachable via explicit ref.
7 system partials
Rensei seeds 7 system partials at install time. They cover: code intelligence context, architecture context, security output constraints, BFSI output constraints, memory recall context, tool-use policy, and session goal framing. These auto-attach to matching system and org scope cards without any configuration.
Deduplication
If an explicit ref and an auto-attach hit the same (scope, metadataId, scopeOwnerId), the explicit ref wins and the auto-attach entry is silently dropped. Per-request result caching prevents duplicate DB queries when multiple refs share the same identity.
Admin API
# List partials (paginated, scoped)
GET /api/admin/partials?scope=system&q=code
# Create / update a partial
POST /api/admin/partials
PATCH /api/admin/partials/<id>
# Publish a partial (increments version, sets publishedAt)
POST /api/admin/partials/<id>/publish
# Deprecate
POST /api/admin/partials/<id>/deprecatePartial CRUD is operator-gated at system scope. Org and project admins can manage partials within their own scope tier.
Related pages
- Agent Cards - how Agent Cards reference partials
- Agent Registry Providers - providers that ship partials alongside agent definitions