openclaw-control-center

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

OpenClaw Control Center

OpenClaw 控制中心

Skill by ara.so — Hermes Skills collection.
OpenClaw Control Center is a TypeScript-based local dashboard that transforms OpenClaw from a black box into a transparent control center. It provides real-time observability for agent activity, token usage, task execution, multi-agent collaboration, and approval workflows—all with safety-first defaults (read-only mode, local token auth, and disabled mutations by default).
ara.so提供的Skill — Hermes Skills 合集。
OpenClaw 控制中心是一个基于TypeScript的本地仪表盘,它将OpenClaw从黑盒转变为透明的控制中心。它为Agent活动、令牌使用、任务执行、多Agent协作以及审批工作流提供实时可观测性——所有功能均采用安全优先的默认配置(只读模式、本地令牌认证、默认禁用变更操作)。

What It Does

功能介绍

  • Overview: Health dashboard showing agent status, decisions waiting, and operator summaries
  • Collaboration Hall: Multi-agent chat workspace with live discussion, assignment, handoff, and review
  • Staff Management: Real-time view of active vs. queued agents
  • Task Management: Execution chains, approvals, runtime evidence, and blocked work
  • Usage Tracking: Token consumption, spend trends, context pressure, quota monitoring
  • Memory & Documents: Source-backed workbenches for agent memory and markdown documents
  • Safety First: Read-only by default, local token auth required, mutation routes disabled
  • 概览面板:显示Agent状态、待处理决策和操作员汇总的健康仪表盘
  • 协作大厅:支持实时讨论、任务分配、交接与审核的多Agent聊天工作区
  • Agent管理:实时查看活跃与排队中的Agent状态
  • 任务管理:执行链、审批流程、运行时证据与阻塞任务管理
  • 使用追踪:令牌消耗、支出趋势、上下文压力与配额监控
  • 内存与文档:基于源数据的Agent内存与Markdown文档工作台
  • 安全优先:默认只读模式,需本地令牌认证,变更路由默认禁用

Installation

安装步骤

bash
undefined
bash
undefined

Clone the repository

Clone the repository

Install dependencies

Install dependencies

npm install
npm install

Set up environment

Set up environment

cp .env.example .env
cp .env.example .env

Build the project

Build the project

npm run build
npm run build

Run tests

Run tests

npm test
npm test

Run smoke tests

Run smoke tests

npm run smoke:ui npm run smoke:hall
npm run smoke:ui npm run smoke:hall

Start development server

Start development server

npm run dev:ui
undefined
npm run dev:ui
undefined

Configuration

配置说明

Environment Variables (.env)

环境变量(.env)

bash
undefined
bash
undefined

Safety and security (defaults)

Safety and security (defaults)

READONLY_MODE=true LOCAL_TOKEN_AUTH_REQUIRED=true LOCAL_API_TOKEN=your-long-random-secret-here
READONLY_MODE=true LOCAL_TOKEN_AUTH_REQUIRED=true LOCAL_API_TOKEN=your-long-random-secret-here

Import/export protection

Import/export protection

IMPORT_MUTATION_ENABLED=false IMPORT_MUTATION_DRY_RUN=false
IMPORT_MUTATION_ENABLED=false IMPORT_MUTATION_DRY_RUN=false

Approval actions

Approval actions

APPROVAL_ACTIONS_ENABLED=false APPROVAL_ACTIONS_DRY_RUN=true
APPROVAL_ACTIONS_ENABLED=false APPROVAL_ACTIONS_DRY_RUN=true

UI configuration

UI configuration

UI_PORT=4310 UI_BIND_ADDRESS=127.0.0.1
UI_PORT=4310 UI_BIND_ADDRESS=127.0.0.1

For Tailscale or remote access

For Tailscale or remote access

OPENCLAW_CONTROL_UI_URL=http://<tailscale-host>:4310/
OPENCLAW_CONTROL_UI_URL=http://<tailscale-host>:4310/

UI_BIND_ADDRESS=0.0.0.0 # Auto-set when OPENCLAW_CONTROL_UI_URL is provided

UI_BIND_ADDRESS=0.0.0.0 # Auto-set when OPENCLAW_CONTROL_UI_URL is provided

undefined
undefined

Directory Structure

目录结构

