Skip to main content

Agents

How the agent system works, how to provision agents, and how to write custom templates.

What an agent is

In HQ, an agent is a long-lived workspace made of:
  • A git branch on the gateway’s local repo (workspace-slug/agent-slug). Holds the agent’s identity files, memory, skills, and any artifacts it produces.
  • A Chrome profile on the gateway (persistent cookies, logged-in sessions, extensions).
  • An OpenClaw session — the runtime. Handles prompt assembly, tool calls, conversation state.
  • A messaging channel — Telegram, Discord, Slack, or none. Each agent can be bound to one channel for conversational I/O.
  • A row in the Supabase agents table — the metadata, including gateway_id (which gateway runs it), reports_to_id (its manager), and meta JSONB for template-specific config.
  • A usage budget row in agent_budgets once usage is configured or first recorded.
Agents run on one gateway. If a gateway goes down, its agents go down with it. Moving an agent to another gateway is still an operator action: provision on the target gateway and migrate the branch/state intentionally.

The template library

templates/ is the catalog of starting points:
  • default/ — minimal baseline that every custom agent inherits from
  • analytics/, assistant/, chief-of-staff/, cmo/, cofounder/, crm-researcher/, designer/, market-researcher/, newsletter-editor/, newsletter-writer/, sales-copywriter/, script-writer/, social-strategist/, social-writer/
Each template directory is the starting file tree for a new agent’s git branch. The gateway seeds every template as a template/<name> branch in its local bare repo on first boot.

Template structure

templates/cofounder/
├── agent.json        # runtime config: name, emoji, model, team, capabilities
├── IDENTITY.md       # personality, voice, domain knowledge
├── SOUL.md           # core beliefs, goals, non-negotiables
├── USER.md           # owner profile (placeholder text filled in at provision)
├── MEMORY.md         # initial memories (e.g. past context)
├── TOOLS.md          # what tools the agent has access to
├── AGENTS.md         # instructions for Claude-style sub-agents (if any)
└── skills/           # role-specific scripts/procedures
At provision time, add-agent.sh forks the chosen template branch into the agent’s personal branch, then patches:
  • agent.json — sets slug, name, description, emoji, channel
  • USER.md — replaces USER_NAME_HERE, PREFERRED_NAME_HERE, TIMEZONE_HERE with the workspace owner’s profile
  • IDENTITY.md — updates the Name/Emoji section to the new agent’s identity
The rest of the template (role-specific skills, IDENTITY prose, MEMORY, etc.) is kept verbatim. Users can customize further by editing files via the file browser — each save enqueues an update command so the gateway reloads the agent with fresh config.

Provisioning flow

  1. UI → Agents → New Agent.
  2. Wizard step 1: pick a template. Templates load from /api/agents/templates (baked into the UI image from the templates/ directory at build time).
  3. Step 2: name, slug (auto-generated from name), emoji, optional description override, and optional manager.
  4. Step 3: choose a messaging channel (Telegram, Discord, Slack, or None) and enter the required credentials.
  5. Click Create.
UI-side:
  • createAgentWithBranch in apps/ui/src/app/dashboard/agents/actions.ts validates the slug, checks uniqueness, inserts the agents row, and enqueues an agent_commands row with action=provision.
Gateway-side:
  • The runner’s Supabase Realtime subscription fires.
  • Runner calls lease_command(p_gateway_slug=<gateway-id>) to atomically claim it.
  • Runner builds the shell command and invokes gateway/scripts/add-agent.sh.
  • add-agent.sh:
    1. Creates a new branch from the template branch in the bare repo.
    2. Creates a git worktree at /home/openclaw/.openclaw/workspace-<agent-slug>/.
    3. Patches agent.json, USER.md, IDENTITY.md.
    4. Appends a bindings entry to openclaw.json for the chosen channel (Telegram account, Discord bot, Slack socket, or no binding).
    5. Creates a Chrome desktop shortcut for the new browser profile.
    6. Links shared auth directories (so all agents share model tokens).
  • Runner restarts the gateway container so openclaw picks up the new agent.
  • Agent appears as online in the UI within ~60 seconds.

Channel pairing

After provisioning, the next step depends on the channel: Telegram or Discord (DM pairing):
  1. Send a message to your bot (Telegram DM or Discord DM).
  2. Bot replies with a 6-digit pairing code.
  3. In the UI, open the agent’s detail page → Pairing Code field → paste code → Submit.
  4. Runner executes openclaw pairing approve <channel> <code>.
  5. Next message triggers the agent.
Slack (no pairing): The agent is active in your Slack workspace immediately after provisioning. No pairing step needed. None: The agent is provisioned without a channel binding. You can add a channel later. If an agent doesn’t respond to the first real message, check:
  • Runner logs: docker compose logs runner | grep pairing
  • Gateway logs: docker compose logs gateway | grep <channel>
  • openclaw.json in the gateway-state volume has the correct bindings entry

Customizing agents after creation

