openclaw-control-center
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOpenClaw 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
undefinedbash
undefinedClone the repository
Clone the repository
git clone https://github.com/TianyiDataScience/openclaw-control-center.git
cd openclaw-control-center
git clone https://github.com/TianyiDataScience/openclaw-control-center.git
cd openclaw-control-center
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
undefinednpm run dev:ui
undefinedConfiguration
配置说明
Environment Variables (.env)
环境变量(.env)
bash
undefinedbash
undefinedSafety 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
undefinedundefinedDirectory 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 configurationcontrol-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 configurationKey Commands
核心命令
Development
开发阶段
bash
undefinedbash
undefinedStart 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
undefinednpm run lint
npm run lint:fix
undefinedAccessing the UI
访问UI界面
bash
undefinedbash
undefinedEnglish 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=falsetypescript
// .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=falseAPI 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.jsonjson
{
"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.jsonjson
{
"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 is set and matches in both and UI:
LOCAL_API_TOKEN.envbash
undefined确保已设置,且在和UI中保持一致:
LOCAL_API_TOKEN.envbash
undefinedGenerate 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>
undefinedLOCAL_API_TOKEN=<generated-token>
undefinedHall Execution Not Starting
大厅执行未启动
- Verify agents are defined in OpenClaw roster
- Check that execution order is saved before starting
- Ensure at least one owner is in the queue
- 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);- 确认Agent已在OpenClaw名单中定义
- 检查执行顺序是否在启动前已保存
- 确保队列中至少有一个所有者
- 查看日志中的运行时调度错误
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
安全最佳实践
- Keep defaults: Don't disable or
READONLY_MODEunless necessaryLOCAL_TOKEN_AUTH_REQUIRED - Strong tokens: Use for
crypto.randomBytes(32).toString('hex')LOCAL_API_TOKEN - Network binding: Keep unless you need remote access
UI_BIND_ADDRESS=127.0.0.1 - Dry-run first: Test approval actions with before enabling live mutations
APPROVAL_ACTIONS_DRY_RUN=true - Monitor Security risk summary: Check Settings page for current risk assessment
- 保留默认配置:除非必要,不要禁用或
READONLY_MODELOCAL_TOKEN_AUTH_REQUIRED - 使用强令牌:采用生成
crypto.randomBytes(32).toString('hex')LOCAL_API_TOKEN - 网络绑定限制:保持,除非需要远程访问
UI_BIND_ADDRESS=127.0.0.1 - 先进行试运行:在启用实时变更操作前,通过测试审批操作
APPROVAL_ACTIONS_DRY_RUN=true - 监控安全风险摘要:在设置页面查看当前风险评估
Further Resources
更多资源
- FAQ & Best Practices
- GitHub Repository
- Chinese README
- FAQ与最佳实践
- GitHub仓库
- 中文说明文档