2026-02-12 09:49:54 +00:00
# `backend/templates/` — Gateway workspace templates
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
This directory contains **Jinja2 templates ** that Mission Control renders and syncs into each OpenClaw gateway agent’ s on-disk workspace (the `workspace-*` folder).
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
These files are the agent’ s “operating manual” (instructions, heartbeat rules, tools, identity, etc.).
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
## Where templates are rendered / synced
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
**Rendering engine**
- Renderer: Jinja2 `Environment(FileSystemLoader(templates_root))` .
- Config (important for safe changes):
- `undefined=StrictUndefined` → **missing variables crash render ** (good: prevents silent partial templates).
- `autoescape=False` → markdown is rendered “verbatim” (no HTML escaping).
- `keep_trailing_newline=True` .
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
Evidence:
- `backend/app/services/openclaw/provisioning.py::_template_env()`
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
**Sync workflows**
- API: `POST /api/v1/gateways/{gateway_id}/templates/sync`
- Router: `backend/app/api/gateways.py` (`sync_gateway_templates` ).
- DB-backed service: `backend/app/services/openclaw/provisioning_db.py::OpenClawProvisioningService.sync_gateway_templates()` .
- CLI: `backend/scripts/sync_gateway_templates.py --gateway-id <uuid> [--board-id <uuid>] [--reset-sessions] [--rotate-tokens] [--force-bootstrap]`
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
## Which files are provisioned
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
Default set (rendered for each agent workspace):
- `AGENTS.md` , `SOUL.md` , `TASK_SOUL.md` , `SELF.md` , `AUTONOMY.md` , `TOOLS.md` , `IDENTITY.md` , `USER.md` , `HEARTBEAT.md` , `BOOT.md` , `BOOTSTRAP.md` , `MEMORY.md`
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
Evidence:
- `backend/app/services/openclaw/constants.py::DEFAULT_GATEWAY_FILES`
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
### “Main agent” template mapping
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
The gateway * main * agent uses a few different templates (prefixed `MAIN_...` ) for some files:
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
| Workspace file | Main-agent template |
|---|---|
| `AGENTS.md` | `MAIN_AGENTS.md` |
| `HEARTBEAT.md` | `MAIN_HEARTBEAT.md` |
| `USER.md` | `MAIN_USER.md` |
| `BOOT.md` | `MAIN_BOOT.md` |
| `TOOLS.md` | `MAIN_TOOLS.md` |
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
Evidence:
- `backend/app/services/openclaw/constants.py::MAIN_TEMPLATE_MAP`
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
## Template variables (context)
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
Templates are rendered with a context built from:
- Agent + board + gateway fields
- Mission Control backend settings (`base_url` )
- Optional user profile fields
- Agent identity profile fields
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
Evidence:
- `backend/app/services/openclaw/provisioning.py::_build_context()` (board-scoped agents)
- `backend/app/services/openclaw/provisioning.py::_build_main_context()` (main agent)
- Identity/user mapping: `backend/app/services/openclaw/provisioning.py::_identity_context()` , `_user_context()`
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
### Common context keys
2026-02-12 12:48:49 +00:00
2026-02-12 09:49:54 +00:00
These keys are available to * all * templates (agent + main):
2026-02-12 12:48:49 +00:00
- `agent_name`
- `agent_id`
- `session_key`
- `base_url`
- `auth_token`
- `main_session_key`
- `workspace_root`
2026-02-12 09:49:54 +00:00
User fields (may be empty strings):
- `user_name` , `user_preferred_name` , `user_pronouns` , `user_timezone`
- `user_notes` , `user_context`
Identity fields (defaults apply if missing):
- `identity_role`
- `identity_communication_style`
- `identity_emoji`
Extra identity fields (optional; may be empty strings):
- `identity_autonomy_level` , `identity_verbosity` , `identity_output_format` , `identity_update_cadence`
- `identity_purpose` , `identity_personality` , `identity_custom_instructions`
Evidence:
- Defaults + mapping: `backend/app/services/openclaw/constants.py::{DEFAULT_IDENTITY_PROFILE, IDENTITY_PROFILE_FIELDS, EXTRA_IDENTITY_PROFILE_FIELDS}`
### Board-scoped-only keys
Only board-scoped agents receive:
- `board_id` , `board_name` , `board_type`
- `board_objective` , `board_success_metrics` , `board_target_date`
- `board_goal_confirmed`
- `is_board_lead`
- `workspace_path`
- `board_*` fields above
Evidence:
- `backend/app/services/openclaw/provisioning.py::_build_context()`
## HEARTBEAT template selection
`HEARTBEAT.md` is special: it renders one of two templates depending on whether the agent is a board lead:
- lead: `HEARTBEAT_LEAD.md`
- agent: `HEARTBEAT_AGENT.md`
Evidence:
- Template names: `backend/app/services/openclaw/constants.py::{HEARTBEAT_LEAD_TEMPLATE, HEARTBEAT_AGENT_TEMPLATE}`
- Selection logic: `backend/app/services/openclaw/provisioning.py::_heartbeat_template_name()`
## Safe change guidelines
1) **Assume templates are user-facing instructions **
- Keep edits backwards compatible when possible.
- Prefer additive changes (new sections) over rewriting major flows.
2) **Do not break rendering **
- Because `StrictUndefined` is enabled, adding `{{ new_var }}` requires also adding that key to the context builder(s).
3) **Preserved (agent-editable) files **
Some files are intentionally not overwritten on template sync if they already exist in the agent workspace (the agent/human may edit them):
- `SELF.md` , `USER.md` , `MEMORY.md` , `TASK_SOUL.md`
Evidence:
- `backend/app/services/openclaw/constants.py::PRESERVE_AGENT_EDITABLE_FILES`
4) **Main-agent vs board-agent differences **
- If changing `TOOLS.md` , `HEARTBEAT.md` , etc., check whether the change should also apply to the main-agent templates (`MAIN_*` ).
5) **Prefer small PRs + keep template scope task-scoped **
## Previewing / testing template changes locally
### Option A (recommended): run template sync against a dev gateway
Use either:
- API: `POST /api/v1/gateways/{gateway_id}/templates/sync`
- CLI: `backend/scripts/sync_gateway_templates.py --gateway-id <uuid> ...`
Then inspect the provisioned files in the gateway’ s workspace directory (the exact path is computed in `backend/app/services/openclaw/provisioning.py::_workspace_path()` ).
### Option B: quick offline render (Jinja2 only)
This is useful for confirming Markdown formatting and variable names.
```bash
python3 - <<'PY'
from pathlib import Path
from jinja2 import Environment, FileSystemLoader, StrictUndefined
root = Path('backend/templates')
env = Environment(
loader=FileSystemLoader(root),
undefined=StrictUndefined,
autoescape=False,
keep_trailing_newline=True,
)
# Minimal dummy context (must include any variables referenced by the template).
ctx = {
'agent_name': 'ExampleAgent',
'agent_id': '00000000-0000-0000-0000-000000000000',
'board_id': '00000000-0000-0000-0000-000000000000',
'board_name': 'Example Board',
'board_type': 'general',
'board_objective': '',
'board_success_metrics': '{}',
'board_target_date': '',
'board_goal_confirmed': 'false',
'is_board_lead': 'false',
'session_key': 'agent:example',
'workspace_path': '/tmp/workspace-example',
'base_url': 'http://localhost:8000',
'auth_token': 'REDACTED',
'main_session_key': 'agent:gateway-main',
'workspace_root': '/tmp',
'user_name': '',
'user_preferred_name': '',
'user_pronouns': '',
'user_timezone': '',
'user_notes': '',
'user_context': '',
'identity_role': 'Generalist',
'identity_communication_style': 'direct',
'identity_emoji': ':gear:',
'identity_autonomy_level': '',
'identity_verbosity': '',
'identity_output_format': '',
'identity_update_cadence': '',
'identity_purpose': '',
'identity_personality': '',
'identity_custom_instructions': '',
}
print(env.get_template('AGENTS.md').render(**ctx))
PY
```
2026-02-12 18:03:07 +00:00
If the template references a variable not present in `ctx` , Jinja2 will raise immediately (by design).