edict-multi-agent-orchestration

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Edict (三省六部) Multi-Agent Orchestration

Edict(三省六部)多Agent编排系统

Skill by ara.so — Daily 2026 Skills collection.
Edict implements a 1400-year-old Tang Dynasty governance model as an AI multi-agent architecture. Twelve specialized agents form a checks-and-balances pipeline: Crown Prince (triage) → Zhongshu (planning) → Menxia (review/veto) → Shangshu (dispatch) → Six Ministries (parallel execution). Built on OpenClaw, it provides a real-time React kanban dashboard, full audit trails, and per-agent LLM configuration.

来自ara.so的Skill — 2026每日技能合集。
Edict将有着1400年历史的唐代治理模型实现为AI多Agent架构。12个专业Agent组成一套相互制衡的工作流程:太子(任务分流)→ 中书省(规划)→ 门下省(审核/否决)→ 尚书省(分派)→ 六部(并行执行)。该系统基于OpenClaw构建,提供实时React看板仪表盘、完整审计追踪功能以及针对单个Agent的LLM配置项。

Architecture Overview

架构概述

You (Emperor) → taizi (triage) → zhongshu (plan) → menxia (review/veto)
             → shangshu (dispatch) → [hubu|libu|bingbu|xingbu|gongbu|libu2] (execute)
             → memorial (result archived)
Key differentiator vs CrewAI/AutoGen: Menxia (门下省) is a mandatory quality gate — it can veto and force rework before tasks reach executors.

你(皇帝)→ taizi(太子,任务分流)→ zhongshu(中书省,规划)→ menxia(门下省,审核/否决)
             → shangshu(尚书省,分派)→ [hubu|libu|bingbu|xingbu|gongbu|libu2](执行)
             → memorial(结果存档)
与CrewAI/AutoGen的核心区别:门下省是强制质量关卡——在任务到达执行环节前,它可以否决任务并要求重新修改。

Prerequisites

前置条件

  • OpenClaw installed and running
  • Python 3.9+
  • Node.js 18+ (for React dashboard build)
  • macOS or Linux

  • 已安装并运行OpenClaw
  • Python 3.9+
  • Node.js 18+(用于React仪表盘构建)
  • macOS或Linux系统

Installation

安装步骤

Quick Demo (Docker — no OpenClaw needed)

快速演示(Docker环境 — 无需OpenClaw)

bash
undefined
bash
undefined

x86/amd64 (Ubuntu, WSL2)

x86/amd64架构(Ubuntu、WSL2)

docker run --platform linux/amd64 -p 7891:7891 cft0808/sansheng-demo
docker run --platform linux/amd64 -p 7891:7891 cft0808/sansheng-demo

Apple Silicon / ARM

Apple Silicon / ARM架构

docker run -p 7891:7891 cft0808/sansheng-demo
docker run -p 7891:7891 cft0808/sansheng-demo

Or with docker-compose (platform already set)

或使用docker-compose(已配置平台信息)

docker compose up

Open http://localhost:7891
docker compose up

打开 http://localhost:7891

Full Installation

完整安装

bash
git clone https://github.com/cft0808/edict.git
cd edict
chmod +x install.sh && ./install.sh
The install script automatically:
  • Creates all 12 agent workspaces (taizi, zhongshu, menxia, shangshu, hubu, libu, bingbu, xingbu, gongbu, libu2, zaochao, legacy-compat)
  • Writes SOUL.md role definitions to each agent workspace
  • Registers agents and permission matrix in
    openclaw.json
  • Symlinks shared data directories across all agent workspaces
  • Sets
    sessions.visibility all
    for inter-agent message routing
  • Syncs API keys across all agents
  • Builds React frontend
  • Initializes data directory and syncs official stats
bash
git clone https://github.com/cft0808/edict.git
cd edict
chmod +x install.sh && ./install.sh
安装脚本将自动完成以下操作:
  • 创建全部12个Agent工作区(taizi、zhongshu、menxia、shangshu、hubu、libu、bingbu、xingbu、gongbu、libu2、zaochao、legacy-compat)
  • 为每个Agent工作区写入SOUL.md角色定义文件
  • openclaw.json
    中注册Agent并配置权限矩阵
  • 在所有Agent工作区之间创建共享数据目录的符号链接
  • 设置
    sessions.visibility all
    以实现Agent间消息路由
  • 为所有Agent同步API密钥
  • 构建React前端
  • 初始化数据目录并同步官方统计数据

