Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Install and use the Edict (三省六部) multi-agent orchestration system with 12 specialized AI agents, real-time kanban dashboard, and audit trails
.claude/skills/leoyeai-edict-multi-agent-orchestration/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-08 | ✗→✓ | ▲ Improved | 259% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 92% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 169% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 156% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 276% | 0% |
> 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.
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.
bash# x86/amd64 (Ubuntu, WSL2) docker run --platform linux/amd64 -p 7891:7891 cft0808/sansheng-demo # Apple Silicon / ARM docker run -p 7891:7891 cft0808/sansheng-demo # Or with docker-compose (platform already set) docker compose up
Open http://localhost:7891
bashgit clone https://github.com/cft0808/edict.git cd edict chmod +x install.sh && ./install.sh
The install script automatically:
openclaw.jsonsessions.visibility all for inter-agent message routingbash# Configure API key on first agent openclaw agents add taizi # Then re-run install to propagate to all agents ./install.sh
bash# Terminal 1: Data refresh loop (keeps kanban data current) bash scripts/run_loop.sh # Terminal 2: Dashboard server python3 dashboard/server.py # Open dashboard open http://127.0.0.1:7891
bash# List all registered agents openclaw agents list # Add/configure an agent openclaw agents add <agent-name> # Check agent status openclaw agents status # Restart gateway (required after config changes) openclaw gateway restart # Send a message/edict to the system openclaw send taizi "帮我分析一下竞争对手的产品策略"
python# dashboard/server.py — serves on port 7891 # Built-in: React frontend + REST API + WebSocket updates python3 dashboard/server.py # Custom port PORT=8080 python3 dashboard/server.py
bash# Sync official (agent) statistics python3 scripts/sync_officials.py # Update kanban task states python3 scripts/kanban_update.py # Run news aggregation python3 scripts/fetch_news.py # Full refresh loop (runs all scripts in sequence) bash scripts/run_loop.sh
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" } } }
Navigate to ⚙️ Models panel → select agent → choose LLM → Apply. Gateway restarts automatically (~5 seconds).
bash# API keys (set before running install.sh or openclaw) export ANTHROPIC_API_KEY="sk-ant-..." export OPENAI_API_KEY="sk-..." # Optional: Feishu/Lark webhook for notifications export FEISHU_WEBHOOK_URL="https://open.feishu.cn/open-apis/bot/v2/hook/..." # Optional: news aggregation export NEWS_API_KEY="..." # Dashboard port override export DASHBOARD_PORT=7891
| Agent | Role | Responsibility | |-------|------|----------------| | taizi | 太子 Crown Prince | Triage: 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 Revenue | Finance, data analysis tasks | | libu | 礼部 Ministry of Rites | Communication, documentation tasks | | bingbu | 兵部 Ministry of War | Strategy, security tasks | | xingbu | 刑部 Ministry of Justice | Review, compliance tasks | | gongbu | 工部 Ministry of Works | Engineering, technical tasks | | libu2 | 吏部 Ministry of Personnel | HR, agent management tasks | | zaochao | 早朝官 | Morning briefing aggregator |
python# Defined in openclaw.json — enforced by gateway 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"], }
python# scripts/kanban_update.py enforces valid transitions 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 } # Invalid transitions are rejected — no silent state corruption
pythonimport 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} # Example edicts send_edict("分析本季度用户增长数据,找出关键驱动因素") send_edict("起草一份关于产品路线图的对外公告") send_edict("审查现有代码库的安全漏洞")
pythonimport 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] # Usage executing = get_tasks_by_status("executing") completed = get_tasks_by_status("completed") print(f"In progress: {len(executing)}, Done: {len(completed)}")
pythonimport 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
pythonimport 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") # 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"}) # Switch model for an agent api_post("/agents/model", { "agent": "zhongshu", "model": "gpt-4o-2024-11-20" })
pythonimport 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 # Usage health = check_agent_health() for agent, s in health.items(): print(f"{agent:12} {s}")
markdown<!-- ~/.openclaw/workspaces/gongbu/SOUL.md --> # 工部尚书 · 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 ## Output Format Always respond with valid JSON. Include a `summary` field ≤ 50 chars for kanban display.
| Panel | URL Fragment | Key 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 |
python# Shangshu dispatches to multiple ministries simultaneously # Each ministry works independently; shangshu aggregates results edict = "竞品分析:研究TOP3竞争对手的产品、定价、市场策略" # Zhongshu splits into subtasks: # hubu → pricing analysis # libu → market communication analysis # bingbu → competitive strategy analysis # gongbu → technical feature comparison # All execute in parallel; shangshu waits for all 4, then aggregates
python# If menxia rejects zhongshu's plan: # menxia → zhongshu: "子任务拆解不完整,缺少风险评估维度,请补充" # zhongshu revises and resubmits to menxia # Loop continues until menxia approves # Max iterations configurable in openclaw.json: "max_review_cycles": 3
python# scripts/fetch_news.py → data/news.json → dashboard #news panel # 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)
exec format error in Dockerbash# Force platform on x86/amd64 docker run --platform linux/amd64 -p 7891:7891 cft0808/sansheng-demo
bash# Ensure sessions visibility is set to "all" openclaw config set sessions.visibility all openclaw gateway restart # Or re-run install.sh — it sets this automatically ./install.sh
bash# Re-run install after configuring key on first agent openclaw agents add taizi # configure key here ./install.sh # propagates to all agents
bash# Ensure run_loop.sh is running bash scripts/run_loop.sh # Or trigger manual refresh python3 scripts/sync_officials.py python3 scripts/kanban_update.py
bash# Requires Node.js 18+ cd dashboard/frontend npm install && npm run build # server.py will then serve the built assets
python# kanban_update.py enforces the state machine # 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']]}")
bash# After editing openclaw.json models section openclaw gateway restart # Wait ~5 seconds for agents to reconnect
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| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-08 | fail→pass | 7,592 | 1,936 | -74% | 1 | 1 | 0% | 1,441 | 5,177 | +259% | 0 | 0 | — |
case-01 | fail→pass | 16,228 | 8,768 | -46% | 1 | 1 | 0% | 3,590 | 6,894 | +92% | 0 | 0 | — |
case-02 | fail→pass | 12,016 | 10,504 | -13% | 1 | 1 | 0% | 2,765 | 7,437 | +169% | 0 | 0 | — |
case-09 | fail→pass | 10,377 | 1,932 | -81% | 1 | 1 | 0% | 2,032 | 5,199 | +156% | 0 | 0 | — |
case-03 | fail→pass | 7,453 | 9,444 | +27% | 1 | 1 | 0% | 1,937 | 7,289 | +276% | 0 | 0 | — |
case-04 | fail→pass | 7,468 | 2,849 | -62% | 1 | 1 | 0% | 1,674 | 5,500 | +229% | 0 | 0 | — |
case-05 | fail→pass | 8,659 | 3,512 | -59% | 1 | 1 | 0% | 1,658 | 5,583 | +237% | 0 | 0 | — |
case-06 | fail→pass | 8,668 | 5,654 | -35% | 1 | 1 | 0% | 1,746 | 6,195 | +255% | 0 | 0 | — |
case-07 | fail→pass | 5,913 | 3,894 | -34% | 1 | 1 | 0% | 1,468 | 5,626 | +283% | 0 | 0 | — |
case-10 | fail→pass | 6,701 | 2,285 | -66% | 1 | 1 | 0% | 1,162 | 5,264 | +353% | 0 | 0 | — |
case-11 | pass→pass | 4,669 | 1,567 | -66% | 1 | 1 | 0% | 847 | 5,129 | +506% | 0 | 0 | — |
case-12 | fail→pass | 8,650 | 2,476 | -71% | 1 | 1 | 0% | 1,517 | 5,302 | +250% | 0 | 0 | — |
case-13 | fail→pass | 12,247 | 7,797 | -36% | 1 | 1 | 0% | 3,234 | 6,716 | +108% | 0 | 0 | — |
case-14 | fail→pass | 7,880 | 3,377 | -57% | 1 | 1 | 0% | 1,618 | 5,236 | +224% | 0 | 0 | — |
case-15 | pass→pass | 6,927 | 1,712 | -75% | 1 | 1 | 0% | 1,225 | 5,262 | +330% | 0 | 0 | — |
case-16 | fail→pass | 8,487 | 2,129 | -75% | 1 | 1 | 0% | 1,468 | 5,271 | +259% | 0 | 0 | — |
case-17 | fail→fail | 11,587 | 1,950 | -83% | 1 | 1 | 0% | 2,102 | 5,162 | +146% | 0 | 0 | — |
case-18 | fail→pass | 11,478 | 1,918 | -83% | 1 | 1 | 0% | 2,422 | 5,255 | +117% | 0 | 0 | — |
case-19 | pass→pass | 4,939 | 3,171 | -36% | 1 | 1 | 0% | 865 | 5,429 | +528% | 0 | 0 | — |
case-20 | pass→pass | 9,310 | 9,207 | -1% | 1 | 1 | 0% | 2,134 | 6,922 | +224% | 0 | 0 | — |
case-21 | pass→pass | 13,343 | 10,746 | -19% | 1 | 1 | 0% | 3,402 | 7,533 | +121% | 0 | 0 | — |
case-22 | pass→pass | 5,462 | 5,314 | -3% | 1 | 1 | 0% | 1,347 | 6,221 | +362% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +68 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.