Workspace Manifest DSL Reference

The workspace manifest DSL is a schema-driven YAML specification. This page documents the schema structure, validation rules, and expression syntax.


Manifest Structure

Every workspace manifest has this root structure:

yaml
1# yaml-language-server: $schema=https://xema.dev/schemas/workspace/v1/WorkspaceManifest.json
2apiVersion: xema.dev/workspace/v1
3kind: WorkspaceManifest
4extends: xema://manifest/primary-agent-[email protected]   # optional
5metadata:
6  slug: my-manifest
7  version: 1.0.0
8  title: "My Workspace"
9  description: Optional description
10spec:
11  inputs: {}       # variables callers supply
12  mounts: {}       # which workspace slots are mounted
13  agent: {}        # agent identity and role
14  seedFiles: []    # files to bootstrap in /workspace
15  env: []          # environment variables
FieldTypeRequiredDescription
apiVersionstringYesAlways xema.dev/workspace/v1
kindstringYesAlways WorkspaceManifest
extendsstringNoBase manifest ref to inherit from (single-level)
metadata.slugstringYesManifest identifier (lowercase kebab-case, 1–64 chars)
metadata.versionstringYesSemVer format (MAJOR.MINOR.PATCH)
metadata.titlestringNoHuman-readable label
metadata.descriptionstringNoOptional one-line summary
spec.inputsobjectNoInput variable definitions
spec.mountsobjectNoWorkspace mounts configuration
spec.agentobjectYesAgent identity
spec.seedFilesarrayNoFiles to bootstrap
spec.envarrayNoEnvironment variables

extends: — manifest inheritance

A manifest may inherit from a base template by setting extends to a xema://manifest/<slug>@<version> reference. Resolution happens at compile time: the base is fetched (user → project → org → biome → system precedence — the standard five-tier ladder), merged into the child, and the resulting effective shape is what the runtime consumes.

yaml
1extends: xema://manifest/primary-agent-[email protected]
2metadata:
3  slug: clarification-coordinator
4  version: 1.0.0
5spec:
6  agent:
7    slug: clarification-coordinator
8    stage: clarification
9    role: coordinator
10  mounts:
11    deliverable-specs: { mode: read-only }   # added on top of base

Merge rules

  • mounts and inputs — key-union. Child's per-slot declaration wins on conflict.
  • seedFiles and env — concatenated (base first), with duplicates by path / name keeping the LAST occurrence (child wins).
  • agent — child's block fully replaces the base's. The agent identity is not inheritable.

Constraints

  • Single-level only — the base manifest itself MUST NOT carry an extends: field. Multi-level inheritance is rejected at compile time.
  • Version-pinned — the URI requires a concrete @MAJOR.MINOR.PATCH so old runs always resolve to the row they were authored against.
  • Fail-fast — missing base → typed error; malformed base → typed error.

Built-in templates

The platform ships four base templates at the system tier:

SlugUse Case
primary-agent-baseCoordinator / unit-worker shape (inputs RO, references RO, uploads RO, deliverables RW)
subagent-baseSame as primary-agent-base minus uploads
reviewer-baseRead-only verdict shape (inputs/references/repos/deliverable-specs/deliverables, all read-only)
agent-session-baseChat-driven runs (inputs RO, references RO, uploads RO, deliverables RW)

Biomes register their own base manifests by shipping additional *.workspace.yaml files under workspace-manifests/ — at install time each one is compiled and seeded into the LLM Registry as a published agent composition, and other manifests can extends: it by xema://manifest/<slug>@<version>. Orgs publish org-private base manifests the same way: ship them via an org-scoped biome or author them directly in the Agent Studio.


Inputs

Declare variables that callers supply at dispatch or session start. All ${input.x} references in the manifest must have a corresponding input declaration.

yaml
1spec:
2  inputs:
3    repoRef:
4      type: string
5      required: true
6      description: Repository owner/name
7      pattern: "^[a-zA-Z0-9-]+/[a-zA-Z0-9-]+$"
8    
9    theme:
10      type: string
11      required: false
12      default: light
13      enum: [light, dark]
14      description: Visual theme preference
15    
16    maxTokens:
17      type: number
18      required: false
19      default: 4000
20      minimum: 100
21      maximum: 10000
22    
23    enableDebug:
24      type: boolean
25      required: false
26      default: false
27    
28    kbSpaceIds:
29      type: array
30      required: false
31      default: []
32      description: Knowledge-base space IDs to include

Input Type Reference

TypeExampleNotes
string"github.com/example/repo"Can include pattern, enum, minLength, maxLength
number4000Can include minimum, maximum, exclusiveMinimum, exclusiveMaximum
booleantrue or falseNo additional constraints
array["space1", "space2"]Items are strings or objects; no nesting
object{ key: "value" }Free-form; reserved for complex structures

Input Constraints

yaml
1spec:
2  inputs:
3    # String with pattern
4    githubToken:
5      type: string
6      required: true
7      pattern: "^ghp_[a-zA-Z0-9]{36}$"
8      description: GitHub personal access token
9    
10    # Number with bounds
11    concurrency:
12      type: number
13      required: false
14      default: 4
15      minimum: 1
16      maximum: 16
17    
18    # Enum (closed set)
19    architecture:
20      type: string
21      required: true
22      enum: [monolith, microservices, serverless]

Expression Syntax