First-time API Key Setup

首次API密钥配置

bash
undefined
bash
undefined

Configure API key on first agent

在第一个Agent上配置API密钥

openclaw agents add taizi
openclaw agents add taizi

Then re-run install to propagate to all agents

然后重新运行安装脚本以同步到所有Agent

./install.sh

---
./install.sh

---

Running the System

运行系统

bash
undefined
bash
undefined

Terminal 1: Data refresh loop (keeps kanban data current)

终端1:数据刷新循环(保持看板数据实时更新)

bash scripts/run_loop.sh
bash scripts/run_loop.sh

Terminal 2: Dashboard server

终端2:仪表盘服务器

python3 dashboard/server.py
python3 dashboard/server.py

Open dashboard

打开仪表盘

Key Commands

核心命令

OpenClaw Agent Management

OpenClaw Agent管理

bash
undefined
bash
undefined

List all registered agents

列出所有已注册的Agent

openclaw agents list
openclaw agents list

Add/configure an agent

添加/配置Agent

openclaw agents add <agent-name>
openclaw agents add <agent-name>

Check agent status

检查Agent状态

openclaw agents status
openclaw agents status

Restart gateway (required after config changes)

重启网关(配置变更后需执行)

openclaw gateway restart
openclaw gateway restart

Send a message/edict to the system

向系统发送消息/指令

openclaw send taizi "帮我分析一下竞争对手的产品策略"
undefined
openclaw send taizi "帮我分析一下竞争对手的产品策略"
undefined

Dashboard Server

仪表盘服务器

python
undefined
python
undefined

dashboard/server.py — serves on port 7891

dashboard/server.py — 监听7891端口

Built-in: React frontend + REST API + WebSocket updates

内置功能:React前端 + REST API + WebSocket实时更新

python3 dashboard/server.py
python3 dashboard/server.py

Custom port

自定义端口

PORT=8080 python3 dashboard/server.py
undefined
PORT=8080 python3 dashboard/server.py
undefined

Data Scripts

数据脚本

bash
undefined
bash
undefined

Sync official (agent) statistics

同步官方(Agent)统计数据

python3 scripts/sync_officials.py
python3 scripts/sync_officials.py

Update kanban task states

更新看板任务状态

python3 scripts/kanban_update.py
python3 scripts/kanban_update.py

Run news aggregation

运行新闻聚合

python3 scripts/fetch_news.py
python3 scripts/fetch_news.py

Full refresh loop (runs all scripts in sequence)

全量刷新循环(按顺序执行所有脚本)

bash scripts/run_loop.sh

---
bash scripts/run_loop.sh

---

Configuration

配置说明

Agent Model Configuration (
openclaw.json
)

