YAML Template Reference¶
agentd supports declarative YAML templates for defining agents and workflows. Templates live in a .agentd/ directory in your project root and can be applied with a single command.
Directory Convention¶
.agentd/
├── rooms/
│ └── engineering.yml # room (created before agents)
├── agents/
│ ├── planner.yml # planning agent (can reference rooms by name)
│ └── worker.yml # worker agent
└── workflows/
└── issue-worker.yml # GitHub issue workflow (references worker agent)
rooms/- Room definitions. Each file creates one room and its initial participants.agents/- Agent definitions. Each file creates one agent. Agents can listroomsto auto-join.workflows/- Workflow definitions. Each file creates one workflow that references an agent by name.
Commands¶
Apply¶
Create rooms, agents, and workflows from templates:
# Apply entire project (rooms first, then agents, then workflows)
agent apply .agentd/
# Apply a single file
agent apply .agentd/rooms/engineering.yml
agent apply .agentd/agents/worker.yml
agent apply .agentd/workflows/issue-worker.yml
# Validate without creating anything
agent apply --dry-run .agentd/
# Custom timeout for agent startup (default: 60s)
agent apply --wait-timeout 120 .agentd/
Apply order for directories:
- Parse and validate all templates (fail fast - no partial creates on error)
- Create rooms from
rooms/*.yml(and add their initial participants) - Create agents from
agents/*.yml, joining them to any listed rooms - Wait for all agents to reach
runningstatus - Create workflows from
workflows/*.yml, resolving agent name references - Print summary
If a room or agent with the same name already exists, it is reused (not duplicated).
Teardown¶
Delete resources in reverse order (workflows → agents → rooms):
Agent Template Schema¶
File: .agentd/agents/<name>.yml
# Required
name: worker # Agent name (must be unique)
# Optional - all have sensible defaults
working_dir: "." # Resolved relative to YAML file location
shell: zsh # Shell to use (default: zsh)
interactive: false # Interactive mode (default: false)
worktree: false # Use git worktree (default: false)
# Optional - grant access to directories outside working_dir
additional_dirs:
- ../shared-libraries # relative: resolved relative to this YAML file
- /opt/company/configs # absolute: used as-is
- ~/other-project # tilde: expanded to home directory
# Optional - no default
prompt: "Analyze the codebase" # Initial prompt sent after agent connects
system_prompt: | # System prompt for the agent session
You are a code review agent.
Focus on security and performance.
# Optional - defaults to allow_all
tool_policy:
mode: allow_list # allow_all | deny_all | allow_list | deny_list | require_approval
tools: # Only for allow_list / deny_list modes
- Read
- Grep
- Glob
Field Reference¶
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | required | Unique agent name |
working_dir |
string | "." |
Working directory. "." resolves to $PWD |
additional_dirs |
list | [] |
Extra directories the agent can access (see Additional Directories) |
shell |
string | "zsh" |
Shell for the tmux session |
interactive |
bool | false |
Run in interactive mode (no WebSocket) |
worktree |
bool | false |
Start with --worktree for isolated git worktree |
prompt |
string | none | Initial prompt sent via WebSocket after connection |
system_prompt |
string | none | System prompt for the Claude session |
tool_policy |
object | allow_all |
Tool use restrictions (see Tool Policies) |
rooms |
list | [] |
Rooms the agent automatically joins at startup (see Room Membership) |
Room Membership¶
The rooms field lists rooms the agent should automatically join when it starts. Each entry is either a plain room name (defaults to member role) or a structured object with an explicit role:
rooms:
- engineering # plain string - member role
- name: announcements
role: observer # read-only access
- name: ops-channel
role: admin
Rooms referenced here must exist before the agent starts. When using agent apply .agentd/, rooms listed in .agentd/rooms/ are created first. If you apply an agent template independently, create the room first:
agent communicate create-room --name engineering --created-by cli
agent apply .agentd/agents/worker.yml
Available roles:
| Role | Can post | Can manage participants |
|---|---|---|
member |
Yes | No |
admin |
Yes | Yes |
observer |
No (read-only) | No |
Working Directory Resolution¶
"."→ resolves to the current working directory ($PWD) at apply time- Relative paths → resolved relative to the YAML file's directory
- Absolute paths → used as-is
The same resolution rules apply to each entry in additional_dirs. See Additional Directories for full details.
Room Template Schema¶
File: .agentd/rooms/<name>.yml
# Required
name: engineering # Room name (must be unique)
# Optional
topic: "Engineering coordination" # Short label shown in listings
description: | # Longer description
General channel for engineering agents and humans.
type: group # direct | group (default) | broadcast
# Optional - participants added when the room is first created
participants:
- identifier: alice # Human username or agent UUID/name
kind: human # agent (default) | human
role: admin # member (default) | admin | observer
display_name: "Alice" # Optional; defaults to identifier
- identifier: worker
kind: agent
role: member
Field Reference¶
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | required | Unique room name |
topic |
string | none | Short label |
description |
string | none | Longer description |
type |
string | "group" |
"direct", "group", or "broadcast" |
participants |
list | [] |
Initial participants added at creation time |
Participant fields¶
| Field | Type | Default | Description |
|---|---|---|---|
identifier |
string | required | Agent UUID/name or human username |
kind |
string | "agent" |
"agent" or "human" |
role |
string | "member" |
"member", "admin", or "observer" |
display_name |
string | identifier |
Display name shown in messages |
Idempotent creation
If a room with the given name already exists, agent apply skips creation entirely - it does not add participants or update the topic/description. To modify an existing room, use the CLI or REST API directly.
Room types¶
| Type | Who can post | Use case |
|---|---|---|
group |
All members | Collaborative agent teams, human-agent coordination |
direct |
Both participants | One-to-one agent ↔ human or agent ↔ agent conversation |
broadcast |
Admins only | Status feeds, announcement channels |
Workflow Template Schema¶
File: .agentd/workflows/<name>.yml
# Required
name: issue-worker # Unique workflow name
agent: worker # Agent NAME (resolved to UUID at apply time)
source:
type: github_issues
owner: myorg
repo: myrepo
labels: # Optional - filter issues by label
- agent
state: open # Optional - default: open
# Required (one of these)
prompt_template: | # Inline prompt with {{variables}}
Fix issue #{{source_id}}: {{title}}
{{body}}
# OR
prompt_template_file: ../prompts/worker.txt # Relative to YAML file
# Optional
poll_interval: 60 # Seconds between polls (default: 60)
enabled: true # Start polling immediately (default: true)
# Optional - defaults to allow_all
tool_policy:
mode: allow_all
Field Reference¶
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | required | Unique workflow name |
agent |
string | required | Agent name (resolved to UUID via API) |
source |
object | required | Task source configuration |
prompt_template |
string | see below | Inline prompt template |
prompt_template_file |
string | see below | Path to external template file |
poll_interval |
integer | 60 |
Seconds between source polls |
enabled |
bool | true |
Start polling on creation |
tool_policy |
object | allow_all |
Tool policy applied before each dispatch |
One of prompt_template or prompt_template_file is required.
Template Variables¶
Available {{placeholders}} in prompt templates:
Task fields - present for all trigger types:
| Variable | Description | Example |
|---|---|---|
{{title}} |
Task title | "Fix login bug" |
{{body}} |
Task body | Full markdown content |
{{url}} |
Source URL | "https://github.com/org/repo/issues/42" |
{{labels}} |
Comma-separated labels | "bug, auth" |
{{assignee}} |
Assigned user (or empty) | "alice" |
{{source_id}} |
Source identifier | "42" |
{{metadata}} |
All metadata as key: value lines |
"fire_time: 2026-04-01T09:00:00Z" |
Schedule trigger variables - populated by cron and delay triggers:
| Variable | Trigger | Description | Example |
|---|---|---|---|
{{fire_time}} |
cron |
RFC 3339 timestamp when the cron fired | 2026-04-01T09:00:00Z |
{{cron_expression}} |
cron |
The cron expression that fired | 0 9 * * MON-FRI |
{{run_at}} |
delay |
Scheduled datetime from the trigger config | 2026-04-01T09:00:00Z |
{{workflow_id}} |
delay |
UUID of the workflow | 550e8400-... |
Webhook trigger variables - populated by the webhook trigger:
| Variable | Trigger | Description | Example |
|---|---|---|---|
{{delivery_id}} |
webhook |
Delivery ID from X-GitHub-Delivery header or auto-generated UUID |
abc-123 |
{{timestamp}} |
webhook |
RFC 3339 time the webhook was received | 2026-04-01T09:00:00Z |
{{github_event}} |
webhook (GitHub) |
GitHub event type | issues |
{{action}} |
webhook (GitHub) |
GitHub action | opened |
{{issue_number}} |
webhook (GitHub issues) |
Issue number | 42 |
{{pr_number}} |
webhook (GitHub PRs) |
Pull request number | 99 |
Linear trigger variables - populated by the linear_issues trigger:
| Variable | Description | Example |
|---|---|---|
{{identifier}} |
Linear issue identifier | ENG-123 |
{{state}} |
Linear issue state name | Todo, In Progress |
{{priority}} |
Priority level (0 = none, 1 = urgent, 2 = high, 3 = medium, 4 = low) | 2 |
{{team}} |
Linear team key | ENG |
{{team_name}} |
Linear team display name | Engineering |
{{project}} |
Linear project name | Backend |
{{linear_id}} |
Internal Linear UUID (stable dedup key) | abc-uuid-... |
Event trigger variables - populated by agent_lifecycle and dispatch_result triggers:
| Variable | Trigger | Description | Example |
|---|---|---|---|
{{event_type}} |
agent_lifecycle |
Lifecycle event name | session_start |
{{agent_id}} |
agent_lifecycle |
UUID of the agent that fired the event | 550e8400-... |
{{timestamp}} |
agent_lifecycle, dispatch_result |
RFC 3339 timestamp of the event | 2026-04-01T09:00:00Z |
{{source_workflow_id}} |
dispatch_result |
UUID of the workflow that completed | a1b2c3d4-... |
{{dispatch_id}} |
dispatch_result |
UUID of the dispatch record | b2c3d4e5-... |
{{status}} |
dispatch_result |
Completion status | completed |
{{original_source_id}} |
dispatch_result |
Source ID from the parent dispatch (e.g. GitHub issue or PR number). Absent when the parent had no task-level source identifier. | 42 |
Note
Schedule and event trigger variables are stored in the task's metadata map and resolved during template rendering. If a variable is referenced but not present for the trigger type (e.g. {{fire_time}} in a delay workflow), the placeholder is left as-is in the rendered prompt.
Validate templates before creating workflows:
agent orchestrator validate-template "Fix: {{title}}\n{{body}}"
agent orchestrator validate-template --file ./my-template.txt
Source Configuration¶
Supported sources:
GitHub Issues:
source:
type: github_issues
owner: myorg # GitHub user or organization
repo: myrepo # Repository name
labels: [bug, agent] # Filter by labels (optional)
state: open # Issue state filter (default: open)
GitHub Pull Requests:
source:
type: github_pull_requests
owner: myorg # GitHub user or organization
repo: myrepo # Repository name
labels: [needs-review] # Filter by labels (optional)
state: open # PR state filter (default: open)
Cron (recurring schedule):
Delay (one-shot):
See Schedule Triggers for full syntax reference, common expression examples, and operational notes.
Webhook:
See Webhook Triggers for endpoint details, HMAC verification, payload parsing, and GitHub setup.
Manual:
See Manual Triggers for the trigger-workflow CLI command and the POST /workflows/{id}/trigger API endpoint.
Linear Issues:
source:
type: linear_issues
team_key: ENG # Linear team key filter (optional but at least one filter required)
project: Backend # Project name filter (optional)
status: [Todo, "In Progress"] # Issue status filter (optional)
labels: [bug] # Label filter - issue must carry all listed labels (optional)
assignee: alice@example.com # Assignee display name or email (optional)
Requires AGENTD_LINEAR_API_KEY to be set in the environment. At least one filter field must be provided. Linear-specific variables ({{identifier}}, {{state}}, {{priority}}, {{team}}, {{team_name}}, {{project}}, {{linear_id}}) are available in the prompt template.
Event-driven triggers (API only)
The agent_lifecycle and dispatch_result trigger types are configured via the REST API only. They are not supported in .agentd/ YAML templates. See Event-Driven Triggers.
Tool Policies¶
Control which tools an agent can use. Set on agents at creation or on workflows for dispatch-time enforcement.
| Mode | YAML | Effect |
|---|---|---|
| Allow all | mode: allow_all |
No restrictions (default) |
| Deny all | mode: deny_all |
Block all tool usage |
| Allow list | mode: allow_list |
Only listed tools permitted |
| Deny list | mode: deny_list |
All tools except listed ones |
| Require approval | mode: require_approval |
Human must approve each tool use |
Example - read-only agent:
Example - block dangerous tools:
Example - human oversight:
With require_approval, every tool request is held pending until a human approves or denies it:
agent orchestrator list-approvals
agent orchestrator approve <APPROVAL_ID>
agent orchestrator deny <APPROVAL_ID>
Unanswered approvals auto-deny after 5 minutes.
Complete Example¶
The agentd project itself uses templates in .agentd/:
.agentd/agents/worker.yml¶
name: worker
working_dir: "."
shell: /bin/zsh
worktree: false
system_prompt: |
You are a worker agent for the agentd project. You will receive
GitHub issues as tasks. For each issue:
1. Read the issue carefully
2. Plan your approach
3. Implement the change
4. Run tests
5. Create a branch, commit, and push
6. Create a PR using the gh CLI
.agentd/workflows/issue-worker.yml¶
name: issue-worker
agent: worker
source:
type: github_issues
owner: geoffjay
repo: agentd
labels: [agent]
state: open
poll_interval: 60
enabled: true
prompt_template: |
Work on the following GitHub issue:
Issue #{{source_id}}: {{title}}
URL: {{url}}
Labels: {{labels}}
Description:
{{body}}
Instructions:
1. Create a feature branch: git checkout -b issue-{{source_id}}
2. Implement the changes
3. Run tests: cargo test
4. Commit and push
5. Create a PR: gh pr create --title "{{title}}" --body "Closes #{{source_id}}"
Launch everything¶
This creates the worker agent, waits for it to connect, then creates the workflow that starts polling for GitHub issues.