openclaw-control-center by aradotso/trending-skills
npx skills add https://github.com/aradotso/trending-skills --skill openclaw-control-centerSkill by ara.so — Daily 2026 Skills collection
OpenClaw Control Center 将 OpenClaw 从一个黑盒转变为一个本地、可审计的控制中心。它提供了对智能体活动、令牌消耗、任务执行链、跨会话协作、记忆状态和文档来源的可见性——并采用安全至上的默认设置,默认情况下所有变更操作均处于关闭状态。
Main ⇄ Pandas)git clone https://github.com/TianyiDataScience/openclaw-control-center.git
cd openclaw-control-center
npm install
cp .env.example .env
npm run build
npm test
npm run smoke:ui
npm run dev:ui
打开:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
http://127.0.0.1:4310/?section=overview&lang=zhhttp://127.0.0.1:4310/?section=overview&lang=en使用
npm run dev:ui而非UI_MODE=true npm run dev—— 更稳定,尤其是在 Windows 命令行环境中。
openclaw-control-center/
├── control-center/ # 所有修改必须限制在此目录内
│ ├── src/
│ │ ├── runtime/ # 核心运行时、连接器、监控器
│ │ └── ui/ # 前端 UI 组件
│ ├── .env.example
│ └── package.json
├── docs/
│ └── assets/ # 截图和文档图片
├── README.md
└── README.en.md
关键约束 : 仅修改
control-center/目录内的文件。切勿修改~/.openclaw/openclaw.json。
复制 .env.example 为 .env 并进行配置:
# 安全默认值 — 在不理解影响的情况下请勿更改
READONLY_MODE=true
LOCAL_TOKEN_AUTH_REQUIRED=true
IMPORT_MUTATION_ENABLED=false
IMPORT_MUTATION_DRY_RUN=false
APPROVAL_ACTIONS_ENABLED=false
APPROVAL_ACTIONS_DRY_RUN=true
# 连接
OPENCLAW_GATEWAY_URL=http://127.0.0.1:PORT
OPENCLAW_HOME=~/.openclaw
# UI
PORT=4310
DEFAULT_LANG=zh
| 标志 | 默认值 | 效果 |
|---|---|---|
READONLY_MODE | true | 所有更改状态的端点被禁用 |
LOCAL_TOKEN_AUTH_REQUIRED | true | 导入/导出和写入 API 需要本地令牌 |
IMPORT_MUTATION_ENABLED | false | 导入变更被完全阻止 |
IMPORT_MUTATION_DRY_RUN | false | 启用时导入的试运行模式 |
APPROVAL_ACTIONS_ENABLED | false | 审批操作被硬性禁用 |
APPROVAL_ACTIONS_DRY_RUN | true | 启用时审批操作以试运行模式执行 |
# 开发
npm run dev:ui # 启动 UI 服务器(推荐)
npm run dev # 一次性监控运行,无 HTTP UI
# 构建与测试
npm run build # TypeScript 编译
npm test # 运行测试套件
npm run smoke:ui # 对 UI 端点进行冒烟测试
# 代码检查
npm run lint # ESLint 检查
npm run lint:fix # 自动修复代码检查问题
import { createMonitor } from './src/runtime/monitor';
const monitor = createMonitor({
gatewayUrl: process.env.OPENCLAW_GATEWAY_URL ?? 'http://127.0.0.1:4310',
readonlyMode: process.env.READONLY_MODE !== 'false',
localTokenAuthRequired: process.env.LOCAL_TOKEN_AUTH_REQUIRED !== 'false',
});
// 获取当前系统概览
const overview = await monitor.getOverview();
console.log(overview.systemStatus); // 'healthy' | 'degraded' | 'critical'
console.log(overview.pendingItems); // number
console.log(overview.activeAgents); // Agent[]
import { StaffConnector } from './src/runtime/connectors/staff';
const staff = new StaffConnector({ gatewayUrl: process.env.OPENCLAW_GATEWAY_URL });
// 获取正在主动执行的智能体(不仅仅是排队中的)
const activeAgents = await staff.getActiveAgents();
activeAgents.forEach(agent => {
console.log(`${agent.name}: ${agent.status}`);
// 'executing' | 'queued' | 'idle' | 'blocked'
console.log(`Current task: ${agent.currentTask?.title ?? 'none'}`);
console.log(`Last output: ${agent.lastOutput}`);
});
// 获取完整的人员名册,包括队列深度
const roster = await staff.getRoster();
import { CollaborationTracer } from './src/runtime/connectors/collaboration';
const tracer = new CollaborationTracer({ gatewayUrl: process.env.OPENCLAW_GATEWAY_URL });
// 获取父子会话交接
const handoffs = await tracer.getSessionHandoffs();
handoffs.forEach(handoff => {
console.log(`${handoff.parentSession} → ${handoff.childSession}`);
console.log(`Delegated task: ${handoff.taskTitle}`);
console.log(`Status: ${handoff.status}`);
});
// 获取经过验证的跨会话消息(例如 Main ⇄ Pandas)
const crossSessionMessages = await tracer.getCrossSessionMessages();
crossSessionMessages.forEach(msg => {
console.log(`${msg.fromAgent} ⇄ ${msg.toAgent}: ${msg.messageType}`);
// messageType: 'sessions_send' | 'inter-session message'
});
import { UsageConnector } from './src/runtime/connectors/usage';
const usage = new UsageConnector({ gatewayUrl: process.env.OPENCLAW_GATEWAY_URL });
// 今日使用情况
const today = await usage.getUsageSummary('today');
console.log(`Tokens used: ${today.tokensUsed}`);
console.log(`Cost: $${today.costUsd.toFixed(4)}`);
console.log(`Context pressure: ${today.contextPressure}`);
// contextPressure: 'low' | 'medium' | 'high' | 'critical'
// 7 天内的使用趋势
const trend = await usage.getUsageTrend(7);
trend.forEach(day => {
console.log(`${day.date}: ${day.tokensUsed} tokens, $${day.costUsd.toFixed(4)}`);
});
// 按任务归因令牌消耗(谁消耗了计划任务的令牌)
const attribution = await usage.getTokenAttribution();
attribution.tasks.forEach(task => {
console.log(`${task.title}: ${task.tokensUsed} (${task.percentOfTotal}%)`);
});
import { MemoryConnector } from './src/runtime/connectors/memory';
const memory = new MemoryConnector({
openclawHome: process.env.OPENCLAW_HOME ?? '~/.openclaw',
});
// 获取每个活跃智能体的记忆健康状况(限定于 openclaw.json)
const memoryState = await memory.getMemoryState();
memoryState.agents.forEach(agent => {
console.log(`${agent.name}:`);
console.log(` Available: ${agent.memoryAvailable}`);
console.log(` Searchable: ${agent.memorySearchable}`);
console.log(` Needs review: ${agent.needsReview}`);
});
// 读取智能体的每日记忆
const dailyMemory = await memory.readDailyMemory('main-agent');
console.log(dailyMemory.content);
// 编辑记忆(需要 READONLY_MODE=false 且有效的本地令牌)
await memory.writeDailyMemory('main-agent', updatedContent, { token: localToken });
import { WiringChecker } from './src/runtime/connectors/wiring';
const wiring = new WiringChecker({ gatewayUrl: process.env.OPENCLAW_GATEWAY_URL });
const status = await wiring.getWiringStatus();
status.connectors.forEach(connector => {
console.log(`${connector.name}: ${connector.status}`);
// status: 'connected' | 'partial' | 'disconnected'
if (connector.status !== 'connected') {
console.log(` Fix: ${connector.nextStep}`);
}
});
import { TaskConnector } from './src/runtime/connectors/tasks';
const tasks = new TaskConnector({
gatewayUrl: process.env.OPENCLAW_GATEWAY_URL,
approvalActionsEnabled: process.env.APPROVAL_ACTIONS_ENABLED === 'true',
approvalActionsDryRun: process.env.APPROVAL_ACTIONS_DRY_RUN !== 'false',
});
// 如果 APPROVAL_ACTIONS_ENABLED=false(默认),此操作将抛出异常
try {
const result = await tasks.approveTask('task-id-123', { token: localToken });
if (result.dryRun) {
console.log('Dry run — no actual state change');
}
} catch (err) {
if (err.code === 'APPROVAL_ACTIONS_DISABLED') {
console.log('Set APPROVAL_ACTIONS_ENABLED=true to enable approvals');
}
}
通过查询参数导航:
http://127.0.0.1:4310/?section=overview&lang=zh
http://127.0.0.1:4310/?section=usage&lang=en
http://127.0.0.1:4310/?section=staff&lang=zh
http://127.0.0.1:4310/?section=collaboration&lang=en
http://127.0.0.1:4310/?section=tasks&lang=zh
http://127.0.0.1:4310/?section=memory&lang=en
http://127.0.0.1:4310/?section=documents&lang=zh
http://127.0.0.1:4310/?section=settings&lang=en
部分:overview | usage | staff | collaboration | tasks | memory | documents | settings
语言:zh (中文,默认) | en (英文)
如果你的 OpenClaw 智能体需要将安装指令交接给控制中心进行设置,请使用文档化的安装代码块:
// 在你的 OpenClaw 智能体任务中
const installInstructions = `
cd openclaw-control-center
npm install
cp .env.example .env
# 编辑 .env: 设置 OPENCLAW_GATEWAY_URL 和 OPENCLAW_HOME
npm run build && npm test && npm run dev:ui
`;
所有连接器都位于 control-center/src/runtime/connectors/。遵循此模式:
// control-center/src/runtime/connectors/my-connector.ts
import { BaseConnector, ConnectorOptions } from './base';
export interface MyData {
id: string;
value: string;
}
export class MyConnector extends BaseConnector {
constructor(options: ConnectorOptions) {
super(options);
}
async getData(): Promise<MyData[]> {
// 对于任何写操作,始终检查只读模式
this.assertNotReadonly('getData is readonly-safe');
const response = await this.fetch('/api/my-endpoint');
return response.json() as Promise<MyData[]>;
}
}
// control-center/src/ui/sections/MySection.tsx
import React from 'react';
import { useConnector } from '../hooks/useConnector';
import { MyConnector } from '../../runtime/connectors/my-connector';
export const MySection: React.FC = () => {
const { data, loading, error } = useConnector(MyConnector, 'getData');
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<ul>
{data?.map(item => (
<li key={item.id}>{item.value}</li>
))}
</ul>
);
};
这几乎总是意味着工作目录错误:
# 确保你在仓库根目录
pwd # 应以 /openclaw-control-center 结尾
ls control-center/src/runtime # 应该存在
如果克隆正确但仍然缺失:克隆不完整。重新克隆:
git clone https://github.com/TianyiDataScience/openclaw-control-center.git
# 检查端口 4310 是否被占用
lsof -i :4310
# 或者在 Windows 上
netstat -ano | findstr :4310
# 在 .env 中更改端口
PORT=4311
Settings → 接线状态 (Wiring Status) —— 它列出了哪些连接器已连接、部分连接或缺失。OPENCLAW_GATEWAY_URL 未设置或端口错误OPENCLAW_HOME 未指向实际的 ~/.openclaw# 生成本地令牌(查看 openclaw 文档了解令牌位置)
cat ~/.openclaw/local-token
# 在 API 调用中通过请求头传递
curl -H "X-Local-Token: <token>" http://127.0.0.1:4310/api/tasks/approve
检查你的 .env:
APPROVAL_ACTIONS_ENABLED=true # 必须为 true
APPROVAL_ACTIONS_DRY_RUN=false # 必须为 false 才能实际执行
两者都必须明确设置。默认是禁用 + 试运行。
记忆部分限定于 openclaw.json 中列出的智能体。如果已删除的智能体仍然出现:
# 检查活跃智能体
cat ~/.openclaw/openclaw.json | grep -A5 '"agents"'
从 openclaw.json 中删除过时的条目——记忆部分将在下次加载时更新。
优先使用 npm run dev:ui 而非 UI_MODE=true npm run dev。跨环境变量设置在 PowerShell/CMD 中的行为不同。dev:ui 脚本在内部处理了这个问题。
~/.openclaw 的读取权限~/.codex 和 OpenClaw 订阅快照以获取完整的使用数据每周安装数
1.8K
仓库
GitHub 星标
10
首次出现
9 天前
安全审计
安装于
github-copilot1.7K
opencode1.7K
gemini-cli1.7K
codex1.7K
kimi-cli1.7K
cursor1.7K
Skill by ara.so — Daily 2026 Skills collection
OpenClaw Control Center transforms OpenClaw from a black box into a local, auditable control center. It provides visibility into agent activity, token spend, task execution chains, cross-session collaboration, memory state, and document sources — with security-first defaults that keep all mutations off by default.
Main ⇄ Pandas)git clone https://github.com/TianyiDataScience/openclaw-control-center.git
cd openclaw-control-center
npm install
cp .env.example .env
npm run build
npm test
npm run smoke:ui
npm run dev:ui
Open:
http://127.0.0.1:4310/?section=overview&lang=zhhttp://127.0.0.1:4310/?section=overview&lang=enUse
npm run dev:uioverUI_MODE=true npm run dev— more stable, especially on Windows shells.
openclaw-control-center/
├── control-center/ # All modifications must stay within this directory
│ ├── src/
│ │ ├── runtime/ # Core runtime, connectors, monitors
│ │ └── ui/ # Frontend UI components
│ ├── .env.example
│ └── package.json
├── docs/
│ └── assets/ # Screenshots and documentation images
├── README.md
└── README.en.md
Critical constraint : Only modify files inside
control-center/. Never modify~/.openclaw/openclaw.json.
Copy .env.example to .env and configure:
# Security defaults — do NOT change without understanding implications
READONLY_MODE=true
LOCAL_TOKEN_AUTH_REQUIRED=true
IMPORT_MUTATION_ENABLED=false
IMPORT_MUTATION_DRY_RUN=false
APPROVAL_ACTIONS_ENABLED=false
APPROVAL_ACTIONS_DRY_RUN=true
# Connection
OPENCLAW_GATEWAY_URL=http://127.0.0.1:PORT
OPENCLAW_HOME=~/.openclaw
# UI
PORT=4310
DEFAULT_LANG=zh
| Flag | Default | Effect |
|---|---|---|
READONLY_MODE | true | All state-changing endpoints disabled |
LOCAL_TOKEN_AUTH_REQUIRED | true | Import/export and write APIs require local token |
IMPORT_MUTATION_ENABLED | false | Import mutations blocked entirely |
IMPORT_MUTATION_DRY_RUN |
# Development
npm run dev:ui # Start UI server (recommended)
npm run dev # One-shot monitor run, no HTTP UI
# Build & Test
npm run build # TypeScript compile
npm test # Run test suite
npm run smoke:ui # Smoke test the UI endpoints
# Lint
npm run lint # ESLint check
npm run lint:fix # Auto-fix lint issues
import { createMonitor } from './src/runtime/monitor';
const monitor = createMonitor({
gatewayUrl: process.env.OPENCLAW_GATEWAY_URL ?? 'http://127.0.0.1:4310',
readonlyMode: process.env.READONLY_MODE !== 'false',
localTokenAuthRequired: process.env.LOCAL_TOKEN_AUTH_REQUIRED !== 'false',
});
// Fetch current system overview
const overview = await monitor.getOverview();
console.log(overview.systemStatus); // 'healthy' | 'degraded' | 'critical'
console.log(overview.pendingItems); // number
console.log(overview.activeAgents); // Agent[]
import { StaffConnector } from './src/runtime/connectors/staff';
const staff = new StaffConnector({ gatewayUrl: process.env.OPENCLAW_GATEWAY_URL });
// Get agents actively executing (not just queued)
const activeAgents = await staff.getActiveAgents();
activeAgents.forEach(agent => {
console.log(`${agent.name}: ${agent.status}`);
// 'executing' | 'queued' | 'idle' | 'blocked'
console.log(`Current task: ${agent.currentTask?.title ?? 'none'}`);
console.log(`Last output: ${agent.lastOutput}`);
});
// Get the full staff roster including queue depth
const roster = await staff.getRoster();
import { CollaborationTracer } from './src/runtime/connectors/collaboration';
const tracer = new CollaborationTracer({ gatewayUrl: process.env.OPENCLAW_GATEWAY_URL });
// Get parent-child session handoffs
const handoffs = await tracer.getSessionHandoffs();
handoffs.forEach(handoff => {
console.log(`${handoff.parentSession} → ${handoff.childSession}`);
console.log(`Delegated task: ${handoff.taskTitle}`);
console.log(`Status: ${handoff.status}`);
});
// Get verified cross-session messages (e.g. Main ⇄ Pandas)
const crossSessionMessages = await tracer.getCrossSessionMessages();
crossSessionMessages.forEach(msg => {
console.log(`${msg.fromAgent} ⇄ ${msg.toAgent}: ${msg.messageType}`);
// messageType: 'sessions_send' | 'inter-session message'
});
import { UsageConnector } from './src/runtime/connectors/usage';
const usage = new UsageConnector({ gatewayUrl: process.env.OPENCLAW_GATEWAY_URL });
// Today's usage
const today = await usage.getUsageSummary('today');
console.log(`Tokens used: ${today.tokensUsed}`);
console.log(`Cost: $${today.costUsd.toFixed(4)}`);
console.log(`Context pressure: ${today.contextPressure}`);
// contextPressure: 'low' | 'medium' | 'high' | 'critical'
// Usage trend over 7 days
const trend = await usage.getUsageTrend(7);
trend.forEach(day => {
console.log(`${day.date}: ${day.tokensUsed} tokens, $${day.costUsd.toFixed(4)}`);
});
// Token attribution by task (who ate the scheduled task tokens)
const attribution = await usage.getTokenAttribution();
attribution.tasks.forEach(task => {
console.log(`${task.title}: ${task.tokensUsed} (${task.percentOfTotal}%)`);
});
import { MemoryConnector } from './src/runtime/connectors/memory';
const memory = new MemoryConnector({
openclawHome: process.env.OPENCLAW_HOME ?? '~/.openclaw',
});
// Get memory health per active agent (scoped to openclaw.json)
const memoryState = await memory.getMemoryState();
memoryState.agents.forEach(agent => {
console.log(`${agent.name}:`);
console.log(` Available: ${agent.memoryAvailable}`);
console.log(` Searchable: ${agent.memorySearchable}`);
console.log(` Needs review: ${agent.needsReview}`);
});
// Read daily memory for an agent
const dailyMemory = await memory.readDailyMemory('main-agent');
console.log(dailyMemory.content);
// Edit memory (requires READONLY_MODE=false and valid local token)
await memory.writeDailyMemory('main-agent', updatedContent, { token: localToken });
import { WiringChecker } from './src/runtime/connectors/wiring';
const wiring = new WiringChecker({ gatewayUrl: process.env.OPENCLAW_GATEWAY_URL });
const status = await wiring.getWiringStatus();
status.connectors.forEach(connector => {
console.log(`${connector.name}: ${connector.status}`);
// status: 'connected' | 'partial' | 'disconnected'
if (connector.status !== 'connected') {
console.log(` Fix: ${connector.nextStep}`);
}
});
import { TaskConnector } from './src/runtime/connectors/tasks';
const tasks = new TaskConnector({
gatewayUrl: process.env.OPENCLAW_GATEWAY_URL,
approvalActionsEnabled: process.env.APPROVAL_ACTIONS_ENABLED === 'true',
approvalActionsDryRun: process.env.APPROVAL_ACTIONS_DRY_RUN !== 'false',
});
// This throws if APPROVAL_ACTIONS_ENABLED=false (default)
try {
const result = await tasks.approveTask('task-id-123', { token: localToken });
if (result.dryRun) {
console.log('Dry run — no actual state change');
}
} catch (err) {
if (err.code === 'APPROVAL_ACTIONS_DISABLED') {
console.log('Set APPROVAL_ACTIONS_ENABLED=true to enable approvals');
}
}
Navigate via query params:
http://127.0.0.1:4310/?section=overview&lang=zh
http://127.0.0.1:4310/?section=usage&lang=en
http://127.0.0.1:4310/?section=staff&lang=zh
http://127.0.0.1:4310/?section=collaboration&lang=en
http://127.0.0.1:4310/?section=tasks&lang=zh
http://127.0.0.1:4310/?section=memory&lang=en
http://127.0.0.1:4310/?section=documents&lang=zh
http://127.0.0.1:4310/?section=settings&lang=en
Sections: overview | usage | staff | collaboration | tasks | memory | documents | settings
Languages: zh (Chinese, default) | en (English)
If your OpenClaw agent needs to hand off instructions to the control center for setup, use the documented install block:
// In your OpenClaw agent task
const installInstructions = `
cd openclaw-control-center
npm install
cp .env.example .env
# Edit .env: set OPENCLAW_GATEWAY_URL and OPENCLAW_HOME
npm run build && npm test && npm run dev:ui
`;
All connectors live in control-center/src/runtime/connectors/. Follow this pattern:
// control-center/src/runtime/connectors/my-connector.ts
import { BaseConnector, ConnectorOptions } from './base';
export interface MyData {
id: string;
value: string;
}
export class MyConnector extends BaseConnector {
constructor(options: ConnectorOptions) {
super(options);
}
async getData(): Promise<MyData[]> {
// Always check readonly mode for any write operation
this.assertNotReadonly('getData is readonly-safe');
const response = await this.fetch('/api/my-endpoint');
return response.json() as Promise<MyData[]>;
}
}
// control-center/src/ui/sections/MySection.tsx
import React from 'react';
import { useConnector } from '../hooks/useConnector';
import { MyConnector } from '../../runtime/connectors/my-connector';
export const MySection: React.FC = () => {
const { data, loading, error } = useConnector(MyConnector, 'getData');
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<ul>
{data?.map(item => (
<li key={item.id}>{item.value}</li>
))}
</ul>
);
};
This almost always means the working directory is wrong:
# Ensure you're in the repo root
pwd # should end in /openclaw-control-center
ls control-center/src/runtime # should exist
If cloned correctly but still missing: the clone was incomplete. Re-clone:
git clone https://github.com/TianyiDataScience/openclaw-control-center.git
# Check if port 4310 is in use
lsof -i :4310
# or on Windows
netstat -ano | findstr :4310
# Change port in .env
PORT=4311
Settings → 接线状态 (Wiring Status) — it lists exactly which connectors are connected, partial, or missing.OPENCLAW_GATEWAY_URL not set or wrong portOPENCLAW_HOME doesn't point to actual ~/.openclaw# Generate a local token (see openclaw docs for token location)
cat ~/.openclaw/local-token
# Pass via header in API calls
curl -H "X-Local-Token: <token>" http://127.0.0.1:4310/api/tasks/approve
Check your .env:
APPROVAL_ACTIONS_ENABLED=true # Must be true
APPROVAL_ACTIONS_DRY_RUN=false # Must be false for real execution
Both must be explicitly set. Default is disabled + dry-run.
The memory section is scoped to agents listed in openclaw.json. If deleted agents still appear:
# Check active agents
cat ~/.openclaw/openclaw.json | grep -A5 '"agents"'
Remove stale entries from openclaw.json — the memory section will update on next load.
Prefer npm run dev:ui over UI_MODE=true npm run dev. Cross-env variable setting behaves differently in PowerShell/CMD. The dev:ui script handles this internally.
~/.openclaw on the local machine~/.codex and OpenClaw subscription snapshot for full usage dataWeekly Installs
1.8K
Repository
GitHub Stars
10
First Seen
9 days ago
Security Audits
Gen Agent Trust HubWarnSocketPassSnykFail
Installed on
github-copilot1.7K
opencode1.7K
gemini-cli1.7K
codex1.7K
kimi-cli1.7K
cursor1.7K
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
102,200 周安装
false |
| Dry-run mode for imports when enabled |
APPROVAL_ACTIONS_ENABLED | false | Approval actions hard-disabled |
APPROVAL_ACTIONS_DRY_RUN | true | Approval actions run as dry-run when enabled |