control-center/
├── src/
│   ├── ui/           # Frontend TypeScript/React components
│   ├── server/       # Backend API routes
│   ├── lib/          # Shared utilities
│   └── types/        # TypeScript definitions
├── docs/
│   ├── assets/       # Screenshots and images
│   └── FAQ.md        # Troubleshooting guide
├── HALL.md           # Shared collaboration style guide
└── .env              # Local configuration
control-center/
├── src/
│   ├── ui/           # Frontend TypeScript/React components
│   ├── server/       # Backend API routes
│   ├── lib/          # Shared utilities
│   └── types/        # TypeScript definitions
├── docs/
│   ├── assets/       # Screenshots and images
│   └── FAQ.md        # Troubleshooting guide
├── HALL.md           # Shared collaboration style guide
└── .env              # Local configuration

Key Commands

核心命令

Development

开发阶段

bash
undefined
bash
undefined

Start UI development server (recommended, cross-platform)

Start UI development server (recommended, cross-platform)

npm run dev:ui
npm run dev:ui

Single monitor pass without UI

Single monitor pass without UI

npm run dev
npm run dev

Build production bundle

Build production bundle

npm run build
npm run build

Run all tests

Run all tests

npm test
npm test

Smoke tests for UI and hall

Smoke tests for UI and hall

npm run smoke:ui npm run smoke:hall
npm run smoke:ui npm run smoke:hall

Linting

Linting

npm run lint npm run lint:fix
undefined
npm run lint npm run lint:fix
undefined

Accessing the UI

访问UI界面

bash
undefined
bash
undefined

English interface

English interface

Chinese interface

Chinese interface

Direct section access

Direct section access

Real Code Examples

代码示例

Enabling Write Operations

启用写入操作

typescript
// .env configuration for enabling mutations
READONLY_MODE=false
LOCAL_TOKEN_AUTH_REQUIRED=true
LOCAL_API_TOKEN=generate-a-secure-random-token-here
IMPORT_MUTATION_ENABLED=true
APPROVAL_ACTIONS_ENABLED=true
APPROVAL_ACTIONS_DRY_RUN=false
typescript
// .env configuration for enabling mutations
READONLY_MODE=false
LOCAL_TOKEN_AUTH_REQUIRED=true
LOCAL_API_TOKEN=generate-a-secure-random-token-here
IMPORT_MUTATION_ENABLED=true
APPROVAL_ACTIONS_ENABLED=true
APPROVAL_ACTIONS_DRY_RUN=false

API Authentication Pattern

API认证模式

typescript
// src/lib/api-client.ts
interface ApiRequest {
  endpoint: string;
  method: 'GET' | 'POST' | 'PUT' | 'DELETE';
  body?: any;
  requiresAuth?: boolean;
}

async function callApi({ endpoint, method, body, requiresAuth = true }: ApiRequest) {
  const headers: Record<string, string> = {
    'Content-Type': 'application/json',
  };

  // Add authorization for protected endpoints
  if (requiresAuth) {
    const token = process.env.LOCAL_API_TOKEN;
    if (!token) {
      throw new Error('LOCAL_API_TOKEN not configured');
    }
    headers['Authorization'] = `Bearer ${token}`;
  }

  const response = await fetch(`http://127.0.0.1:4310${endpoint}`, {
    method,
    headers,
    body: body ? JSON.stringify(body) : undefined,
  });

  if (!response.ok) {
    throw new Error(`API error: ${response.status} ${response.statusText}`);
  }

  return response.json();
}

// Example: Save task with authentication
async function saveTask(taskId: string, updates: any) {
  return callApi({
    endpoint: `/api/tasks/${taskId}`,
    method: 'PUT',
    body: updates,
    requiresAuth: true,
  });
}
typescript
// src/lib/api-client.ts
interface ApiRequest {
  endpoint: string;
  method: 'GET' | 'POST' | 'PUT' | 'DELETE';
  body?: any;
  requiresAuth?: boolean;
}

async function callApi({ endpoint, method, body, requiresAuth = true }: ApiRequest) {
  const headers: Record<string, string> = {
    'Content-Type': 'application/json',
  };

  // Add authorization for protected endpoints
  if (requiresAuth) {
    const token = process.env.LOCAL_API_TOKEN;
    if (!token) {
      throw new Error('LOCAL_API_TOKEN not configured');
    }
    headers['Authorization'] = `Bearer ${token}`;
  }

  const response = await fetch(`http://127.0.0.1:4310${endpoint}`, {
    method,
    headers,
    body: body ? JSON.stringify(body) : undefined,
  });

  if (!response.ok) {
    throw new Error(`API error: ${response.status} ${response.statusText}`);
  }

  return response.json();
}

