Skip to main content

Overview

The Agent SOUL System lets you define agent personality, capabilities, and behavioral guidelines through markdown files. Changes sync bidirectionally between the UI database and workspace soul.md files—edit in either location and both stay in sync.
SOUL files use a simple markdown format with frontmatter-style metadata. The system automatically parses identity information and maintains consistency across your agent fleet.

Workspace Sync Architecture

Mission Control reads agent configurations from openclaw.json and enriches them with workspace files:
// src/lib/agent-sync.ts
function enrichAgentConfigFromWorkspace(configData: any): any {
  const workspace = configData.workspace
  if (!workspace) return configData

  // Read identity.md and TOOLS.md from agent workspace
  const identityFile = readWorkspaceFile(workspace, 'identity.md')
  const toolsFile = readWorkspaceFile(workspace, 'TOOLS.md')

  // Parse and merge with config
  const mergedIdentity = {
    ...parseIdentityFromFile(identityFile || ''),
    ...configData.identity,
  }

  return {
    ...configData,
    identity: mergedIdentity,
    tools: mergedTools,
  }
}

SOUL File Format

SOUL files follow a simple markdown structure:
# Agent Name

theme: engineering specialist
emoji: 🔧

## Core Capabilities

- Code review and refactoring
- Architecture design
- Performance optimization

## Behavioral Guidelines

- Prioritize code quality and maintainability
- Provide detailed explanations
- Ask clarifying questions before major changes

## Communication Style

Professional, concise, technically accurate. Use code examples.

Bidirectional Sync

Changes sync automatically in both directions:
1

Workspace → Database

When syncAgentsFromConfig() runs (startup, manual sync), it reads soul.md from each agent’s workspace and writes to the database:
// Read soul.md from workspace
const soul_content = readWorkspaceFile(agent.workspace, 'soul.md')

// Write to database
insertAgent.run(
  mapped.name,
  mapped.role,
  soul_content, // Stored in agents.soul_content column
  'offline',
  now,
  now,
  configJson
)
2

Database → Workspace

When you edit SOUL content in the UI via PUT /api/agents/[id]/soul, it writes to both locations:
// Update database
db.prepare('UPDATE agents SET soul_content = ? WHERE id = ?')
  .run(content, agentId)

// Write to workspace soul.md
const workspace = agent.config?.workspace
if (workspace) {
  const soulPath = resolveWithin(workspace, 'soul.md')
  await writeFile(soulPath, content, 'utf-8')
}
3

Conflict Resolution

When syncing from openclaw.json, the system only overwrites database content if:
  • The workspace file has newer content
  • The existing database value is null
const soulChanged = mapped.soul_content !== null && 
                    mapped.soul_content !== existingSoul

if (soulChanged) {
  const soulToWrite = mapped.soul_content ?? existingSoul
  updateAgent.run(mapped.role, configJson, soulToWrite, now, mapped.name)
}

Identity Parsing

The system extracts structured metadata from markdown:
function parseIdentityFromFile(content: string): {
  name?: string
  theme?: string
  emoji?: string
  content?: string
} {
  const lines = content.split('\n').map(line => line.trim())

  let name: string | undefined
  let theme: string | undefined
  let emoji: string | undefined

  for (const line of lines) {
    // Extract name from first heading
    if (!name && line.startsWith('#')) {
      name = line.replace(/^#+\s*/, '').trim()
      continue
    }

    // Extract theme: field
    const themeMatch = line.match(/^theme\s*:\s*(.+)$/i)
    if (themeMatch?.[1]) {
      theme = themeMatch[1].trim()
      continue
    }

    // Extract emoji: field
    const emojiMatch = line.match(/^emoji\s*:\s*(.+)$/i)
    if (emojiMatch?.[1]) {
      emoji = emojiMatch[1].trim()
    }
  }

  return { name, theme, emoji, content: lines.slice(0, 8).join('\n') }
}

API Reference

Get Agent SOUL

curl -X GET "http://localhost:3000/api/agents/123/soul" \
  -H "x-api-key: YOUR_API_KEY"
The API returns database content by default. To read directly from workspace, the system checks if the file exists and is readable.

Update Agent SOUL

curl -X PUT "http://localhost:3000/api/agents/123/soul" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "soul_content": "# Updated SOUL\n\ntheme: updated theme\n..."
  }'

Sync from Config

curl -X POST "http://localhost:3000/api/agents/sync" \
  -H "x-api-key: YOUR_API_KEY"

Tools Configuration

The system also syncs TOOLS.md from workspaces:
# Allowed Tools

- `bash` - Execute shell commands
- `read` - Read file contents
- `write` - Write to files
- `glob` - Search for files
- `grep` - Search file contents

Best Practices

Security Note: SOUL files may contain sensitive behavioral guidelines. Store them in version control with appropriate access controls.
  • Use clear heading hierarchy (#, ##, ###)
  • Place metadata fields (theme:, emoji:) near the top
  • Keep SOUL content under 4KB for optimal performance
  • Use consistent formatting across your agent fleet

Troubleshooting

1

SOUL not syncing from workspace

Check that:
  • OPENCLAW_HOME environment variable is set correctly
  • Agent’s workspace field in openclaw.json is valid
  • File path resolves correctly: $OPENCLAW_HOME/[workspace]/soul.md
  • File has read permissions
2

UI changes not writing to workspace

Verify:
  • Agent has workspace field in database config
  • Workspace directory exists and is writable
  • No file system errors in Mission Control logs
3

Identity fields not parsing

Ensure:
  • Fields use exact format: theme: value (lowercase, space after colon)
  • Name comes from first markdown heading (# Name)
  • No extra whitespace or special characters