Two paths: In the UI file browser (Phase 1):
  • Agents → [agent] → Files tab → browse the agent’s git branch.
  • Edit IDENTITY.md, MEMORY.md, TOOLS.md, any skill file.
  • Save. The UI auto-enqueues an update command. Gateway reloads the agent.
Via the agent’s messaging channel (Telegram, Discord, Slack):
  • “Remember that I prefer short-form responses.” → agent updates its own MEMORY.md (with your approval).
  • “Learn to summarize in three bullets.” → agent updates SKILL.md or adds a new skill.
The second is the eventual happy path. The first is the escape hatch when you want direct control.

Sync model (git)

Every agent lives on its own git branch. File changes land on disk immediately, but aren’t saved to git until someone commits. HQ’s sync model is event-driven, not polled. Commits are triggered by meaningful events:
  1. Provisioningadd-agent.sh commits the initial branch when an agent is created (“feat: initialize agent <slug>”).
  2. UI file-browser editsfiles_api.py commits on every file write (“edit via UI: <path>”) or create/delete.
  3. Agent-initiated saves — the agent calls save_progress (alias for ./scripts/git-sync.sh) when it does something meaningful: learned a preference, produced an artifact, updated a skill. Commit messages like learned: <what>, done: <what>, skill: <what>.
Pushes are automatic. The gateway installs a post-commit git hook on the bare repo that async-pushes every commit to origin if a remote is configured. You never call git push manually. Works offline — commits land locally, push retries next boot or sweep. The backup sweep runs inside the runner every GIT_SYNC_INTERVAL seconds (default 30 min). It:
  • Commits any dirty worktrees with “autosync: uncommitted changes at <timestamp>
  • Pushes all branches (belt-and-suspenders — catches missed pushes)
  • Fetches from origin and fast-forwards branches that moved on the remote (only when the local worktree is clean; we never stomp on in-progress edits)
Conflict strategy: local wins. If both local and remote have diverged, the sweep logs a warning and skips the pull. This isn’t a collaboration tool — same user, different machines, not multiple editors. Configuring the remote: either GIT_REMOTE_URL (any git host), or GITHUB_TOKEN + GITHUB_REPO_OWNER + GITHUB_REPO_NAME (GitHub shorthand). See CONFIGURATION.md → Git remote sync for details. Disabling the sweep: set GIT_SYNC_INTERVAL=0. Event-driven commits and the post-commit push hook still work; only the periodic safety net turns off.

Writing a new template

  1. Copy templates/default/:
    cp -r templates/default templates/your-role
    
  2. Edit templates/your-role/agent.json:
    {
      "slug": "your-role",
      "name": "Your Role",
      "emoji": "🎯",
      "team": "ops",
      "description": "One-sentence role description."
    }
    
    The model field is optional — agents use whatever default provider/model is configured in Settings → Connections. You can override per-agent from the agent detail page.
  3. Edit IDENTITY.md — this is the prose that gets prepended to every prompt. Voice, domain knowledge, how they talk. See templates/cofounder/IDENTITY.md for a good example.
  4. Edit SOUL.md — core beliefs. Goals. Non-negotiables. What the agent refuses to do.
  5. Leave USER.md alone — the placeholder tokens (USER_NAME_HERE, etc.) are filled in at provision time.
  6. Write starting memories in MEMORY.md — e.g. “The user’s company is in early-stage SaaS. They prefer short outputs.”
  7. Add role-specific skills in skills/. A skill is a markdown file describing a procedure. Examples:
    • skills/outreach/draft-cold-email.md
    • skills/content/weekly-newsletter.md
    • skills/research/competitor-analysis.md
  8. Rebuild the templates index so the UI sees your new template:
    node apps/ui/scripts/build-templates-index.mjs
    
    Commit the updated apps/ui/src/generated/templates.ts.
  9. Build and test (only needed if developing; docker compose up -d alone is fine for published images):
    docker compose build ui    # rebuild only when you edit UI source
    docker compose up -d ui gateway
    
    Go to Agents → New Agent → your template should appear.
  10. Provision a test agent against it. Iterate on IDENTITY.md and skills until it behaves right.
  11. Open a PR if it’s generally useful.

Org chart and delegation

Agents can report to other agents through reports_to_id. The UI surfaces the resulting hierarchy in two places:
  • Agents list — once at least one agent has a manager, a Fleet / Org chart view toggle appears in the filter bar. The chart lays the reporting tree out as connected boxes; chevron toggles on parent nodes collapse subtrees, and hovering a node reveals the same edit/pause/delete actions as the list view.
  • Agent detail sidebar — an “Org” section shows the agent’s manager (if any), peers (other direct reports of the same manager), and direct reports. Clicking the manager pill opens a picker for inline reassignment.
When an agent has a manager or direct reports, the HQ bootstrap plugin injects a “Your Position” section into runtime context. That context tells the agent:
  • Who its manager is.
  • Which agents report to it.
  • To delegate by creating assigned tasks for direct reports.
  • To escalate by creating high-priority tasks for its manager.
  • To ask the human before routing work to peer agents outside the direct hierarchy.
Cycle prevention is handled before saving manager changes: an agent cannot report to itself, and the UI walks the manager chain via the agent_reports_chain RPC so loops cannot be created accidentally.