// Example: Save task with authentication
async function saveTask(taskId: string, updates: any) {
  return callApi({
    endpoint: `/api/tasks/${taskId}`,
    method: 'PUT',
    body: updates,
    requiresAuth: true,
  });
}

Collaboration Hall Workflow

协作大厅工作流

typescript
// src/types/hall.ts
interface HallMessage {
  id: string;
  taskId: string;
  agentId: string;
  content: string;
  phase: 'discussion' | 'execution' | 'review' | 'blocked';
  timestamp: string;
  mentions?: string[];
}

interface ExecutionOrder {
  taskId: string;
  owners: string[];
  currentOwnerIndex: number;
  nextHandoff?: string;
}

// Example: Create hall task and arrange execution
async function createHallTask(content: string, roster: string[]) {
  // 1. Create task in hall
  const task = await callApi({
    endpoint: '/api/hall/tasks',
    method: 'POST',
    body: { content, phase: 'discussion' },
  });

  // 2. Let agents discuss (wait for 2+ replies)
  await waitForDiscussion(task.id, 2);

  // 3. Arrange execution order
  const executionOrder = await callApi({
    endpoint: `/api/hall/tasks/${task.id}/execution-order`,
    method: 'PUT',
    body: {
      owners: ['agent-manager', 'agent-builder', 'agent-qa'],
    },
  });

  // 4. Start execution
  const execution = await callApi({
    endpoint: `/api/hall/tasks/${task.id}/start`,
    method: 'POST',
  });

  return { task, executionOrder, execution };
}
typescript
// src/types/hall.ts
interface HallMessage {
  id: string;
  taskId: string;
  agentId: string;
  content: string;
  phase: 'discussion' | 'execution' | 'review' | 'blocked';
  timestamp: string;
  mentions?: string[];
}

interface ExecutionOrder {
  taskId: string;
  owners: string[];
  currentOwnerIndex: number;
  nextHandoff?: string;
}

// Example: Create hall task and arrange execution
async function createHallTask(content: string, roster: string[]) {
  // 1. Create task in hall
  const task = await callApi({
    endpoint: '/api/hall/tasks',
    method: 'POST',
    body: { content, phase: 'discussion' },
  });

  // 2. Let agents discuss (wait for 2+ replies)
  await waitForDiscussion(task.id, 2);

  // 3. Arrange execution order
  const executionOrder = await callApi({
    endpoint: `/api/hall/tasks/${task.id}/execution-order`,
    method: 'PUT',
    body: {
      owners: ['agent-manager', 'agent-builder', 'agent-qa'],
    },
  });

  // 4. Start execution
  const execution = await callApi({
    endpoint: `/api/hall/tasks/${task.id}/start`,
    method: 'POST',
  });

  return { task, executionOrder, execution };
}

Staff Status Monitoring

Agent状态监控

typescript
// src/lib/staff-monitor.ts
interface AgentStatus {
  agentId: string;
  displayName: string;
  status: 'active' | 'idle' | 'blocked' | 'queued';
  currentTask?: string;
  lastActivity: string;
  tokenUsage24h: number;
}

async function getStaffStatus(): Promise<AgentStatus[]> {
  const response = await callApi({
    endpoint: '/api/staff/status',
    method: 'GET',
    requiresAuth: false, // Read-only endpoint
  });

  return response.agents.map((agent: any) => ({
    agentId: agent.id,
    displayName: agent.display_name || agent.id,
    status: determineStatus(agent),
    currentTask: agent.current_task_id,
    lastActivity: agent.last_seen,
    tokenUsage24h: agent.token_usage_24h || 0,
  }));
}

function determineStatus(agent: any): AgentStatus['status'] {
  if (agent.blocked_reason) return 'blocked';
  if (agent.current_task_id) return 'active';
  if (agent.queued_tasks > 0) return 'queued';
  return 'idle';
}
typescript
// src/lib/staff-monitor.ts
interface AgentStatus {
  agentId: string;
  displayName: string;
  status: 'active' | 'idle' | 'blocked' | 'queued';
  currentTask?: string;
  lastActivity: string;
  tokenUsage24h: number;
}

