Core Schema

The formal definition of a Mandrel Spec contract.

The Mandrel Spec is formalized using a machine-readable YAML schema. It is a drop-in extension of the Agent Card defined by the Linux Foundation’s Agent2Agent (A2A) project.

Top-Level Fields

FieldRequiredDescription
apiVersionMust be mandrelproject.ai/v1.
kindMust be MandrelSpec.
metadataStandard K8s-style metadata (name, namespace, labels).
x-mandrel-versionInternal schema versioning tag (e.g. v1).
specThe core governance and behavior contract (see below).
statusPromotion and signature block (appended by Metrology Lab).

Schema Structure

The spec is divided into several logical blocks that govern different aspects of the agent’s lifecycle.

1. Governance & Safety (governance)

Defines the behavioral envelope and tiered escalation paths.

  • risk-profile: Posture defining the fallback behavior (e.g., safety-first, balanced).
  • circuit-breaker: System-level action on violation (e.g., deny-all).
  • intent-verification: Defense-in-depth check that an agent’s action matches the intent the user expressed. mode is strict, advisory or disabled; failure-action is deny, challenge, challenge-always or log. The agent declares the posture here; the platform supplies the mechanism — which model does the checking, at what endpoint — by baking mandrelproject.ai/intent-classifier into extensions at promotion. An agent that could choose its own classifier could point it at an endpoint it controls, which is a verifier grading its own homework.
  • enforcement-matrices: Mapping request attributes to actions.

Actions: Supported actions across the spec include autonomous, challenge (conditional HITL), challenge-always (mandatory HITL), and deny.

2. Enhanced Identity (identity)

Advanced identity requirements for Agent-to-Agent communication.

  • required-oidc-scopes: Granular scopes needed for authorization.
  • attribute-whitelist: Attributes visible via token exchange.
  • enforce-dpop: Mandatory sender-constrained tokens.

3. Hardened Network (network)

Strict network and data persistence claims.

  • egress-spiffe-targets: Permitted downstream agents.
  • ingress-spiffe-allow-list: Workloads permitted to contact this agent.
  • state-claim: Named resource for data persistence.

Naming a workload

Both lists take references in three forms.

FormExampleMeans
Path-only/ns/finance/sa/ledgerA workload in this deployment’s own trust domain
Absolutespiffe://partner.example/ns/x/sa/yA workload in a foreign trust domain
Tagtag:spiffe-authA platform-defined selector

Prefer the path-only form. A trust domain belongs to the SPIRE server or CA that issues SVIDs — a property of the deployment, not of the agent — so writing it into a spec ties that spec to one environment. A path-only reference is resolved against the platform’s trust domain at promotion time, which is what lets a single reviewed spec move between dev, staging and production without editing.

An absolute reference asserts that a SPIFFE federation relationship exists with that trust domain. A lab rejects one the platform has not federated with: without federation there is no bundle exchange, without a bundle the SVID cannot be validated, and the rule could never fire. Rejecting at promotion turns a permanently dead rule into a named error. mandrel-cli emits W030 on an absolute reference for the same reason.