Manifest values can include interpolation tokens resolved at bind time. The grammar is intentionally narrow — parameterized templates, not control flow — so the only form is single-brace ${ … }, and the only reference the manifest interpolator resolves is a declared input:

  • Input: ${input.repoRef} — resolves to a spec.inputs value (a whole-value token preserves the input's declared type, e.g. an array stays an array).
  • Input with default: ${input.repoRef | default: 'main'} — falls back to a string ('foo'/"foo"), number, or boolean literal when the input is absent.

spec.env values may additionally reference a declared credential as ${credential.NAME} — see Environment Blocks. No other token namespaces (env.*, bare literals, arithmetic, function calls) are supported; an unrecognised token is a compile-time error (unsupported interpolation token).

Examples

yaml
1spec:
2  inputs:
3    repo:
4      type: string
5      required: true
6    debug:
7      type: boolean
8      default: false
9
10  mounts:
11    repos:
12      work:
13        - url: "https://github.com/${input.repo}"
14          role: primary
15  
16  seedFiles:
17    - path: /workspace/config.json
18      content: |
19        {
20          "debug": ${input.debug},
21          "repo": "${input.repo}"
22        }
23  
24  env:
25    - name: DEBUG_MODE
26      value: "${input.debug}"

Expression Resolution Rules

  1. Type coercion: Expressions in YAML values are resolved to their declared type
  2. Missing input: If required: true input is missing → compile error
  3. Default fallback: If required: false input is missing → use default value
  4. Null handling: null values are rejected unless explicitly allowed
  5. No nested tokens: ${ ${ … } } is invalid
  6. String interpolation: Expressions can be embedded in strings: "prefix-${input.x}-suffix"

Validation Tiers

The manifest compiler validates in three tiers:

Tier 1: Structural

YAML syntax, required fields, type compatibility.

Examples of Tier 1 errors:

  • YAML syntax error (bad indentation, invalid escape)
  • Missing required field (spec.agent not present)
  • Type mismatch (agent.slug is a number instead of string)

When caught: At manifest compile time — in your editor via the schema hint, and again when the biome that ships the manifest is installed.

Tier 2: Policy

Format rules, enums, closed-set validation.

Examples of Tier 2 errors:

  • Slug format invalid: "My Manifest" → must be kebab-case "my-manifest"
  • Version not SemVer: "1.0" → must be "1.0.0"
  • Unknown enum value: role: "unknown" → must be one of unit-worker, coordinator, gate-reviewer, clarification-coordinator, scope-validator, agent-session, brainstorming, generic-agent, auditor, or engineer. The compile error names the offending field as $.spec.agent.role.

When caught: At manifest compile time — in your editor via the schema hint, and again when the biome that ships the manifest is installed.

Tier 3: Semantic (Deferred to Runtime)

Agent existence, phase availability, mount source availability.

Examples of Tier 3 checks (deferred):

  • Agent slug "nonexistent" → resolved at dispatch, fails if not found in LLM Registry
  • Phase key "invalid" → resolved at dispatch
  • Mount source (KB space, external repo) → resolved at dispatch

When caught: At workflow dispatch or session start (not at biome install / composition seed time)

Why deferred: These depend on runtime state (which org, which agent versions are available). The DSL validates what it can offline; the runtime validates the rest.


Schema URL

The manifest schema is published at the apiVersion-aligned URL (Kubernetes convention <group>/<version>/<Kind>):

GET https://xema.dev/schemas/workspace/v1/WorkspaceManifest.json

Add the schema hint to your YAML files for IDE autocomplete:

yaml
1# yaml-language-server: $schema=https://xema.dev/schemas/workspace/v1/WorkspaceManifest.json

Schema Updates: breaking changes bump the apiVersion (e.g. xema.dev/workspace/v2) and ship at a new URL. Old apiVersions stay served until fully deprecated.


Error Messages

When manifest compilation fails — at biome install time, or in your editor via the schema hint — each error carries a structured code:

json
1{
2  "ok": false,
3  "errors": [
4    {
5      "code": "VALIDATION_ERROR",
6      "path": "spec.agent.slug",
7      "message": "agent slug must not be empty"
8    },
9    {
10      "code": "VALIDATION_ERROR",
11      "path": "spec.seedFiles[0].template",
12      "message": "template 'my-custom-template' does not resolve"
13    }
14  ]
15}

Offline validation reports every failure as VALIDATION_ERROR with a path locating it and a message describing it. There is no per-cause code vocabulary at this layer — the path is what you branch on.

What the message describesNext step
A schema or structural failureFix the YAML at the reported path
A referenced template that does not resolveShip the template as a skill-bundle resource the manifest references
An expression that does not parseCheck the ${ … } token syntax

Tier-3 (runtime) failures cannot be detected offline at all; they surface at dispatch.


Best Practices

  1. Always include the schema hint in your YAML files for IDE completion
  2. Use required inputs sparingly — most inputs should have sensible defaults
  3. Validate early — let the editor's YAML language server flag schema errors as you author
  4. Version your manifests — use SemVer; breaking changes bump MAJOR
  5. Document your inputs — include descriptions for all inputs so callers understand what they're for
  6. Use enums for closed sets — prefer enum: over free-form strings for better validation

Related: Authoring Guide · Mounts Reference


Previous: ← Authoring Next: Mounts Reference →