async function getStaffStatus(): Promise<AgentStatus[]> {
  const response = await callApi({
    endpoint: '/api/staff/status',
    method: 'GET',
    requiresAuth: false, // Read-only endpoint
  });

  return response.agents.map((agent: any) => ({
    agentId: agent.id,
    displayName: agent.display_name || agent.id,
    status: determineStatus(agent),
    currentTask: agent.current_task_id,
    lastActivity: agent.last_seen,
    tokenUsage24h: agent.token_usage_24h || 0,
  }));
}

function determineStatus(agent: any): AgentStatus['status'] {
  if (agent.blocked_reason) return 'blocked';
  if (agent.current_task_id) return 'active';
  if (agent.queued_tasks > 0) return 'queued';
  return 'idle';
}

Task Approval Flow

任务审批流程

typescript
// src/lib/approval-handler.ts
interface ApprovalRequest {
  taskId: string;
  action: 'approve' | 'reject' | 'request-changes';
  comment?: string;
  reviewerId: string;
}

async function handleTaskApproval(request: ApprovalRequest) {
  // Ensure approval actions are enabled
  if (process.env.APPROVAL_ACTIONS_ENABLED !== 'true') {
    throw new Error('Approval actions are disabled');
  }

  const isDryRun = process.env.APPROVAL_ACTIONS_DRY_RUN === 'true';

  const response = await callApi({
    endpoint: `/api/tasks/${request.taskId}/approve`,
    method: 'POST',
    body: {
      action: request.action,
      comment: request.comment,
      reviewer_id: request.reviewerId,
      dry_run: isDryRun,
    },
    requiresAuth: true,
  });

  if (isDryRun) {
    console.log('[DRY RUN] Would have:', request.action, request.taskId);
  }

  return response;
}
typescript
// src/lib/approval-handler.ts
interface ApprovalRequest {
  taskId: string;
  action: 'approve' | 'reject' | 'request-changes';
  comment?: string;
  reviewerId: string;
}

async function handleTaskApproval(request: ApprovalRequest) {
  // Ensure approval actions are enabled
  if (process.env.APPROVAL_ACTIONS_ENABLED !== 'true') {
    throw new Error('Approval actions are disabled');
  }

  const isDryRun = process.env.APPROVAL_ACTIONS_DRY_RUN === 'true';

  const response = await callApi({
    endpoint: `/api/tasks/${request.taskId}/approve`,
    method: 'POST',
    body: {
      action: request.action,
      comment: request.comment,
      reviewer_id: request.reviewerId,
      dry_run: isDryRun,
    },
    requiresAuth: true,
  });

  if (isDryRun) {
    console.log('[DRY RUN] Would have:', request.action, request.taskId);
  }

  return response;
}

Usage Tracking

使用情况追踪

typescript
// src/lib/usage-tracker.ts
interface UsageMetrics {
  period: 'today' | '7d' | '30d';
  tokenCount: number;
  estimatedCost: number;
  topConsumers: Array<{ agentId: string; tokens: number }>;
  contextPressure: Array<{ sessionId: string; usage: number; limit: number }>;
}

async function getUsageMetrics(period: UsageMetrics['period']): Promise<UsageMetrics> {
  const response = await callApi({
    endpoint: `/api/usage/metrics?period=${period}`,
    method: 'GET',
    requiresAuth: false,
  });

  return {
    period,
    tokenCount: response.total_tokens,
    estimatedCost: response.estimated_cost_usd,
    topConsumers: response.agents
      .sort((a: any, b: any) => b.tokens - a.tokens)
      .slice(0, 5),
    contextPressure: response.sessions.filter(
      (s: any) => s.usage / s.limit > 0.75
    ),
  };
}
typescript
// src/lib/usage-tracker.ts
interface UsageMetrics {
  period: 'today' | '7d' | '30d';
  tokenCount: number;
  estimatedCost: number;
  topConsumers: Array<{ agentId: string; tokens: number }>;
  contextPressure: Array<{ sessionId: string; usage: number; limit: number }>;
}

async function getUsageMetrics(period: UsageMetrics['period']): Promise<UsageMetrics> {
  const response = await callApi({
    endpoint: `/api/usage/metrics?period=${period}`,
    method: 'GET',
    requiresAuth: false,
  });

  return {
    period,
    tokenCount: response.total_tokens,
    estimatedCost: response.estimated_cost_usd,
    topConsumers: response.agents
      .sort((a: any, b: any) => b.tokens - a.tokens)
      .slice(0, 5),
    contextPressure: response.sessions.filter(
      (s: any) => s.usage / s.limit > 0.75
    ),
  };
}

