Skip to main content

openclaw-control-center

Run a local observability and control dashboard for OpenClaw AI agents with real-time collaboration, task management, and safety-first defaults.

インストールへ移動

ソース情報

リポジトリ
reason-machines/hermes-skills
ソースの最終更新活動
2026年5月16日 18:19
検出された SKILL.md の言語
英語
スター
5
フォーク
0

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
openclaw-control-center
description
Run a local observability and control dashboard for OpenClaw AI agents with real-time collaboration, task management, and safety-first defaults.
triggers
["set up openclaw control center dashboard","create openclaw observability interface","monitor openclaw agents and tasks","implement openclaw collaboration hall","configure openclaw control center","debug openclaw agent activity","track openclaw usage and spend","manage openclaw task approvals"]
# OpenClaw Control Center > Skill by [ara.so](https://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). ## 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 ## Installation ```bash # Clone the repository git clone https://github.com/TianyiDataScience/openclaw-control-center.git cd openclaw-control-center # Install dependencies npm install # Set up environment cp .env.example .env # Build the project npm run build # Run tests npm test # Run smoke tests npm run smoke:ui npm run smoke:hall # Start development server npm run dev:ui ``` ## Configuration ### Environment Variables (.env) ```bash # Safety and security (defaults) READONLY_MODE=true LOCAL_TOKEN_AUTH_REQUIRED=true LOCAL_API_TOKEN=your-long-random-secret-here # Import/export protection IMPORT_MUTATION_ENABLED=false IMPORT_MUTATION_DRY_RUN=false # Approval actions APPROVAL_ACTIONS_ENABLED=false APPROVAL_ACTIONS_DRY_RUN=true # UI configuration UI_PORT=4310 UI_BIND_ADDRESS=127.0.0.1 # For Tailscale or remote access OPENCLAW_CONTROL_UI_URL=http://<tailscale-host>:4310/ # UI_BIND_ADDRESS=0.0.0.0 # Auto-set when OPENCLAW_CONTROL_UI_URL is provided ``` ### 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 ``` ## Key Commands ### Development ```bash # Start UI development server (recommended, cross-platform) npm run dev:ui # Single monitor pass without UI npm run dev # Build production bundle npm run build # Run all tests npm test # Smoke tests for UI and hall npm run smoke:ui npm run smoke:hall # Linting npm run lint npm run lint:fix ``` ### Accessing the UI ```bash # English interface http://127.0.0.1:4310/?section=overview&lang=en # Chinese interface http://127.0.0.1:4310/?section=overview&lang=zh # Direct section access http://127.0.0.1:4310/?section=collaboration&lang=en http://127.0.0.1:4310/?section=staff&lang=en http://127.0.0.1:4310/?section=tasks&lang=en ``` ## 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 ``` ### API Authentication Pattern ```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 }; } ``` ### Staff Status Monitoring ```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; } ``` ### 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 ), }; } ``` ## 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)); } } ``` ### 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, });
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る