Skip to content

Manifest Schema Reference

Complete field reference for wave.yaml — the single source of truth for all Wave orchestration behavior.

Top-Level Fields

FieldTypeRequiredDescription
apiVersionstringyesSchema version. Currently "v1".
kindstringyesMust be "WaveManifest".
metadataMetadatayesProject metadata.
adaptersmap[string]AdapteryesNamed adapter configurations.
personasmap[string]PersonayesNamed persona configurations.
runtimeRuntimeyesGlobal runtime settings.
projectProjectnoProject metadata for language, test commands, and source globs.

Minimal Example

yaml
apiVersion: v1
kind: WaveManifest
metadata:
  name: my-project
adapters:
  claude:
    binary: claude
    mode: headless
personas:
  navigator:
    adapter: claude
    system_prompt_file: .wave/personas/navigator.md
runtime:
  workspace_root: .wave/workspaces

Metadata

FieldTypeRequiredDefaultDescription
namestringyesProject name. Used in event output and workspace paths.
descriptionstringno""Human-readable project description.
repostringno""Repository URL. Used in audit logs and generated documentation.
yaml
metadata:
  name: acme-backend
  description: "Acme Corp backend API service"
  repo: https://github.com/acme/backend

Project

Optional project-level settings used for build, test, and source discovery.

FieldTypeRequiredDefaultDescription
languagestringno""Project language (e.g., "go", "typescript"). Used for adapter heuristics.
test_commandstringno""Command to run tests (e.g., "go test ./..."). Used by contract validation.
lint_commandstringno""Command to run linting.
build_commandstringno""Command to build the project.
source_globstringno""Glob pattern matching source files (e.g., "**/*.go").
yaml
project:
  language: go
  test_command: "go test ./..."
  lint_command: "golangci-lint run"
  build_command: "go build ./..."
  source_glob: "**/*.go"

Adapter

Wraps a specific LLM CLI for subprocess invocation. Each adapter defines how Wave communicates with one LLM tool.

FieldTypeRequiredDefaultDescription
binarystringyesCLI binary name. Must be resolvable on $PATH.
modestringyesExecution mode. Currently only "headless" (always subprocess, never interactive).
output_formatstringno"json"Expected output format from the CLI.
project_files[]stringno[]Files to project (copy) into every workspace using this adapter. Supports glob patterns.
default_permissionsPermissionsnoallow allDefault tool permissions applied to all personas using this adapter. Persona-level permissions override these.
hooks_templatestringno""Directory containing hook script templates. Scripts are copied into workspaces.

Adapter Example

yaml
adapters:
  claude:
    binary: claude
    mode: headless
    output_format: json
    project_files:
      - CLAUDE.md
      - .claude/settings.json
    default_permissions:
      allowed_tools: ["Read", "Write", "Bash"]
      deny: []
    hooks_template: .wave/hooks/claude/

  opencode:
    binary: opencode
    mode: headless
    output_format: json
    default_permissions:
      allowed_tools: ["Read", "Write"]
      deny: ["Bash(rm *)"]

Binary Resolution

The binary field is resolved against $PATH at validation time. If the binary is not found, wave validate emits a warning (not an error) — the binary may be available at runtime but not at validation time (e.g., in CI).


Persona

Agent configuration binding an adapter to a specific role. Personas enforce separation of concerns — each persona has distinct permissions, behavior, and purpose.

FieldTypeRequiredDefaultDescription
adapterstringyesReferences a key in adapters.
descriptionstringno""Human-readable purpose description.
system_prompt_filestringyesPath to markdown file containing the persona's system prompt. Relative to project root.
temperaturefloatnoadapter defaultLLM temperature setting. Range: 0.0 to 1.0. Lower values produce more deterministic output.
permissionsPermissionsnoinherit from adapterTool permission overrides. Merged with adapter defaults; persona-level deny always takes precedence.
modelstringnoadapter defaultLLM model override for this persona (e.g., "opus", "sonnet").
hooksHookConfigno{}Pre/post tool use hook definitions.
sandboxPersonaSandboxnonullPer-persona network sandbox settings.