Common Patterns

通用模式

Hall Collaboration Workflow

协作大厅完整工作流

typescript
// Complete hall workflow from task creation to completion
async function runHallCollaboration(taskDescription: string) {
  // 1. Create task
  const task = await callApi({
    endpoint: '/api/hall/tasks',
    method: 'POST',
    body: { content: taskDescription, phase: 'discussion' },
  });

  // 2. Wait for discussion (at least 2 agents should reply)
  console.log('Waiting for agent discussion...');
  await pollUntil(
    async () => {
      const messages = await callApi({
        endpoint: `/api/hall/tasks/${task.id}/messages`,
        method: 'GET',
        requiresAuth: false,
      });
      return messages.length >= 2;
    },
    { intervalMs: 2000, timeoutMs: 60000 }
  );

  // 3. Arrange execution order
  await callApi({
    endpoint: `/api/hall/tasks/${task.id}/execution-order`,
    method: 'PUT',
    body: {
      owners: ['agent-planner', 'agent-builder', 'agent-qa'],
    },
  });

  // 4. Start execution
  await callApi({
    endpoint: `/api/hall/tasks/${task.id}/start`,
    method: 'POST',
  });

  // 5. Monitor execution with SSE
  const eventSource = new EventSource(
    `http://127.0.0.1:4310/api/hall/tasks/${task.id}/stream`
  );

  eventSource.onmessage = (event) => {
    const update = JSON.parse(event.data);
    console.log(`[${update.agentId}] ${update.content}`);
  };

  // 6. Wait for completion
  await pollUntil(
    async () => {
      const status = await callApi({
        endpoint: `/api/hall/tasks/${task.id}`,
        method: 'GET',
        requiresAuth: false,
      });
      return status.phase === 'review' || status.phase === 'blocked';
    },
    { intervalMs: 5000, timeoutMs: 600000 }
  );

  eventSource.close();
}

async function pollUntil(
  condition: () => Promise<boolean>,
  options: { intervalMs: number; timeoutMs: number }
): Promise<void> {
  const startTime = Date.now();
  while (!(await condition())) {
    if (Date.now() - startTime > options.timeoutMs) {
      throw new Error('Polling timeout');
    }
    await new Promise((resolve) => setTimeout(resolve, options.intervalMs));
  }
}
typescript
// Complete hall workflow from task creation to completion
async function runHallCollaboration(taskDescription: string) {
  // 1. Create task
  const task = await callApi({
    endpoint: '/api/hall/tasks',
    method: 'POST',
    body: { content: taskDescription, phase: 'discussion' },
  });

  // 2. Wait for discussion (at least 2 agents should reply)
  console.log('Waiting for agent discussion...');
  await pollUntil(
    async () => {
      const messages = await callApi({
        endpoint: `/api/hall/tasks/${task.id}/messages`,
        method: 'GET',
        requiresAuth: false,
      });
      return messages.length >= 2;
    },
    { intervalMs: 2000, timeoutMs: 60000 }
  );

  // 3. Arrange execution order
  await callApi({
    endpoint: `/api/hall/tasks/${task.id}/execution-order`,
    method: 'PUT',
    body: {
      owners: ['agent-planner', 'agent-builder', 'agent-qa'],
    },
  });

  // 4. Start execution
  await callApi({
    endpoint: `/api/hall/tasks/${task.id}/start`,
    method: 'POST',
  });

  // 5. Monitor execution with SSE
  const eventSource = new EventSource(
    `http://127.0.0.1:4310/api/hall/tasks/${task.id}/stream`
  );

  eventSource.onmessage = (event) => {
    const update = JSON.parse(event.data);
    console.log(`[${update.agentId}] ${update.content}`);
  };

  // 6. Wait for completion
  await pollUntil(
    async () => {
      const status = await callApi({
        endpoint: `/api/hall/tasks/${task.id}`,
        method: 'GET',
        requiresAuth: false,
      });
      return status.phase === 'review' || status.phase === 'blocked';
    },
    { intervalMs: 5000, timeoutMs: 600000 }
  );

  eventSource.close();
}

async function pollUntil(
  condition: () => Promise<boolean>,
  options: { intervalMs: number; timeoutMs: number }
): Promise<void> {
  const startTime = Date.now();
  while (!(await condition())) {
    if (Date.now() - startTime > options.timeoutMs) {
      throw new Error('Polling timeout');
    }
    await new Promise((resolve) => setTimeout(resolve, options.intervalMs));
  }
}

