Trending-skills openclaw-control-center
Local-first, security-first control center for OpenClaw agents — visibility dashboard with readonly defaults, token attribution, collaboration tracing, and safe write operations.
git clone https://github.com/Aradotso/trending-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/Aradotso/trending-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/openclaw-control-center" ~/.claude/skills/aradotso-trending-skills-openclaw-control-center && rm -rf "$T"
T=$(mktemp -d) && git clone --depth=1 https://github.com/Aradotso/trending-skills "$T" && mkdir -p ~/.openclaw/skills && cp -r "$T/skills/openclaw-control-center" ~/.openclaw/skills/aradotso-trending-skills-openclaw-control-center && rm -rf "$T"
skills/openclaw-control-center/SKILL.mdopenclaw-control-center
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.
What It Does
- Overview: System health, pending items, risk signals, and operational summary
- Usage: Daily/7d/30d token spend, quota, context pressure, subscription window
- Staff: Who is actively executing vs. queued — not just "has tasks"
- Collaboration: Parent-child session handoffs and verified cross-session messages (e.g.
)Main ⇄ Pandas - Tasks: Task board, approvals, execution chains, run evidence
- Memory: Per-agent memory health, searchability, and source file editing
- Documents: Shared and agent-core documents opened from actual source files
- Settings: Connector wiring status, security risk summary, update status
Installation
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=en
Use
overnpm run dev:ui— more stable, especially on Windows shells.UI_MODE=true npm run dev
Project Structure
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
. Never modifycontrol-center/.~/.openclaw/openclaw.json
Environment Configuration
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
Security Flag Meanings
| Flag | Default | Effect |
|---|---|---|
| | All state-changing endpoints disabled |
| | Import/export and write APIs require local token |
| | Import mutations blocked entirely |
| | Dry-run mode for imports when enabled |
| | Approval actions hard-disabled |
| | Approval actions run as dry-run when enabled |
Key Commands
# 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
TypeScript Code Examples
Connecting to the Runtime Monitor
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[]
Reading Agent Staff Status
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();
Tracing Cross-Session Collaboration
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' });
Fetching Token Usage and Spend
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}%)`); });
Reading Memory State
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 });
Checking Wiring Status
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}`); } });
Approving Tasks (Gated Endpoint)
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'); } }
UI Section Navigation
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)
Integration Patterns
Embedding in an Existing OpenClaw Workflow
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 `;
Adding a Custom Connector
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[]>; } }
Custom UI Section
// 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> ); };
Troubleshooting
"Missing src/runtime" or "Missing core source"
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
UI Doesn't Start / Port Conflicts
# Check if port 4310 is in use lsof -i :4310 # or on Windows netstat -ano | findstr :4310 # Change port in .env PORT=4311
Data Not Showing (Partial or Empty Sections)
- Open
→ 接线状态 (Wiring Status) — it lists exactly which connectors are connected, partial, or missing.Settings - Common causes:
not set or wrong portOPENCLAW_GATEWAY_URL
doesn't point to actualOPENCLAW_HOME~/.openclaw- OpenClaw subscription snapshot not at default path
Token Auth Failures
# 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
Approval Actions Silently Do Nothing
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.
Memory Section Shows Inactive Agents
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.
Windows Shell Issues
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.
Prerequisites
- Node.js + npm
- A running OpenClaw installation with accessible Gateway
- Read access to
on the local machine~/.openclaw - (Optional)
and OpenClaw subscription snapshot for full usage data~/.codex