Either path form may end in /* to match beneath it. The wildcard is segment-aligned: /ns/finance/* matches /ns/finance/sa/ledger and does not match /ns/finance-test/sa/ledger.

4. Deterministic Runtime (runtime)

Execution constraints to prevent stochastic drift.

  • idempotency: Defines if actions can be safely retried.
  • max-hops-allowed: Prevents infinite delegation loops (depth).
  • max-fan-out: Maximum simultaneous outbound delegation calls at one hop (concurrent width). 0 means no delegations permitted; absent means no limit.
  • max-delegations: Maximum total outbound delegation calls per turn (per-turn) and per session (per-session). Complements max-fan-out with a volume constraint. 0 means no delegations permitted; absent means no limit.
  • timeout-seconds: Hard execution deadline per turn.

5. Plugin Extensions (extensions)

Free-form configuration blocks owned by registered plugin validators. Each top-level key must be claimed by exactly one plugin via OwnsExtensions(). Unclaimed keys fail validation by default (Default-Deny). See the Extensions Reference for the full ownership model and override flags.

The mandrelproject.ai/ prefix is reserved. Keys under it are owned by the specification and written by a metrology lab when it bakes platform configuration into a spec — currently mandrelproject.ai/intent-classifier. A third-party validator that claims a key under this prefix is rejected with E007: allowing it would let an agent supply its own substitute for platform-owned configuration and have the claim legitimize it.

6. Orchestrator Mode (orchestrator)

Adding spec.orchestrator to a MandrelSpec marks the agent as an orchestrator-mode agent. The stanza is absent on specialist agents — its presence alone activates the orchestrator enforcement layers in the Collet. All sub-fields are optional; an empty orchestrator: {} declares orchestrator mode with no constraints.

This stanza closes the governance gap between the orchestrator (previously the trusted caller outside the governance boundary) and the specialist agents it governs. See the Orchestration & Delegation page for the enforcement model.

permitted-intents

The set of user intents this orchestrator is authorized to handle. The ingress Collet classifies each inbound request against this list before routing. Requests that do not match are handled per scope-rejection-policy.

ValueMeaning
AbsentNo intent restriction — orchestrator accepts all inbound tasks
[] (empty list)All inbound tasks rejected
One or more entriesOnly the declared intents are accepted

Each entry has a required name (classifier label) and an optional description (classifier training signal and documentation).

scope-rejection-policy

Controls the Collet’s response when an inbound request does not match permitted-intents.

ValueBehaviour
denyReturn PermissionDenied immediately (default when field is absent)
escalatePause execution and raise a HITL challenge — caller must supply a HumanApprovalToken or redirect
transferQuery the Metrology Lab for a sibling orchestrator declaring this intent; redirect if found, otherwise deny. Requires Metrology Lab infrastructure.

permitted-delegates

Declares which agents this orchestrator may route work to. Supports three binding modes:

Modeagents fieldBehaviour
Capability-bindingAbsentAny promoted agent matching capability + optional namespace/risk-profile constraints
Name-binding["agent-name"]Only the specifically named agent(s) — supports compliance audit requirements
Hybrid["a", "b"]Any agent in the named set, provided capability and namespace also match

The capability sub-field is required. namespace, risk-profile, and agents are optional narrowing constraints.

context-trust

Declares which information sources may inform the orchestrator’s routing decisions. Restricting this surface reduces the prompt injection attack surface for the agent selection step.

Sub-fieldTypeDefaultMeaning
user-querybooltrueRaw inbound user query may be in the selection prompt
tool-resultsbooltrueTool call results may be in the selection prompt
agent-responsesbooltruePrior specialist responses may be in the selection prompt
session-historyenumfullfull | intents-only | none — what portion of accumulated session history is included

intents-only reduces session history to a sequence of classified intent labels, excluding raw content.

planning-depth

Caps the number of sub-task decomposition levels the orchestrator may produce from a single inbound request. Distinct from runtime.max-hops-allowed, which bounds delegation chain depth at the wire level after planning is complete.

ValueMeaning
AbsentNo planning depth restriction
1Orchestrator delegates directly to specialists; no intermediate planning
>= 2Orchestrator may produce plans containing sub-plans up to this depth
0 or negativeInvalid (E022)

autonomy

Declares which orchestrator actions require human approval before proceeding. Three actions are governed independently:

ActionWhat triggers it
re-planningOrchestrator changes its delegation plan mid-task after execution has begun
scope-expansionOrchestrator attempts to delegate to an agent not in its permitted-delegates list
cross-namespace-delegationOrchestrator delegates to an agent outside its declared namespace

Each action accepts autonomous (proceed without approval), challenge (pause and require a HumanApprovalToken), or deny (never permitted regardless of approval). Absent fields default to autonomous.

Orchestrator Example

apiVersion: mandrelproject.ai/v1
kind: MandrelSpec
metadata:
  name: finance-orchestrator
  namespace: domain-finance

spec:
  capabilities:
    intents:
      - name: "Get_Account_Balance"
        description: "Routes balance inquiries to the finance specialist."
      - name: "Execute_Payout"
        description: "Routes payout requests with threshold enforcement."

  governance:
    risk-profile: "safety-first"
    circuit-breaker: "deny-all"

  runtime:
    max-hops-allowed: 3
    timeout-seconds: 30
    max-delegations:
      per-turn: 4

  orchestrator:
    permitted-intents:
      - name: "Get_Account_Balance"
        description: "Balance inquiries for verified accounts."
      - name: "Execute_Payout"
        description: "Fund transfers subject to threshold governance."
    scope-rejection-policy: "escalate"

    permitted-delegates:
      - capability: "Get_Account_Balance"
        namespace: "domain-finance"
      - capability: "Execute_Payout"
        namespace: "domain-finance"
        risk-profile: "safety-first"
        agents: ["finance-specialist"]

    context-trust:
      user-query: true
      tool-results: false
      agent-responses: false
      session-history: "intents-only"

    planning-depth: 2

    autonomy:
      re-planning: "challenge"
      scope-expansion: "deny"
      cross-namespace-delegation: "challenge"

7. Token Budget (token-budget)

Declares chip-based cost governance for the agent. Absent means no chip-budget enforcement is configured.

FieldRequiredTypeDefaultDescription
primary-chipsnumber (tenths)Max Chips for normal execution (e.g. 500.0)
model-idstringModel identifier; must exist in the active MandrelChipRateTable
resolution-chipsnumber (tenths)500.0Isolated budget activated when primary-chips is exhausted
clamp-pointsarray of enum["inbound","outbound"]Active governance boundaries
hold-strategyenumcold-maxCost-estimation strategy for pre-flight holds
graceful-degradationobjectsee belowBehaviour on budget exhaustion

clamp-points values:

ValueBoundaryEnforcement
inboundClient → AgentMacro-hold placed on the user chip balance before the task begins
outboundAgent → External (LLMs, MCP)Micro-check before each sub-call; blocks when budget is insufficient

hold-strategy values:

ValueBehaviour
cold-maxAssume 0% cache hit (conservative; recommended)
warm-estimateApply Bayesian priors from Collet telemetry (requires outbound clamp-point; Phase 4+)

graceful-degradation sub-fields:

FieldTypeDefaultDescription
resolution-messagestringsee belowSystem message injected when transitioning to the Resolution Budget
block-mcp-on-resolvebooleantrueBlock all MCP tool calls while the session is in resolving state

Default resolution-message:

SYSTEM: Token budget exhausted. Immediately summarize findings and advise the user. Do not execute further tools.

Validation (E012): See the CLI reference for the full diagnostic code list. W012 is emitted by mandrel-cli validate --metrology-lab when model-id is not found in the active ChipRateTable.

Example:

spec:
  token-budget:
    primary-chips: 500.0
    resolution-chips: 50.0
    model-id: "claude-sonnet-4-6"
    clamp-points: ["inbound", "outbound"]
    hold-strategy: cold-max
    graceful-degradation:
      block-mcp-on-resolve: true

8. Promotion Status (status)

The status block is absent on raw developer-authored specs. It is appended by a metrology lab promotion gate and must not be authored manually. Its presence, with phase: approved and a valid signature, is what distinguishes a realized spec from a raw declaration.

status:
  phase: approved                          # pending | approved | rejected | revoked
  promotedAt: "2026-05-07T09:00:00Z"
  promotedBy: "metrology-lab-a1b2c3d4"
signature: "eyJhbGciOiJFZERTQSIsImtpZCI6ImExYjJjM2Q0In0..."

The signature is top-level

signature is a sibling of status, not a member of it. Nesting it inside status would make the signature part of what it signs, and the exclusion rule that then becomes necessary is one that two implementations get subtly different — presenting as an unverifiable signature with no diagnostic naming the cause.

At the document root the rule is one sentence: the signature covers the entire document except the signature field itself. That brings apiVersion, kind, metadata, spec and all of status under coverage. status.phase matters most — it gates the first enforcement decision, so leaving it unsigned would put an unauthenticated field in front of every subsequent check.

Two hashes

ClaimCoversAnswers
doc_hashThe whole document minus signatureIntegrity. This is what a verifier checks
spec_hashThe source spec block as authoredProvenance, and promotion idempotency

Neither substitutes for the other. doc_hash cannot serve idempotency, because a realized document contains lab-generated status fields a source document does not have, so the comparison would never match. spec_hash cannot serve integrity, because it covers neither the baked ceilings nor the phase.

Both are computed over the RFC 8785 canonical form of the content, not over Go’s or Python’s default JSON encoding — those differ between languages, and a signature that verifies in one and not another is worse than no signature. The normative rules live in the metrology contract.

Expiry is carried in the JWT exp claim; it is not a separate YAML field.

Example Source Spec

apiVersion: mandrelproject.ai/v1
kind: MandrelSpec
metadata:
  name: finance-agent
spec:
  governance:
    risk-profile: "safety-first"
    enforcement-matrices:
      - type: "threshold"
        attribute: "transaction.value"
        tiers:
          - limit: 1000.00
            action: "challenge"
  runtime:
    max-hops-allowed: 2
    max-fan-out: 4
    max-delegations:
      per-turn: 10
      per-session: 50
    timeout-seconds: 30

Example Realized Spec

After promotion, the same spec gains a status block. The spec block values reflect the baked (platform-policy-applied) effective values.

apiVersion: mandrelproject.ai/v1
kind: MandrelSpec
metadata:
  name: finance-agent
  namespace: domain-finance
spec:
  governance:
    risk-profile: "safety-first"
    enforcement-matrices:
      - type: "threshold"
        attribute: "transaction.value"
        tiers:
          - limit: 1000.00
            action: "challenge"
  runtime:
    max-hops-allowed: 2      # baked: min(spec:2, platform:5) = 2
    max-fan-out: 4
    max-delegations:
      per-turn: 10
      per-session: 50
    timeout-seconds: 30
status:
  phase: approved
  promotedAt: "2026-05-07T09:00:00Z"
  promotedBy: "metrology-lab-a1b2c3d4"
signature: "eyJhbGciOiJFZERTQSIsImtpZCI6ImExYjJjM2Q0In0..."

Source: gitlab.com/the-mandrel-project/mandrel-spec