Skip to content
Weaveweave / docs
Get started ↗
Docs/Guides/Prompt Composition

Prompt Composition

How Weave builds agent prompts from templates, delegation targets, and configuration

Weave composes each agent’s final prompt before execution by combining prompt sources, rendering templates, and injecting delegation routing guidance. This guide explains how prompt composition works, what template features are supported, and how to customize agent prompts safely.

The Weave engine builds a complete prompt for each agent by:

  1. Loading the primary prompt source (inline prompt or prompt_file)
  2. Rendering Mustache template tags with context from configuration
  3. Generating delegation targets from agent triggers
  4. Appending optional additional instructions (prompt_append or prompt_append_file)
  5. Evaluating tool policy into concrete permissions

The output is a normalized agent descriptor containing the final prompt text and all metadata needed by the execution harness.

Every agent must declare exactly one primary prompt source:

  • prompt: Inline prompt text in the agent configuration
  • prompt_file: Path to a Markdown file containing the prompt
agent reviewer {
prompt "Review code changes for quality and security."
# OR
prompt_file "prompts/reviewer.md"
}

If neither is declared, composition fails with PromptSourceMissingError.

Agents can optionally append additional instructions after the primary prompt:

  • prompt_append: Inline append text
  • prompt_append_file: Path to a Markdown file containing append text
agent reviewer {
prompt_file "prompts/reviewer.md"
prompt_append "Focus on security vulnerabilities."
# OR
prompt_append_file "prompts/security-focus.md"
}

prompt_append and prompt_append_file are mutually exclusive. Only one may be declared per agent.

All prompt sources (primary and append) are rendered as Mustache templates before execution. Templates can reference bounded context fields to customize prompts based on agent configuration.