Agent模型配置(
openclaw.json

json
{
  "agents": {
    "taizi": {
      "model": "claude-3-5-sonnet-20241022",
      "workspace": "~/.openclaw/workspaces/taizi"
    },
    "zhongshu": {
      "model": "gpt-4o",
      "workspace": "~/.openclaw/workspaces/zhongshu"
    },
    "menxia": {
      "model": "claude-3-5-sonnet-20241022",
      "workspace": "~/.openclaw/workspaces/menxia"
    },
    "shangshu": {
      "model": "gpt-4o-mini",
      "workspace": "~/.openclaw/workspaces/shangshu"
    }
  },
  "gateway": {
    "port": 7891,
    "sessions": {
      "visibility": "all"
    }
  }
}
json
{
  "agents": {
    "taizi": {
      "model": "claude-3-5-sonnet-20241022",
      "workspace": "~/.openclaw/workspaces/taizi"
    },
    "zhongshu": {
      "model": "gpt-4o",
      "workspace": "~/.openclaw/workspaces/zhongshu"
    },
    "menxia": {
      "model": "claude-3-5-sonnet-20241022",
      "workspace": "~/.openclaw/workspaces/menxia"
    },
    "shangshu": {
      "model": "gpt-4o-mini",
      "workspace": "~/.openclaw/workspaces/shangshu"
    }
  },
  "gateway": {
    "port": 7891,
    "sessions": {
      "visibility": "all"
    }
  }
}

Per-Agent Model Hot-Switching (via Dashboard)

单个Agent模型热切换(通过仪表盘)

Navigate to ⚙️ Models panel → select agent → choose LLM → Apply. Gateway restarts automatically (~5 seconds).
导航至**⚙️ Models**面板 → 选择Agent → 选择LLM → 应用。网关将自动重启(约5秒)。

Environment Variables

环境变量

bash
undefined
bash
undefined

API keys (set before running install.sh or openclaw)

API密钥(在运行install.sh或openclaw前设置)

export ANTHROPIC_API_KEY="sk-ant-..." export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..." export OPENAI_API_KEY="sk-..."

Optional: Feishu/Lark webhook for notifications

可选:飞书/Lark机器人通知Webhook

export FEISHU_WEBHOOK_URL="https://open.feishu.cn/open-apis/bot/v2/hook/..."
export FEISHU_WEBHOOK_URL="https://open.feishu.cn/open-apis/bot/v2/hook/..."

Optional: news aggregation

可选:新闻聚合API密钥

export NEWS_API_KEY="..."
export NEWS_API_KEY="..."

Dashboard port override

仪表盘端口覆盖

export DASHBOARD_PORT=7891

---
export DASHBOARD_PORT=7891

---

Agent Roles Reference

Agent角色参考

AgentRoleResponsibility
taizi
太子 Crown PrinceTriage: chat → auto-reply, edicts → create task
zhongshu
中书省Planning: decompose edict into subtasks
menxia
门下省Review/Veto: quality gate, can reject and force rework
shangshu
尚书省Dispatch: assign subtasks to ministries
hubu
户部 Ministry of RevenueFinance, data analysis tasks
libu
礼部 Ministry of RitesCommunication, documentation tasks
bingbu
兵部 Ministry of WarStrategy, security tasks
xingbu
刑部 Ministry of JusticeReview, compliance tasks
gongbu
工部 Ministry of WorksEngineering, technical tasks
libu2
吏部 Ministry of PersonnelHR, agent management tasks
zaochao
早朝官Morning briefing aggregator
Agent角色职责
taizi
太子 Crown Prince任务分流:聊天消息→自动回复,指令→创建任务
zhongshu
中书省任务规划:将指令拆解为子任务
menxia
门下省审核/否决:质量关卡,可拒绝任务并要求返工
shangshu
尚书省任务分派:将子任务分配至对应六部
hubu
户部 Ministry of Revenue财务、数据分析类任务
libu
礼部 Ministry of Rites沟通、文档类任务
bingbu
兵部 Ministry of War战略、安全类任务
xingbu
刑部 Ministry of Justice审核、合规类任务
gongbu
工部 Ministry of Works工程、技术类任务
libu2
吏部 Ministry of Personnel人力资源、Agent管理类任务
zaochao
早朝官早间简报聚合

Permission Matrix (who can message whom)

权限矩阵(Agent间消息发送规则)

python
undefined
python
undefined

Defined in openclaw.json — enforced by gateway

定义在openclaw.json中 — 由网关强制执行

PERMISSIONS = { "taizi": ["zhongshu"], "zhongshu": ["menxia"], "menxia": ["zhongshu", "shangshu"], # can veto back to zhongshu "shangshu": ["hubu", "libu", "bingbu", "xingbu", "gongbu", "libu2"], # ministries report back up the chain "hubu": ["shangshu"], "libu": ["shangshu"], "bingbu": ["shangshu"], "xingbu": ["shangshu"], "gongbu": ["shangshu"], "libu2": ["shangshu"], }

---
PERMISSIONS = { "taizi": ["zhongshu"], "zhongshu": ["menxia"], "menxia": ["zhongshu", "shangshu"], # 可否决并退回至中书省 "shangshu": ["hubu", "libu", "bingbu", "xingbu", "gongbu", "libu2"], # 六部向上汇报结果 "hubu": ["shangshu"], "libu": ["shangshu"], "bingbu": ["shangshu"], "xingbu": ["shangshu"], "gongbu": ["shangshu"], "libu2": ["shangshu"], }

---

Task State Machine

任务状态机

python
undefined
python
undefined

scripts/kanban_update.py enforces valid transitions

scripts/kanban_update.py 强制执行状态转换规则

VALID_TRANSITIONS = { "pending": ["planning"], "planning": ["reviewing", "pending"], # zhongshu → menxia "reviewing": ["dispatching", "planning"], # menxia approve or veto "dispatching": ["executing"], "executing": ["completed", "failed"], "completed": [], "failed": ["pending"], # retry }
VALID_TRANSITIONS = { "pending": ["planning"], "planning": ["reviewing", "pending"], # 中书省→门下省 "reviewing": ["dispatching", "planning"], # 门下省批准或否决返工 "dispatching": ["executing"], "executing": ["completed", "failed"], "completed": [], "failed": ["pending"], # 重试 }

Invalid transitions are rejected — no silent state corruption

无效的状态转换将被拒绝 — 不会出现静默状态损坏


---

---

Real Code Examples

实际代码示例

Send an Edict Programmatically

程序化发送指令

python
import subprocess
import json

def send_edict(message: str, agent: str = "taizi") -> dict:
    """Send an edict to the Crown Prince for triage."""
    result = subprocess.run(
        ["openclaw", "send", agent, message],
        capture_output=True,
        text=True
    )
    return {"stdout": result.stdout, "returncode": result.returncode}
python
import subprocess
import json

def send_edict(message: str, agent: str = "taizi") -> dict:
    """向太子Agent发送指令进行任务分流。"""
    result = subprocess.run(
        ["openclaw", "send", agent, message],
        capture_output=True,
        text=True
    )
    return {"stdout": result.stdout, "returncode": result.returncode}

Example edicts

示例指令

send_edict("分析本季度用户增长数据,找出关键驱动因素") send_edict("起草一份关于产品路线图的对外公告") send_edict("审查现有代码库的安全漏洞")
undefined
send_edict("分析本季度用户增长数据,找出关键驱动因素") send_edict("起草一份关于产品路线图的对外公告") send_edict("审查现有代码库的安全漏洞")
undefined

Read Kanban State

读取看板状态

python
import json
from pathlib import Path

def get_kanban_tasks(data_dir: str = "data") -> list[dict]:
    """Read current kanban task state."""
    tasks_file = Path(data_dir) / "tasks.json"
    if not tasks_file.exists():
        return []
    with open(tasks_file) as f:
        return json.load(f)

def get_tasks_by_status(status: str) -> list[dict]:
    tasks = get_kanban_tasks()
    return [t for t in tasks if t.get("status") == status]
python
import json
from pathlib import Path

def get_kanban_tasks(data_dir: str = "data") -> list[dict]:
    """读取当前看板任务状态。"""
    tasks_file = Path(data_dir) / "tasks.json"
    if not tasks_file.exists():
        return []
    with open(tasks_file) as f:
        return json.load(f)

def get_tasks_by_status(status: str) -> list[dict]:
    tasks = get_kanban_tasks()
    return [t for t in tasks if t.get("status") == status]

Usage

使用示例

executing = get_tasks_by_status("executing") completed = get_tasks_by_status("completed") print(f"In progress: {len(executing)}, Done: {len(completed)}")
undefined
executing = get_tasks_by_status("executing") completed = get_tasks_by_status("completed") print(f"进行中任务:{len(executing)},已完成任务:{len(completed)}")
undefined

Update Task Status (with validation)

更新任务状态(含验证)

python
import json
from pathlib import Path
from datetime import datetime, timezone

VALID_TRANSITIONS = {
    "pending":     ["planning"],
    "planning":    ["reviewing", "pending"],
    "reviewing":   ["dispatching", "planning"],
    "dispatching": ["executing"],
    "executing":   ["completed", "failed"],
    "completed":   [],
    "failed":      ["pending"],
}

def update_task_status(task_id: str, new_status: str, data_dir: str = "data") -> bool:
    """Update task status with state machine validation."""
    tasks_file = Path(data_dir) / "tasks.json"
    tasks = json.loads(tasks_file.read_text())

    task = next((t for t in tasks if t["id"] == task_id), None)
    if not task:
        raise ValueError(f"Task {task_id} not found")

    current = task["status"]
    allowed = VALID_TRANSITIONS.get(current, [])

    if new_status not in allowed:
        raise ValueError(
            f"Invalid transition: {current}{new_status}. "
            f"Allowed: {allowed}"
        )

    task["status"] = new_status
    task["updated_at"] = datetime.now(timezone.utc).isoformat()
    task.setdefault("history", []).append({
        "from": current,
        "to": new_status,
        "timestamp": task["updated_at"]
    })

    tasks_file.write_text(json.dumps(tasks, ensure_ascii=False, indent=2))
    return True
python
import json
from pathlib import Path
from datetime import datetime, timezone

VALID_TRANSITIONS = {
    "pending":     ["planning"],
    "planning":    ["reviewing", "pending"],
    "reviewing":   ["dispatching", "planning"],
    "dispatching": ["executing"],
    "executing":   ["completed", "failed"],
    "completed":   [],
    "failed":      ["pending"],
}

def update_task_status(task_id: str, new_status: str, data_dir: str = "data") -> bool:
    """通过状态机验证更新任务状态。"""
    tasks_file = Path(data_dir) / "tasks.json"
    tasks = json.loads(tasks_file.read_text())

    task = next((t for t in tasks if t["id"] == task_id), None)
    if not task:
        raise ValueError(f"未找到任务 {task_id}")

    current = task["status"]
    allowed = VALID_TRANSITIONS.get(current, [])

    if new_status not in allowed:
        raise ValueError(
            f"无效状态转换:{current}{new_status}。 "
            f"允许的转换:{allowed}"
        )

    task["status"] = new_status
    task["updated_at"] = datetime.now(timezone.utc).isoformat()
    task.setdefault("history", []).append({
        "from": current,
        "to": new_status,
        "timestamp": task["updated_at"]
    })

    tasks_file.write_text(json.dumps(tasks, ensure_ascii=False, indent=2))
    return True

Dashboard REST API Client

仪表盘REST API客户端

python
import urllib.request
import json

BASE_URL = "http://127.0.0.1:7891/api"

def api_get(endpoint: str) -> dict:
    with urllib.request.urlopen(f"{BASE_URL}{endpoint}") as resp:
        return json.loads(resp.read())

def api_post(endpoint: str, data: dict) -> dict:
    payload = json.dumps(data).encode()
    req = urllib.request.Request(
        f"{BASE_URL}{endpoint}",
        data=payload,
        headers={"Content-Type": "application/json"},
        method="POST"
    )
    with urllib.request.urlopen(req) as resp:
        return json.loads(resp.read())
python
import urllib.request
import json

BASE_URL = "http://127.0.0.1:7891/api"

def api_get(endpoint: str) -> dict:
    with urllib.request.urlopen(f"{BASE_URL}{endpoint}") as resp:
        return json.loads(resp.read())

def api_post(endpoint: str, data: dict) -> dict:
    payload = json.dumps(data).encode()
    req = urllib.request.Request(
        f"{BASE_URL}{endpoint}",
        data=payload,
        headers={"Content-Type": "application/json"},
        method="POST"
    )
    with urllib.request.urlopen(req) as resp:
        return json.loads(resp.read())

Read dashboard data

读取仪表盘数据

tasks = api_get("/tasks") agents = api_get("/agents") sessions = api_get("/sessions") news = api_get("/news")
tasks = api_get("/tasks") agents = api_get("/agents") sessions = api_get("/sessions") news = api_get("/news")

Trigger task action

触发任务操作

api_post("/tasks/pause", {"task_id": "task-123"}) api_post("/tasks/cancel", {"task_id": "task-123"}) api_post("/tasks/resume", {"task_id": "task-123"})
api_post("/tasks/pause", {"task_id": "task-123"}) api_post("/tasks/cancel", {"task_id": "task-123"}) api_post("/tasks/resume", {"task_id": "task-123"})

Switch model for an agent

切换Agent模型

api_post("/agents/model", { "agent": "zhongshu", "model": "gpt-4o-2024-11-20" })
undefined
api_post("/agents/model", { "agent": "zhongshu", "model": "gpt-4o-2024-11-20" })
undefined

Agent Health Check

Agent健康检查

python
import json
from pathlib import Path
from datetime import datetime, timezone, timedelta

def check_agent_health(data_dir: str = "data") -> dict[str, str]:
    """
    Returns health status for each agent.
    🟢 active   = heartbeat within 2 min
    🟡 stale    = heartbeat 2-10 min ago
    🔴 offline  = heartbeat >10 min ago or missing
    """
    heartbeats_file = Path(data_dir) / "heartbeats.json"
    if not heartbeats_file.exists():
        return {}

    heartbeats = json.loads(heartbeats_file.read_text())
    now = datetime.now(timezone.utc)
    status = {}

    for agent, last_beat in heartbeats.items():
        last = datetime.fromisoformat(last_beat)
        delta = now - last
        if delta < timedelta(minutes=2):
            status[agent] = "🟢 active"
        elif delta < timedelta(minutes=10):
            status[agent] = "🟡 stale"
        else:
            status[agent] = "🔴 offline"

    return status
python
import json
from pathlib import Path
from datetime import datetime, timezone, timedelta

def check_agent_health(data_dir: str = "data") -> dict[str, str]:
    """
    返回每个Agent的健康状态。
    🟢 active   = 2分钟内有心跳
    🟡 stale    = 心跳在2-10分钟前
    🔴 offline  = 心跳超过10分钟或缺失
    """
    heartbeats_file = Path(data_dir) / "heartbeats.json"
    if not heartbeats_file.exists():
        return {}

    heartbeats = json.loads(heartbeats_file.read_text())
    now = datetime.now(timezone.utc)
    status = {}

    for agent, last_beat in heartbeats.items():
        last = datetime.fromisoformat(last_beat)
        delta = now - last
        if delta < timedelta(minutes=2):
            status[agent] = "🟢 active"
        elif delta < timedelta(minutes=10):
            status[agent] = "🟡 stale"
        else:
            status[agent] = "🔴 offline"

    return status

Usage

使用示例

health = check_agent_health() for agent, s in health.items(): print(f"{agent:12} {s}")
undefined
health = check_agent_health() for agent, s in health.items(): print(f"{agent:12} {s}")
undefined

Custom SOUL.md (Agent Personality)

自定义SOUL.md(Agent个性)

markdown
<!-- ~/.openclaw/workspaces/gongbu/SOUL.md -->
markdown
<!-- ~/.openclaw/workspaces/gongbu/SOUL.md -->

工部尚书 · Minister of Works

工部尚书 · Minister of Works

Role

角色定位

You are the Minister of Works (工部). You handle all technical, engineering, and infrastructure tasks assigned by Shangshu Province.
你是工部尚书,负责处理尚书省分配的所有技术、工程和基础设施类任务。

Rules

规则

  1. Always break technical tasks into concrete, verifiable steps
  2. Return structured results: { "status": "...", "output": "...", "artifacts": [] }
  3. Flag blockers immediately — do not silently fail
  4. Estimate complexity: S/M/L/XL before starting
  1. 始终将技术任务拆解为具体、可验证的步骤
  2. 返回结构化结果:{ "status": "...", "output": "...", "artifacts": [] }
  3. 立即标记阻塞问题 — 不要静默失败
  4. 开始任务前评估复杂度:S/M/L/XL

Output Format

输出格式

Always respond with valid JSON. Include a
summary
field ≤ 50 chars for kanban display.

---
始终返回有效的JSON。包含一个长度≤50字符的
summary
字段,用于看板展示。

---

Dashboard Panels

仪表盘面板

PanelURL FragmentKey Features
Kanban
#kanban
Task columns, heartbeat badges, filter/search, pause/cancel/resume
Monitor
#monitor
Agent health cards, task distribution charts
Memorials
#memorials
Completed task archive, 5-stage timeline, Markdown export
Templates
#templates
9 preset edict templates with parameter forms
Officials
#officials
Token usage ranking, activity stats
News
#news
Daily tech/finance briefing, Feishu push
Models
#models
Per-agent LLM switcher (hot reload ~5s)
Skills
#skills
View/add agent skills
Sessions
#sessions
Live OC-* session monitor
Court
#court
Multi-agent discussion around a topic

面板URL片段核心功能
看板
#kanban
任务列、心跳徽章、筛选/搜索、暂停/取消/恢复任务
监控
#monitor
Agent健康卡片、任务分布图表
奏折
#memorials
已完成任务存档、5阶段时间线、Markdown导出
模板
#templates
9个预设指令模板及参数表单
官员统计
#officials
Token使用排名、活跃度统计
新闻
#news
每日科技/财经简报、飞书推送
模型管理
#models
单个Agent LLM切换器(热重载约5秒)
技能管理
#skills
查看/添加Agent技能
会话监控
#sessions
实时OC-*会话监控
朝议
#court
围绕特定主题的多Agent讨论

Common Patterns

常见使用模式

Pattern 1: Parallel Ministry Execution

模式1:六部并行执行

python
undefined
python
undefined

Shangshu dispatches to multiple ministries simultaneously

尚书省同时将任务分派至多个六部

Each ministry works independently; shangshu aggregates results

每个六部独立工作;尚书省汇总结果

edict = "竞品分析:研究TOP3竞争对手的产品、定价、市场策略"
edict = "竞品分析:研究TOP3竞争对手的产品、定价、市场策略"

Zhongshu splits into subtasks:

中书省拆解为子任务:

hubu → pricing analysis

hubu → 定价分析

libu → market communication analysis

libu → 市场传播分析

bingbu → competitive strategy analysis

bingbu → 竞争策略分析

gongbu → technical feature comparison

gongbu → 技术特性对比

All execute in parallel; shangshu waits for all 4, then aggregates

所有子任务并行执行;尚书省等待全部4个结果后汇总

undefined
undefined

Pattern 2: Menxia Veto Loop

模式2:门下省否决循环

python
undefined
python
undefined

If menxia rejects zhongshu's plan:

如果门下省否决中书省的计划:

menxia → zhongshu: "子任务拆解不完整,缺少风险评估维度,请补充"

menxia → zhongshu: "子任务拆解不完整,缺少风险评估维度,请补充"

zhongshu revises and resubmits to menxia

中书省修改后重新提交给门下省

Loop continues until menxia approves

循环直至门下省批准

Max iterations configurable in openclaw.json: "max_review_cycles": 3

最大迭代次数可在openclaw.json中配置:"max_review_cycles": 3

undefined
undefined

Pattern 3: News Aggregation + Push

模式3:新闻聚合+推送

python
undefined
python
undefined

scripts/fetch_news.py → data/news.json → dashboard #news panel

scripts/fetch_news.py → data/news.json → 仪表盘#news面板

Optional Feishu push:

可选飞书推送:

import os, json, urllib.request
def push_to_feishu(summary: str): webhook = os.environ["FEISHU_WEBHOOK_URL"] payload = json.dumps({ "msg_type": "text", "content": {"text": f"📰 天下要闻\n{summary}"} }).encode() req = urllib.request.Request( webhook, data=payload, headers={"Content-Type": "application/json"} ) urllib.request.urlopen(req)

---
import os, json, urllib.request
def push_to_feishu(summary: str): webhook = os.environ["FEISHU_WEBHOOK_URL"] payload = json.dumps({ "msg_type": "text", "content": {"text": f"📰 天下要闻\n{summary}"} }).encode() req = urllib.request.Request( webhook, data=payload, headers={"Content-Type": "application/json"} ) urllib.request.urlopen(req)

---

Troubleshooting

故障排查

exec format error
in Docker

Docker中出现
exec format error

bash
undefined
bash
undefined

Force platform on x86/amd64

在x86/amd64架构上强制指定平台

docker run --platform linux/amd64 -p 7891:7891 cft0808/sansheng-demo
undefined
docker run --platform linux/amd64 -p 7891:7891 cft0808/sansheng-demo
undefined

Agents not receiving messages

Agent无法接收消息

bash
undefined
bash
undefined

Ensure sessions visibility is set to "all"

确保会话可见性设置为"all"

openclaw config set sessions.visibility all openclaw gateway restart
openclaw config set sessions.visibility all openclaw gateway restart

Or re-run install.sh — it sets this automatically

或重新运行install.sh — 脚本会自动设置该配置

./install.sh
undefined
./install.sh
undefined

API key not propagated to all agents

API密钥未同步到所有Agent

bash
undefined
bash
undefined

Re-run install after configuring key on first agent

在第一个Agent上配置密钥后重新运行安装脚本

openclaw agents add taizi # configure key here ./install.sh # propagates to all agents
undefined
openclaw agents add taizi # 在此处配置密钥 ./install.sh # 同步到所有Agent
undefined

Dashboard shows stale data

仪表盘显示陈旧数据

bash
undefined
bash
undefined

Ensure run_loop.sh is running

确保run_loop.sh正在运行

bash scripts/run_loop.sh
bash scripts/run_loop.sh

Or trigger manual refresh

或触发手动刷新

python3 scripts/sync_officials.py python3 scripts/kanban_update.py
undefined
python3 scripts/sync_officials.py python3 scripts/kanban_update.py
undefined

React frontend not built

React前端未构建

bash
undefined
bash
undefined

Requires Node.js 18+

需要Node.js 18+

cd dashboard/frontend npm install && npm run build
cd dashboard/frontend npm install && npm run build

server.py will then serve the built assets

之后server.py将提供构建后的静态资源

undefined
undefined

Invalid state transition error

出现无效状态转换错误

python
undefined
python
undefined

kanban_update.py enforces the state machine

kanban_update.py强制执行状态机规则

Check current status before updating:

更新前检查当前状态:

tasks = get_kanban_tasks() task = next(t for t in tasks if t["id"] == "your-task-id") print(f"Current: {task['status']}") print(f"Allowed next: {VALID_TRANSITIONS[task['status']]}")
undefined
tasks = get_kanban_tasks() task = next(t for t in tasks if t["id"] == "your-task-id") print(f"当前状态:{task['status']}") print(f"允许的下一个状态:{VALID_TRANSITIONS[task['status']]}")
undefined

Gateway restart after model change

模型变更后重启网关

bash
undefined
bash
undefined

After editing openclaw.json models section

编辑openclaw.json的models部分后

openclaw gateway restart
openclaw gateway restart

Wait ~5 seconds for agents to reconnect

等待约5秒让Agent重新连接


---

---

Project Structure

项目结构

edict/
├── install.sh              # One-command setup
├── openclaw.json           # Agent registry + permissions + model config
├── scripts/
│   ├── run_loop.sh         # Continuous data refresh daemon
│   ├── kanban_update.py    # State machine enforcement
│   ├── sync_officials.py   # Agent stats aggregation
│   └── fetch_news.py       # News aggregation
├── dashboard/
│   ├── server.py           # stdlib-only HTTP + WebSocket server (port 7891)
│   ├── dashboard.html      # Fallback single-file dashboard
│   └── frontend/           # React 18 source (builds to server.py assets)
├── data/                   # Shared data (symlinked into all workspaces)
│   ├── tasks.json
│   ├── heartbeats.json
│   ├── news.json
│   └── officials.json
├── workspaces/             # Per-agent workspace roots
│   ├── taizi/SOUL.md
│   ├── zhongshu/SOUL.md
│   └── ...
└── docs/
    ├── task-dispatch-architecture.md
    └── getting-started.md
edict/
├── install.sh              # 一键安装脚本
├── openclaw.json           # Agent注册表 + 权限配置 + 模型配置
├── scripts/
│   ├── run_loop.sh         # 持续数据刷新守护进程
│   ├── kanban_update.py    # 状态机强制执行脚本
│   ├── sync_officials.py   # Agent统计数据聚合脚本
│   └── fetch_news.py       # 新闻聚合脚本
├── dashboard/
│   ├── server.py           # 仅依赖标准库的HTTP + WebSocket服务器(端口7891)
│   ├── dashboard.html      # 备用单文件仪表盘
│   └── frontend/           # React 18源码(构建后由server.py提供服务)
├── data/                   # 共享数据目录(符号链接至所有工作区)
│   ├── tasks.json
│   ├── heartbeats.json
│   ├── news.json
│   └── officials.json
├── workspaces/             # 单个Agent工作区根目录
│   ├── taizi/SOUL.md
│   ├── zhongshu/SOUL.md
│   └── ...
└── docs/
    ├── task-dispatch-architecture.md
    └── getting-started.md