PersonaSandbox

FieldTypeRequiredDefaultDescription
allowed_domains[]stringno[]Network domains this persona is allowed to access. Merged with runtime.sandbox.default_allowed_domains.

Built-in Persona Archetypes

yaml
personas:
  # Read-only codebase analysis
  navigator:
    adapter: claude
    description: "Codebase exploration and analysis"
    system_prompt_file: .wave/personas/navigator.md
    temperature: 0.1
    permissions:
      allowed_tools: ["Read", "Glob", "Grep", "Bash(git log*)", "Bash(git status*)"]
      deny: ["Write(*)", "Edit(*)", "Bash(git commit*)", "Bash(git push*)"]

  # Design and specification
  philosopher:
    adapter: claude
    description: "Architecture design and specification"
    system_prompt_file: .wave/personas/philosopher.md
    temperature: 0.3
    permissions:
      allowed_tools: ["Read", "Write(.wave/specs/*)"]
      deny: ["Bash(*)"]

  # Implementation with full write access
  craftsman:
    adapter: claude
    description: "Code implementation and testing"
    system_prompt_file: .wave/personas/craftsman.md
    temperature: 0.7
    permissions:
      allowed_tools: ["Read", "Write", "Edit", "Bash"]
      deny: ["Bash(rm -rf /*)"]

  # Security and quality review
  auditor:
    adapter: claude
    description: "Security review and quality assurance"
    system_prompt_file: .wave/personas/auditor.md
    temperature: 0.1
    permissions:
      allowed_tools: ["Read", "Grep", "Bash(npm audit*)", "Bash(go vet*)"]
      deny: ["Write(*)", "Edit(*)"]

  # Context relay summarizer
  summarizer:
    adapter: claude
    description: "Context compaction for relay handoffs"
    system_prompt_file: .wave/personas/summarizer.md
    temperature: 0.0
    permissions:
      allowed_tools: ["Read"]
      deny: ["Write(*)", "Bash(*)"]

Permissions

Tool access control applied to an adapter or persona.

FieldTypeRequiredDefaultDescription
allowed_tools[]stringno["*"] (all)Glob patterns for allowed tool calls.
deny[]stringno[]Glob patterns for denied tool calls. Always takes precedence over allowed_tools.

Evaluation Order

  1. Check deny patterns first. If any deny pattern matches → blocked.
  2. Check allowed_tools. If any allowed pattern matches → permitted.
  3. If no pattern matches → blocked (implicit deny).

Pattern Syntax

Patterns use glob matching against tool call signatures:

PatternMatches
ReadAll Read tool calls
Write(*)All Write tool calls (any path)
Write(src/*.ts)Write calls to TypeScript files in src/
Bash(git *)Bash calls starting with git
Bash(npm test*)Bash calls starting with npm test
*All tool calls

Permission Inheritance

Adapter default_permissions
    ↓ (base)
Persona permissions
    ↓ (override)
Effective permissions

Persona deny patterns are additive — they combine with adapter-level denies. Persona allowed_tools replace adapter-level allowed tools when specified.


HookConfig

Pre/post tool execution hooks. Hooks execute shell commands triggered by tool call patterns.

FieldTypeRequiredDefaultDescription
PreToolUse[]HookRuleno[]Hooks that fire before a tool call executes.
PostToolUse[]HookRuleno[]Hooks that fire after a tool call completes.

HookRule

FieldTypeRequiredDescription
matcherstringyesGlob pattern matching tool call signatures. Same syntax as Permissions.
commandstringyesShell command to execute. Must be a script on disk or inline command.

Hook Behavior

  • PreToolUse: If the command exits non-zero, the tool call is blocked. The agent receives a permission denial message.
  • PostToolUse: Informational only. Exit code is logged but does not block execution.

Hook Example

yaml
personas:
  craftsman:
    adapter: claude
    system_prompt_file: .wave/personas/craftsman.md
    hooks:
      PreToolUse:
        # Block destructive filesystem operations
        - matcher: "Bash(rm -rf *)"
          command: ".wave/hooks/block-destructive.sh"
        # Require linting before any commit
        - matcher: "Bash(git commit*)"
          command: ".wave/hooks/pre-commit-lint.sh"
      PostToolUse:
        # Run tests after file writes
        - matcher: "Write(src/**)"
          command: "npm test --silent"
        # Log all bash invocations
        - matcher: "Bash(*)"
          command: ".wave/hooks/log-bash.sh"

Runtime

Global runtime settings governing execution behavior.

FieldTypeRequiredDefaultDescription
workspace_rootstringno".wave/workspaces"Root directory for ephemeral workspaces. Each pipeline run creates subdirectories here.
max_concurrent_workersintno5Maximum parallel matrix strategy workers. Range: 110.
default_timeout_minutesintno5Default per-step timeout. Steps exceeding this are killed (entire process group).
relayRelayConfignosee defaultsContext relay/compaction settings.
auditAuditConfignosee defaultsAudit logging settings.
meta_pipelineMetaPipelineConfignosee defaultsMeta-pipeline recursion and resource limits.
routingRoutingConfignosee defaultsPipeline routing rules for matching inputs to pipelines.
sandboxRuntimeSandboxnosee defaultsSandbox settings including env passthrough and domain allowlisting.
artifactsRuntimeArtifactsConfignosee defaultsGlobal artifact handling configuration.
pipeline_id_hash_lengthintno4Length of hash suffix appended to pipeline workspace IDs.
timeoutsTimeoutsnosee defaultsFine-grained timeout configuration for all Wave operations.

RelayConfig

FieldTypeRequiredDefaultDescription
token_threshold_percentintno80Context utilization percentage that triggers relay. Range: 5095.
strategystringno"summarize_to_checkpoint"Compaction strategy. Currently only "summarize_to_checkpoint".
context_windowintno0Context window size in tokens. 0 uses adapter default.
summarizer_personastringno""Persona to use for relay summarization. Must reference a key in personas.

AuditConfig

FieldTypeRequiredDefaultDescription
log_dirstringno".wave/traces/"Directory for audit trail files. Created automatically.
log_all_tool_callsboolnofalseLog every tool invocation with arguments and results.
log_all_file_operationsboolnofalseLog every file read, write, and delete with paths.

Credential Scrubbing

Audit logs never capture environment variable values or credential content. Known credential patterns (*_KEY, *_TOKEN, *_SECRET, *_PASSWORD) are automatically redacted.

MetaPipelineConfig

FieldTypeRequiredDefaultDescription
max_depthintno2Maximum recursion depth for meta-pipeline generation. A meta-pipeline spawning another meta-pipeline counts as depth+1.
max_total_stepsintno20Maximum total steps across all recursion levels.
max_total_tokensintno500000Maximum total token consumption across all meta-pipeline levels.
timeout_minutesintno60Hard timeout for entire meta-pipeline tree.

RoutingConfig

FieldTypeRequiredDefaultDescription
defaultstringno""Pipeline to use when no routing rules match.
rules[]RoutingRuleno[]Routing rules evaluated in priority order.

RoutingRule

FieldTypeRequiredDefaultDescription
patternstringno""Glob pattern for matching input strings. Supports *, ?, [abc], [a-z].
pipelinestringyesPipeline name to route to when this rule matches.
priorityintno0Evaluation order. Higher priority rules are evaluated first.
match_labelsmap[string]stringno{}Label key-value patterns that must all match. Keys are exact matches, values support glob patterns.

RuntimeSandbox

FieldTypeRequiredDefaultDescription
enabledboolnofalseEnable sandbox mode for adapter subprocesses.
default_allowed_domains[]stringno[]Network domain allowlist applied to all personas.
env_passthrough[]stringno[]Environment variables passed through to adapter subprocesses.

RuntimeArtifactsConfig

FieldTypeRequiredDefaultDescription
max_stdout_sizeintno10485760Maximum bytes to capture from stdout (default: 10MB).
default_artifact_dirstringno".wave/artifacts"Base directory for artifacts.

Timeouts

Fine-grained timeout configuration. All values fall back to built-in defaults in internal/timeouts/ when omitted or zero.

FieldTypeDefaultDescription
step_default_minutesint5Default per-step execution timeout.
relay_compaction_minutesint5Context compaction/summarization timeout.
meta_default_minutesint30Meta-pipeline generation timeout.
skill_install_secondsint120Skill auto-install timeout during preflight.
skill_cli_secondsint120Skill CLI command execution timeout.
skill_http_secondsint120Skill HTTP source fetch timeout.
skill_http_header_secondsint30Skill HTTP header-only probe timeout.
skill_publish_secondsint30tessl publish command timeout.
process_grace_secondsint3Grace period between SIGTERM and SIGKILL for adapter subprocesses.
stdout_drain_secondsint1Post-cancel stdout drain wait.
gate_approval_hoursint24Maximum wait for manual gate approval.
gate_poll_interval_secondsint30Poll interval for command-based gates.
gate_poll_timeout_minutesint30Maximum poll duration for command-based gates.
git_command_secondsint30Timeout for git subprocess calls (diff, log, etc.).
forge_api_secondsint15Timeout for forge API calls (GitHub, GitLab, Bitbucket, Gitea).
retry_max_delay_secondsint60Cap on exponential backoff delay between retries.

Full Runtime Example

yaml
runtime:
  workspace_root: .wave/workspaces
  max_concurrent_workers: 5
  default_timeout_minutes: 5
  timeouts:
    step_default_minutes: 5
    relay_compaction_minutes: 5
    meta_default_minutes: 30
    skill_install_seconds: 120
    process_grace_seconds: 3
    forge_api_seconds: 15
    retry_max_delay_seconds: 60
  relay:
    token_threshold_percent: 80
    strategy: summarize_to_checkpoint
  audit:
    log_dir: .wave/traces/
    log_all_tool_calls: true
    log_all_file_operations: true
  meta_pipeline:
    max_depth: 2
    max_total_steps: 20
    max_total_tokens: 500000
    timeout_minutes: 60

Pipeline Requires

Pipelines can declare tool and skill dependencies via a requires block. These are validated at preflight time before any step executes.

FieldTypeRequiredDescription
requires.skills[]stringnoSkill names that must be installed. Resolved by the skill discovery system at preflight time.
requires.tools[]stringnoCLI tool names that must be available on $PATH (checked via exec.LookPath).

Requires Example

yaml
kind: WavePipeline
metadata:
  name: impl-speckit
requires:
  skills: [speckit]
  tools: [git, go]
steps:
  - id: specify
    # ...

Workspace Types

Steps can use different workspace isolation strategies via the workspace.type field.

TypeDescription
(empty)Default directory-based workspace under runtime.workspace_root. Supports mount for bind-mounting source directories.
worktreeCreates a git worktree for full repository isolation. Each step gets its own branch and working copy.

Worktree Workspace Fields

FieldTypeRequiredDefaultDescription
workspace.typestringno""Set to "worktree" for git worktree isolation.
workspace.branchstringnowave/<pipelineID>/<stepID>Branch name for the worktree. Supports template placeholder resolution.

Worktree Example

yaml
steps:
  - id: implement
    persona: craftsman
    workspace:
      type: worktree
      branch: "feat/{{ pipeline_name }}"
    exec:
      type: prompt
      source: "Implement the feature on this isolated branch."

Agent Concurrency

Steps can configure the maximum number of concurrent sub-agents the persona may spawn via max_concurrent_agents.

FieldTypeRequiredDefaultDescription
max_concurrent_agentsintno0Maximum concurrent sub-agents for this step. Values > 1 inject a concurrency hint into the persona's system prompt. Capped at 10.

When max_concurrent_agents is set to a value greater than 1, the generated CLAUDE.md includes:

You may spawn up to N concurrent sub-agents or workers for this step.

Values of 0 or 1 produce no hint (default single-agent behavior).

Agent Concurrency Example

yaml
steps:
  - id: implement
    persona: craftsman
    max_concurrent_agents: 6
    exec:
      type: prompt
      source: "Implement the feature using parallel sub-agents."

Slash Command Exec Type

Steps can invoke skill slash commands instead of inline prompts via exec.type: slash_command.

FieldTypeRequiredDescription
exec.typestringyesSet to "slash_command" to invoke a skill command.
exec.commandstringyesSlash command name (e.g., speckit.specify). Automatically prefixed with / if missing.
exec.argsstringnoArguments passed to the slash command. Supports {{ input }} placeholder.

Slash Command Example

yaml
steps:
  - id: specify
    persona: implementer
    exec:
      type: slash_command
      command: speckit.specify
      args: "{{ input }}"

Validation Rules

wave validate checks the following rules:

#RuleSeverityDescription
1Adapter referenceerrorEvery persona must reference a defined adapter key.
2System prompt existserrorEvery persona's system_prompt_file must exist on disk.
3Hook scripts existerrorEvery hook command script must exist on disk (if it's a file path, not inline).
4Binary on PATHwarningAdapter binary should be resolvable on $PATH.
5No circular refserrorNo circular persona or pipeline references.
6Required fieldserrorAll required fields must be present and non-empty.
7Type correctnesserrorFields must match expected types (string, int, float, array, map).
8Value rangeserrorNumeric fields must be within valid ranges (e.g., temperature 0.0–1.0).

Complete Example

yaml
apiVersion: v1
kind: WaveManifest
metadata:
  name: acme-backend
  description: "Acme Corp backend API — Go microservices"
  repo: https://github.com/acme/backend

adapters:
  claude:
    binary: claude
    mode: headless
    output_format: json
    project_files:
      - CLAUDE.md
      - .claude/settings.json
    default_permissions:
      allowed_tools: ["Read", "Write", "Edit", "Bash"]
      deny: []
    hooks_template: .wave/hooks/claude/

personas:
  navigator:
    adapter: claude
    description: "Read-only codebase exploration"
    system_prompt_file: .wave/personas/navigator.md
    temperature: 0.1
    permissions:
      allowed_tools: ["Read", "Glob", "Grep", "Bash(git *)"]
      deny: ["Write(*)", "Edit(*)", "Bash(rm *)"]

  philosopher:
    adapter: claude
    description: "Architecture and specification design"
    system_prompt_file: .wave/personas/philosopher.md
    temperature: 0.3
    permissions:
      allowed_tools: ["Read", "Write(.wave/specs/*)"]
      deny: ["Bash(*)"]

  craftsman:
    adapter: claude
    description: "Implementation and testing"
    system_prompt_file: .wave/personas/craftsman.md
    temperature: 0.7
    permissions:
      allowed_tools: ["Read", "Write", "Edit", "Bash"]
      deny: ["Bash(rm -rf /*)"]
    hooks:
      PreToolUse:
        - matcher: "Bash(git commit*)"
          command: ".wave/hooks/pre-commit-lint.sh"
      PostToolUse:
        - matcher: "Write(src/**)"
          command: "go test ./..."

  auditor:
    adapter: claude
    description: "Security and quality review"
    system_prompt_file: .wave/personas/auditor.md
    temperature: 0.1
    permissions:
      allowed_tools: ["Read", "Grep", "Bash(go vet*)"]
      deny: ["Write(*)", "Edit(*)"]

  summarizer:
    adapter: claude
    description: "Relay checkpoint summarizer"
    system_prompt_file: .wave/personas/summarizer.md
    temperature: 0.0
    permissions:
      allowed_tools: ["Read"]
      deny: ["Write(*)", "Bash(*)"]

runtime:
  workspace_root: .wave/workspaces
  max_concurrent_workers: 5
  default_timeout_minutes: 5
  relay:
    token_threshold_percent: 80
    strategy: summarize_to_checkpoint
  audit:
    log_dir: .wave/traces/
    log_all_tool_calls: true
    log_all_file_operations: false
  meta_pipeline:
    max_depth: 2
    max_total_steps: 20
    max_total_tokens: 500000
    timeout_minutes: 60

Released under the MIT License.