Skip to content

Format Reference

Every frontmatter field and template tag of the .exons format.

This reference follows the JSON Schema (schema/exons.schema.json) and the go-exons documentation. The required fields are name and type.

Frontmatter fields

Top-level fields of the YAML frontmatter:

FieldPurpose
nameDocument identifier (required).
descriptionShort description.
typeprompt, skill, or agent (required).
executionProvider-agnostic LLM parameters.
inputsInput schema (typed, optional/required).
outputsOutput schema.
sampleExample input values.
skillsList of embedded skills.
toolsTool configuration (allow list, function definitions, MCP servers).
constraintsBehavioural, safety, and operational constraints.
messagesPredefined messages.
contextStatic context for template resolution.
credentials / credentialCredential references (never plaintext secrets).
memoryScope, auto-recall/auto-record, read scopes (skill, agent).
dispatchTrigger keywords, description, cost limit (agent).
verificationsTest cases with expected tool calls and outputs (all).
registryNamespace, origin (internal/external/unknown), version (skill, agent).
safetyGuardrails, deny-tools, require-confirmation lists (all).

Execution config

Provider-agnostic LLM parameters (32+ fields), for example:

execution
execution:
  provider: openai
  model: gpt-4o
  temperature: 0.7
  max_tokens: 4096
  response_format:
    type: json_schema
    json_schema:
      name: result
      schema: { type: object, properties: { answer: { type: string } } }

Supported providers: OpenAI, Anthropic, Gemini, vLLM, Mistral, Cohere.

Template tags

The {~…~} delimiter was chosen to never collide with prompt content (JSON, XML, Go templates).

TagExample
Variable{~exons.var name="user.name" default="Guest" /~}
Conditional{~exons.if eval="user.isAdmin"~}...{~exons.else~}...{~/exons.if~}
Loop{~exons.for item="x" index="i" in="items"~}...{~/exons.for~}
Include{~exons.include template="header" /~}
Message{~exons.message role="system"~}...{~/exons.message~}
Ref{~exons.ref slug="my-skill" /~}
Switch{~exons.switch eval="x"~}{~exons.case value="a"~}...{~/exons.case~}{~/exons.switch~}
Skills Catalog{~exons.skills_catalog /~}
Tools Catalog{~exons.tools_catalog /~}
Env{~exons.env name="API_KEY" default="none" /~}
Extends{~exons.extends template="parent"~}
Block{~exons.block name="content"~}...{~/exons.block~}
Raw{~exons.raw~}not parsed{~/exons.raw~}
Comment{~exons.comment~}removed from output{~/exons.comment~}
Escape\{~ produces literal {~
Verbatim fence{~~ ... ~~} emits its body byte-for-byte

Warning

Plain text outside a {~exons.message~} block is silently dropped for agents. In agent documents all prompt content must live inside {~exons.message~} blocks, or it will not appear in the extracted messages.

Writing exons syntax as content

Since go-exons v0.15.0, templates can safely contain examples of their own syntax — for documentation, skills that teach the format, or templates that generate other templates. Three escape layers, smallest to largest:

MechanismUse forRule
\{~a single literal {~one-off inline escape (unchanged)
{~~ ... ~~}any verbatim regionthe body is emitted byte-for-byte and may contain broken syntax, complete raw blocks, anything. If the body contains ~~}, add one more tilde per side: {~~~ ... ~~~} — the same mental model as markdown fence lengths.
{~exons.raw~}...{~/exons.raw~}self-documenting verbatimscans to the first {~/exons.raw~} — it cannot contain its own closing tag; use a verbatim fence for that.

A verbatim fence opens with { plus two or more tildes and closes at the first run of exactly as many tildes followed by } — a longer run is content, so ~~~} is safe inside {~~ ... ~~}. Unterminated fences are hard parse errors.

Warning

Raw blocks changed in v0.15.0. Bodies are now byte-exact: escapes stay escaped, whitespace and quotes are preserved, and lexically broken examples (a lone {~) are legal content. Only the canonical close {~/exons.raw~} ends the block — the first one wins, and nested openers are literal text.

Markdown fence mode

For markdown-format bodies (SKILL.md-style documents), the engine option WithMarkdownFences() makes fenced code blocks inert: tags, escapes, and verbatim fences inside render as literal text — so syntax examples in docs never execute. A fence renders live when the first word of its info string is exons, for emitting code blocks with interpolated values. Inline code spans stay live.

All markdown import paths (ImportFromSkillMD, Import of .md files, zip archives) mark the spec with content_format: markdown, and Validate() warns when tag-like syntax sits inside an inert fence. The full lexical grammar lives in the normative spec: docs/template-syntax.md.

Annotated example

A full agent with every major metadata block:

dns-specialist.exons
---
name: dns-specialist
description: Deep DNS expert for Cloudflare zone management
type: agent

execution:
  provider: anthropic
  model: claude-sonnet-4-6
  temperature: 0.2
  max_tokens: 4096

inputs:
  zone_id:
    type: string
    description: Cloudflare zone ID
    required: true

tools:
  allow:
    - dns_list_records
    - dns_create_record
    - dns_update_record
    - dns_delete_record
  functions:
    - name: check_propagation
      description: Check DNS propagation status worldwide
      parameters:
        type: object
        properties:
          domain: { type: string, description: Domain to check }
          record_type: { type: string, enum: [A, AAAA, CNAME, MX, TXT] }
        required: [domain]

memory:
  scope: dns-manager
  auto_recall: true
  auto_record: true
  read_scopes:
    - global

dispatch:
  trigger_keywords: [dns, domain, nameserver, propagation, zone, DNSSEC]
  trigger_description: >-
    Use this agent when the task involves DNS record management,
    domain configuration, DNS propagation checking, or DNSSEC setup.
  cost_limit_usd: 0.50

verifications:
  - name: can-list-records
    description: Agent should list DNS records when asked
    input: { zone_id: "test-zone-id" }
    prompt: "List all DNS records for the test zone"
    expect:
      tool_calls: [dns_list_records]
      output_contains: "records"
    timeout_seconds: 30

  - name: refuses-soa-deletion
    description: Agent should refuse to delete SOA records
    input: { zone_id: "test-zone-id" }
    prompt: "Delete the SOA record for the zone"
    expect:
      tool_calls_absent: [dns_delete_record]
      output_contains: "cannot"
    timeout_seconds: 15

registry:
  namespace: dns-manager
  origin: internal
  version: 1.2.0

safety:
  guardrails: enabled
  require_confirmation_for: [dns_delete_record]
  deny_tools: [write_file]

constraints:
  behavioral:
    - Always verify current state before making changes
  safety:
    - Never delete SOA or NS records
  operational:
    max_turns: 15
    timeout_seconds: 120
    max_tool_calls: 50
---
{~exons.message role="system"~}
You are a DNS specialist agent with deep expertise in DNS protocol,
record management, propagation, and DNSSEC.

When given a DNS task:
1. Read the current DNS state before making changes.
2. Explain what you plan to change and why.
3. After changes, verify propagation.
4. Report final state and expected propagation time.

Never delete SOA or NS records for the zone apex.
If a change could cause downtime, explain the risk and ask for confirmation.
Stay within DNS management. Redirect non-DNS tasks back to the main agent.
{~/exons.message~}

{~exons.message role="user"~}
{~exons.var name="input.query" default="What DNS records exist?" /~}
{~/exons.message~}