Model and thinking configuration

Each agent has an optional model and thinking setting persisted on the agents table. These control which LLM and reasoning depth the agent uses by default.
  • Model — a full model ID like anthropic/claude-sonnet-4-6 or openai-codex/gpt-5.4. The prefix determines which provider connection is used for billing/auth.
  • Thinkingnone, low, medium, or high. Controls extended reasoning for models that support it.
Both can be set from the agent detail sidebar (Model section in the right rail). Changes take effect on the next wake — no gateway restart needed. For one-off tasks that need different reasoning depth, set the override on the task itself. The dispatcher passes task-level overrides as --model / --thinking flags to openclaw agent, which takes precedence over the agent’s default for that session only.

Usage budgets

HQ records model usage for each agent in agent_usage and keeps a current-period rollup in agent_budgets. Budget controls live on the agent detail page. Per-agent settings include:
  • Monthly limit in USD.
  • Soft warning threshold percentage.
  • Whether to hard-stop the agent after exceeding the limit.
  • Period timezone.
When pricing is known, the runtime estimates cost from token counts. When pricing is unknown, calls are still counted as unmetered usage. If a hard cutoff is active and the agent exceeds its limit, the bootstrap plugin blocks further replies and the inbox dispatcher skips background wakes for that agent.

Skills and tools

Agents have access to (via openclaw):
  • Browser — a dedicated Chrome profile they can drive. Visit pages, screenshot, click, type. Persistent cookies.
  • Messaging channel — Telegram, Discord, or Slack — send/receive messages with their paired user.
  • HQ database — read/write contacts, tasks, knowledge items, interactions via the service role.
  • MCP servers — any MCP server you configure. Slack, GitHub, Notion, Google Calendar, etc.
  • Shell — scoped to their workspace directory.
TOOLS.md in a template documents which tools the agent should reach for in which situations. The browser tool, for example, is automatically registered as a capability (openclaw’s browser plugin is always loaded), and TOOLS.md tells the agent when to use it without being asked.

Agent memory model

Agents wake up fresh each session. Continuity comes from files in their branch:
  • MEMORY.md — curated long-term memory. Durable truths: user preferences, ongoing projects, important context. Updated sparingly.
  • memory/YYYY-MM-DD.md — daily notes. What happened today. Updated every session.
  • history/YYYY-MM-DD_topic.md — operational narratives for meaningful work. Multi-step changes, architecture decisions, lessons learned.
The default AGENTS.md prompts the agent to read these on every session start. The agent maintains them itself — the user doesn’t usually touch them. For shared knowledge across agents, use the knowledge system — workspace-scoped items are visible to all agents, and pinned items are automatically included in boot context.

Skill learning

Agents improve over time by maintaining their own skills — reusable procedures they create when they discover a reliable method. This happens autonomously during work via hq_skill_upsert.py:
  • When to learn: after performing the same sequence 3+ times successfully, or after a breakthrough discovery (trial-and-error that yielded a non-obvious method).
  • What gets stored: a skill (kind: 'skill', scope: 'agent') linked to the agent via the knowledge_item_agents junction table.
  • Visibility: the agent detail page shows a “Skills” section with recency indicators (blue dot for recent agent edits) and the one-line reason the agent provided. The knowledge editor has a History panel showing who made each edit (agent vs. human).
There is no approval gate — agents write directly. Operators observe via the audit trail and can edit, refine, or delete skills at any time through the standard knowledge editor. The --reason parameter on every skill write is surfaced in the UI. It should be a one-line explanation of what changed and why (e.g., “Added YouTube channel research method after 3 successful tasks”).

Agent-to-agent

Agents see the same database, so they can see each other’s tasks and knowledge. Coordination patterns:
  • @-mentions in comments — mentioning @agent-slug in a task comment enqueues an inbox item for that agent via the enqueue_comment_mentions trigger. Dispatcher wakes the agent.
  • Routines — routines can fire inbox items on CRM events or schedules. Agent A writes a contact update → routine creates inbox item for agent B.
  • Task assignment — assigning a task to an agent enqueues an inbox item (via enqueue_task_assignment trigger).
The org chart adds a convention on top of these primitives: managers and direct reports coordinate through tasks instead of direct hidden calls.

Debugging an agent

  • Check the agent’s Chrome window — noVNC into the gateway; you’ll see Chrome with the agent’s profile. Right-click → Agents → click their window.
  • Check command history — Settings → System → Commands tab. Filter by status or gateway.
  • Check inbox history — Settings → System → Inbox tab. See what triggered each wake and its status.
  • Check audit log — Settings → System → Audit Log tab. Filter by module, action, or actor type.
  • Tail runner logsdocker compose logs -f runner while the agent works.
  • Tail gateway logsdocker compose logs -f gateway | grep <agent-slug> for openclaw-side traces.
  • Read the agent’s branch — file browser in the UI, or docker compose exec gateway bashcd ~/.openclaw/workspace-<slug> → inspect directly.
See Troubleshooting for common agent-related failure modes.