Memory Inspection

内存检查

typescript
// src/lib/memory-inspector.ts
async function inspectAgentMemory(agentId: string) {
  // Get memory status
  const status = await callApi({
    endpoint: `/api/memory/${agentId}/status`,
    method: 'GET',
    requiresAuth: false,
  });

  console.log(`Memory status for ${agentId}:`, {
    isUsable: status.is_usable,
    isSearchable: status.is_searchable,
    fileCount: status.file_count,
    totalSizeKb: status.total_size_kb,
  });

  // Read daily memory
  const dailyMemory = await callApi({
    endpoint: `/api/memory/${agentId}/daily`,
    method: 'GET',
    requiresAuth: false,
  });

  console.log('Recent daily entries:', dailyMemory.entries.slice(-5));

  // Search memory (if enabled)
  if (status.is_searchable) {
    const searchResults = await callApi({
      endpoint: `/api/memory/${agentId}/search?q=task+completion`,
      method: 'GET',
      requiresAuth: false,
    });
    console.log('Search results:', searchResults.matches);
  }
}
typescript
// src/lib/memory-inspector.ts
async function inspectAgentMemory(agentId: string) {
  // Get memory status
  const status = await callApi({
    endpoint: `/api/memory/${agentId}/status`,
    method: 'GET',
    requiresAuth: false,
  });

  console.log(`Memory status for ${agentId}:`, {
    isUsable: status.is_usable,
    isSearchable: status.is_searchable,
    fileCount: status.file_count,
    totalSizeKb: status.total_size_kb,
  });

  // Read daily memory
  const dailyMemory = await callApi({
    endpoint: `/api/memory/${agentId}/daily`,
    method: 'GET',
    requiresAuth: false,
  });

  console.log('Recent daily entries:', dailyMemory.entries.slice(-5));

  // Search memory (if enabled)
  if (status.is_searchable) {
    const searchResults = await callApi({
      endpoint: `/api/memory/${agentId}/search?q=task+completion`,
      method: 'GET',
      requiresAuth: false,
    });
    console.log('Search results:', searchResults.matches);
  }
}

Document Management

文档管理

typescript
// src/lib/document-manager.ts
async function updateSharedDocument(filename: string, content: string) {
  // Ensure write mode is enabled
  if (process.env.READONLY_MODE === 'true') {
    throw new Error('Cannot save in READONLY_MODE');
  }

  return callApi({
    endpoint: '/api/documents/shared',
    method: 'PUT',
    body: {
      filename,
      content,
    },
    requiresAuth: true,
  });
}

async function getAgentDocument(agentId: string, docType: string) {
  return callApi({
    endpoint: `/api/documents/agent/${agentId}/${docType}`,
    method: 'GET',
    requiresAuth: false,
  });
}
typescript
// src/lib/document-manager.ts
async function updateSharedDocument(filename: string, content: string) {
  // Ensure write mode is enabled
  if (process.env.READONLY_MODE === 'true') {
    throw new Error('Cannot save in READONLY_MODE');
  }

  return callApi({
    endpoint: '/api/documents/shared',
    method: 'PUT',
    body: {
      filename,
      content,
    },
    requiresAuth: true,
  });
}

async function getAgentDocument(agentId: string, docType: string) {
  return callApi({
    endpoint: `/api/documents/agent/${agentId}/${docType}`,
    method: 'GET',
    requiresAuth: false,
  });
}

Troubleshooting

故障排查

"Role not defined in workspace"

"Role not defined in workspace"

Add agent definitions to
~/.openclaw/openclaw.json
:
json
{
  "agents": [
    {
      "id": "agent-manager",
      "display_name": "Manager",
      "role": "Coordinates work and assigns tasks"
    },
    {
      "id": "agent-builder",
      "display_name": "Builder",
      "role": "Implements features and writes code"
    }
  ]
}
将Agent定义添加到
~/.openclaw/openclaw.json
json
{
  "agents": [
    {
      "id": "agent-manager",
      "display_name": "Manager",
      "role": "Coordinates work and assigns tasks"
    },
    {
      "id": "agent-builder",
      "display_name": "Builder",
      "role": "Implements features and writes code"
    }
  ]
}

Connection Issues

连接问题