Weave supports these Mustache features:

  • Escaped variables: {{agent.name}} renders with HTML escaping
  • Unescaped variables: {{{delegation.section}}} renders without escaping (use for Markdown content)
  • Dotted paths: {{agent.name}}, {{toolPolicy.effective.read}}
  • Sections: {{#delegation.targets}}...{{/delegation.targets}} for conditionals and iteration
  • Inverted sections: {{^delegation.targets}}...{{/delegation.targets}} for negation
  • Comments: {{! This is a comment }}
  • Current item: {{.}} inside list sections

These features are explicitly rejected and cause composition to fail:

  • Partials: {{> footer}} (cannot load external content)
  • Delimiter changes: {{=<% %>=}} (cannot bypass path validation)
  • Lambdas: No executable behavior, function calls, or dynamic logic
  • Filesystem access: Templates cannot read files or environment variables

Use a backslash to render a literal Mustache tag without template expansion:

To reference an agent, use \{{agent.name}} in your template.

This renders as {{agent.name}} in the final prompt.

Templates are rendered against a bounded context containing only safe, public fields from agent configuration. This is a security boundary: templates cannot access raw config, environment variables, or runtime state.

Path Type Description
agent.name string Stable internal agent identifier
agent.description string? Optional agent description
agent.mode "primary" | "subagent" | "all" Agent mode hint
agent.skills string[] Requested skill names
agent.isCategory boolean True for category shuttle agents
category.name string? Category name (only for category agents)
category.description string? Category description (only for category agents)
toolPolicy.effective.read "allow" | "deny" | "ask" Resolved read permission
toolPolicy.effective.write "allow" | "deny" | "ask" Resolved write permission
toolPolicy.effective.execute "allow" | "deny" | "ask" Resolved execute permission
toolPolicy.effective.delegate "allow" | "deny" | "ask" Resolved delegation permission
toolPolicy.effective.network "allow" | "deny" | "ask" Resolved network permission
delegation.targets array List of eligible delegation targets (see below)

Each item in delegation.targets has these fields:

Path Type Description
name string Target agent name
description string? Optional target description
domains string[] Domains this target handles
triggers array List of trigger patterns

Each trigger in triggers has:

Path Type Description
domain string Domain this trigger belongs to
trigger string Trigger pattern
routing_hint string? Optional routing guidance

Inside list sections, Mustache context-stack rules apply:

{{#delegation.targets}}
- **{{name}}**: {{description}}
Domains: {{#domains}}{{.}}{{^last}}, {{/last}}{{/domains}}
{{/delegation.targets}}

Inside {{#delegation.targets}}, {{name}} resolves to the current target’s name. For scalar lists like domains, use {{.}} to render each item.

When an agent has tool_policy.delegate = "allow", Weave generates a list of eligible delegation targets based on other agents’ triggers. Templates can iterate over this list to render routing guidance.

## Delegation
You can delegate tasks to these specialized agents:
{{#delegation.targets}}
### {{name}}
{{#description}}{{description}}{{/description}}
**Domains**: {{#domains}}{{.}}{{^last}}, {{/last}}{{/domains}}
**Triggers**:
{{#triggers}}
- `{{trigger}}`{{#routing_hint}} - {{routing_hint}}{{/routing_hint}}
{{/triggers}}
{{/delegation.targets}}
{{^delegation.targets}}
No delegation targets are available.
{{/delegation.targets}}

This renders a complete delegation section with target names, descriptions, domains, and trigger patterns. If no targets are available, it renders a fallback message.

Weave automatically filters delegation targets using these rules:

  1. Exclude self: An agent cannot delegate to itself
  2. Exclude disabled agents: Agents in disabled.agents are removed
  3. Exclude primary agents: Agents with mode: "primary" are not delegation targets
  4. Exclude shuttle agents from shuttles: The shared shuttle agent and category shuttles do not advertise each other

Final agent prompt text is assembled in this order:

  1. Rendered primary prompt source (prompt or prompt_file)
  2. Rendered append source (prompt_append or prompt_append_file), if present

Both sources are rendered with the same template context. The two parts are joined with a blank line (\n\n).

Workflow steps can also declare prompts and appends. Step composition follows these precedence rules:

Step has append? Workflow has append? Effective append Source
yes any step’s append step-local
no yes workflow’s append workflow fallback
no no none none

Step-local wins: If a step declares its own prompt_append or prompt_append_file, the workflow-level append is completely suppressed for that step.

Example: Step-local wins

workflow secure-feature {
version 1
prompt_append "Always write tests."
step implement {
name "Implement"
type autonomous
agent shuttle
prompt "Execute the plan."
prompt_append "Focus on security."
completion agent_signal
}
}

Composed prompt for implement step:

Execute the plan.
Focus on security.

The workflow-level "Always write tests." is suppressed.

Example: Workflow fallback

workflow secure-feature {
version 1
prompt_append "Always write tests."
step review {
name "Review"
type gate
agent weft
prompt "Review the changes."
completion review_verdict
on_reject pause
}
}

Composed prompt for review step:

Review the changes.
Always write tests.

The workflow-level append is applied because the step has no append of its own.

Template rendering enforces a strict security boundary. Templates can only reference paths in the explicit allowed-path set.

Templates can reference:

  • {{agent.name}}, {{agent.mode}}, {{agent.skills}}, {{agent.isCategory}}
  • {{category.name}}, {{category.description}}
  • {{toolPolicy.effective.read}} (and other capability fields)
  • {{#delegation.targets}} iteration and nested fields

These paths are explicitly rejected with UnknownPath errors:

  • {{artifact.contents}} (artifact data is not in context)
  • {{chat.history}} (chat history is not in context)
  • {{raw.prompt}} (raw prompt text is not in context)
  • Any path not in the allowed-path set

These paths are rejected with UnsafePath errors:

  • {{__proto__}}, {{constructor}}, {{prototype}} (prototype traversal)

Static append text without Mustache tags is always safe and passes through unchanged.

Template failures are reported as typed errors with detailed context:

  • MalformedSyntax: Invalid Mustache syntax (e.g., unclosed tags)
  • UnsupportedTag: Partial or delimiter change detected
  • UnknownPath: Path not in allowed-path set (e.g., {{agnt.name}})
  • UnsafePath: Prototype traversal attempt
  • FunctionValue: Template tried to call a function
  • SectionMismatch: Mismatched section tags (e.g., {{#foo}}...{{/bar}})
  • UnresolvedTag: Mustache tag remained in rendered output

Template errors include:

  • Agent name
  • Source kind (prompt, prompt_file, prompt_append, prompt_append_file)
  • File path (when source is a file)
  • Line and column (when available)
  • Offending tag or path

Because rendering uses schema-aware strict paths:

  • {{agent.name}} succeeds
  • {{agnt.name}} fails as unknown path (typo detection)
  • {{#category}}...{{/category}} is valid and falsey for non-category agents
  • {{agent.__proto__}} fails as unsafe path

Here’s a complete custom prompt with delegation rendering:

# Code Reviewer
You are a specialized code review agent. Your role is to analyze code changes for quality, security, and maintainability.
## Your Capabilities
- **Read**: {{toolPolicy.effective.read}}
- **Write**: {{toolPolicy.effective.write}}
- **Execute**: {{toolPolicy.effective.execute}}
- **Delegate**: {{toolPolicy.effective.delegate}}
## Review Guidelines
1. Check for security vulnerabilities
2. Verify test coverage
3. Ensure code follows project conventions
4. Look for performance issues
{{#delegation.targets}}
## Delegation
When you encounter specialized concerns, delegate to these agents:
{{#delegation.targets}}
### {{name}}
{{#description}}{{description}}{{/description}}
**Handles**: {{#domains}}{{.}}{{^last}}, {{/last}}{{/domains}}
**Delegate when**:
{{#triggers}}
- {{trigger}}{{#routing_hint}} ({{routing_hint}}){{/routing_hint}}
{{/triggers}}
{{/delegation.targets}}
{{/delegation.targets}}
## Output Format
Provide your review as:
- **APPROVE** if changes are acceptable
- **BLOCK** if changes require fixes
Include specific feedback for any issues found.

This template:

  • References tool policy to explain capabilities
  • Conditionally renders delegation section only when targets exist
  • Iterates over targets with nested field access
  • Uses unescaped triple braces for Markdown content
  • Provides clear output format guidance

Only use template tags where they improve prompt clarity. Don’t add artificial tags just to prove templating works.

Use triple braces {{{...}}} for Markdown-rich values to avoid unwanted HTML escaping:

{{#category}}
{{{category.description}}}
{{/category}}

Use sections to test for optional fields:

{{#agent.description}}
Description: {{agent.description}}
{{/agent.description}}

Use {{#delegation.targets}} loops instead of hardcoding target lists that could diverge from configuration.

Use prompt_append for narrow, context-specific guidance. Keep the primary prompt general and reusable.