Check connection health in Settings → Connection health card. Common issues:
typescript
// Verify OpenClaw is reachable
const health = await callApi({
  endpoint: '/api/health',
  method: 'GET',
  requiresAuth: false,
});

console.log('OpenClaw connection:', health.openclaw_reachable);
console.log('Memory accessible:', health.memory_accessible);
console.log('Task storage:', health.task_storage_ready);
在设置→连接健康卡片中检查连接状态。常见问题排查:
typescript
// Verify OpenClaw is reachable
const health = await callApi({
  endpoint: '/api/health',
  method: 'GET',
  requiresAuth: false,
});

console.log('OpenClaw connection:', health.openclaw_reachable);
console.log('Memory accessible:', health.memory_accessible);
console.log('Task storage:', health.task_storage_ready);

Authentication Failures

认证失败

Ensure
LOCAL_API_TOKEN
is set and matches in both
.env
and UI:
bash
undefined
确保
LOCAL_API_TOKEN
已设置,且在
.env
和UI中保持一致:
bash
undefined

Generate a secure token

Generate a secure token

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

Add to .env

Add to .env

LOCAL_API_TOKEN=<generated-token>
undefined
LOCAL_API_TOKEN=<generated-token>
undefined

Hall Execution Not Starting

大厅执行未启动

  1. Verify agents are defined in OpenClaw roster
  2. Check that execution order is saved before starting
  3. Ensure at least one owner is in the queue
  4. Check logs for runtime dispatch errors
typescript
// Debug execution state
const taskState = await callApi({
  endpoint: `/api/hall/tasks/${taskId}`,
  method: 'GET',
  requiresAuth: false,
});

console.log('Phase:', taskState.phase);
console.log('Owners:', taskState.execution_order?.owners);
console.log('Current owner index:', taskState.execution_order?.current_owner_index);
  1. 确认Agent已在OpenClaw名单中定义
  2. 检查执行顺序是否在启动前已保存
  3. 确保队列中至少有一个所有者
  4. 查看日志中的运行时调度错误
typescript
// Debug execution state
const taskState = await callApi({
  endpoint: `/api/hall/tasks/${taskId}`,
  method: 'GET',
  requiresAuth: false,
});

console.log('Phase:', taskState.phase);
console.log('Owners:', taskState.execution_order?.owners);
console.log('Current owner index:', taskState.execution_order?.current_owner_index);

High Context Pressure

高上下文压力

Monitor context usage in Usage → Context pressure card:
typescript
const contextMetrics = await callApi({
  endpoint: '/api/usage/context-pressure',
  method: 'GET',
  requiresAuth: false,
});

// Find sessions near limit
const critical = contextMetrics.sessions.filter(
  (s: any) => s.usage / s.limit > 0.9
);

console.log('Critical sessions:', critical);
在使用情况→上下文压力卡片中监控上下文使用情况:
typescript
const contextMetrics = await callApi({
  endpoint: '/api/usage/context-pressure',
  method: 'GET',
  requiresAuth: false,
});

// Find sessions near limit
const critical = contextMetrics.sessions.filter(
  (s: any) => s.usage / s.limit > 0.9
);

console.log('Critical sessions:', critical);

Security Best Practices

安全最佳实践

  1. Keep defaults: Don't disable
    READONLY_MODE
    or
    LOCAL_TOKEN_AUTH_REQUIRED
    unless necessary
  2. Strong tokens: Use
    crypto.randomBytes(32).toString('hex')
    for
    LOCAL_API_TOKEN
  3. Network binding: Keep
    UI_BIND_ADDRESS=127.0.0.1
    unless you need remote access
  4. Dry-run first: Test approval actions with
    APPROVAL_ACTIONS_DRY_RUN=true
    before enabling live mutations
  5. Monitor Security risk summary: Check Settings page for current risk assessment
  1. 保留默认配置:除非必要,不要禁用
    READONLY_MODE
    LOCAL_TOKEN_AUTH_REQUIRED
  2. 使用强令牌:采用
    crypto.randomBytes(32).toString('hex')
    生成
    LOCAL_API_TOKEN
  3. 网络绑定限制:保持
    UI_BIND_ADDRESS=127.0.0.1
    ,除非需要远程访问
  4. 先进行试运行:在启用实时变更操作前,通过
    APPROVAL_ACTIONS_DRY_RUN=true
    测试审批操作
  5. 监控安全风险摘要:在设置页面查看当前风险评估

Further Resources

更多资源