Agent Company OS — 系统蓝图 + 开发 PRD
Agent Company OS — 系统蓝图 + 开发 PRD
版本:V1.0 | 状态:已定稿 | 基于
agent-company.md愿景转化为可实现规格
第一部分:系统蓝图(System Blueprint)
一、核心理念技术翻译
原文愿景:
"从'你在驱动系统'变成'系统在驱动任务'"
技术架构:
Human(发起者 / 观察者)
↓ 发任务(写 tasks/todo/*.md)
Hermes Core(公司大脑:身份、任务、状态、记忆、日志、交付物)
↓ 读状态
Orchestrator(调度中枢:扫描 → 分配 → 启动 → 监控 → 回收)
↓ 写信号文件 + 控制 tmux
tmux Session(运行容器:pane 常驻,承载 Agent Runner)
↓ 读取信号文件
Agent Runner(Claude Code:执行任务)
↓ 写文件系统
outbox/ + logs/(交付物 + 行为轨迹)
二、三层架构
┌──────────────────────────────────────────┐
│ Layer 1: 人类接口层 │
│ • 任务发起(hermes task create) │
│ • 结果验收(读 outbox/summary.md) │
│ • 状态观测(tmux attach / tree) │
└──────────────────────────────────────────┘
↓
┌──────────────────────────────────────────┐
│ Layer 2: 调度编排层 │
│ • Hermes Core(CLI、任务 CRUD、状态机) │
│ • Orchestrator(轮询、分配、监控、回收) │
└──────────────────────────────────────────┘
↓
┌──────────────────────────────────────────┐
│ Layer 3: 执行引擎层 │
│ • tmux Session/Pane(常驻容器) │
│ • Agent Runner(Claude Code) │
│ • 文件系统(tasks/ logs/ outbox/) │
└──────────────────────────────────────────┘
边界协议
| 模块 | 职责 | 不管什么 |
|---|---|---|
| Hermes Core | 身份、任务票、状态变迁、日志归档、交付物存储 | 不启动进程、不控制 tmux、不调度任务 |
| Orchestrator | 扫描 todo、分配合适 Agent、锁定任务、启动 Runner、监控心跳、回收结果 | 不写业务代码、不修改 outbox 内容 |
| tmux | 多 Agent 并行长驻、可观察、进程隔离 | 不理解业务逻辑 |
| Agent Runner | 读任务 → 执行 → 写日志 → 写 outbox → 发完成信号 | 不感知公司调度规则 |
三、数据模型
3.1 目录结构
agent-company/
├── hermes.py # CLI 入口(Hermes Core)
├── orchestrator.py # 调度器主程序
├── lib/
│ ├── __init__.py
│ ├── task.py # 任务 CRUD 和状态机
│ ├── agent.py # Agent 注册和运行时管理
│ ├── tmux_ctrl.py # tmux 控制封装
│ └── signals.py # Runner 信号文件机制
├── config/
│ ├── agents.yaml # Agent 注册表
│ └── company.yaml # 公司规则
├── runners/
│ └── claude_runner.md # Claude Code prompt 模板
├── company/
│ └── AGENT_WORK_RULES.md # Agent 行为规范
├── agents/
│ └── {agent_name}/
│ ├── profile.json # 身份定义(Hermes 管)
│ └── runtime.json # 运行时状态(Orchestrator 管)
├── tasks/
│ ├── todo/
│ ├── doing/
│ ├── blocked/
│ ├── review/
│ └── done/
├── memory/
│ └── {agent_name}/
├── logs/
│ └── {agent_name}/
│ └── YYYY-MM-DD.md
├── outbox/
│ └── {agent_name}/
│ └── {task_id}/
│ ├── summary.md
│ └── DONE
└── signals/ # Runner 信号文件(Orchestrator → Runner)
└── {agent_name}/
└── current_task.json
3.2 核心数据结构
Task 文件
路径:tasks/{state}/{task_id}.md
---
id: 01HW5T3M7Z9A2B3C4D5E6F7G8H
title: 开发知识库商品落地页
project: knowledge-shop
owner: laohuang
priority: P1
state: todo
created_at: 2026-04-26T10:00:00Z
---
## Goal
完成一个可上线的 Next.js 落地页,包含:
- 商品介绍区
- 价格展示
- 购买引导
## Context
- 项目路径:/home/projects/knowledge-shop
- 设计稿:docs/design/landing-v1.figma
- 技术栈:Next.js 15, Tailwind CSS, TypeScript任务锁定(独立 .lock 文件)
路径:tasks/{state}/{task_id}.lock
{
"task_id": "01HW5T3M7Z9A2B3C4D5E6F7G8H",
"locked_by": "orchestrator",
"locked_at": "2026-04-26T13:35:00Z",
"assigned_agent": "laohuang",
"tmux_pane": "agent_laohuang",
"signal_file": "signals/laohuang/current_task.json"
}设计决策:锁定信息存在独立 .lock 文件,不修改原始 .md 理由:保持原始任务文件纯净,方便 Human 阅读;分离关注点
Agent Profile
路径:agents/{agent_name}/profile.json
{
"name": "laohuang",
"role": "fullstack_engineer",
"description": "资深全栈工程师,负责代码开发和系统架构",
"capabilities": ["frontend", "backend", "devops"],
"preferred_engine": "claude-code",
"max_concurrent_tasks": 1,
"workspace_root": "/home/laohuang/projects"
}Runtime State
路径:agents/{agent_name}/runtime.json
{
"agent": "laohuang",
"engine": "claude-code",
"container": "tmux",
"tmux_session": "hermes",
"tmux_pane": "agent_laohuang",
"status": "idle",
"current_task_id": null,
"current_task_signal": null,
"last_heartbeat": "2026-04-26T13:30:00Z",
"task_history": []
}Runner 信号文件(Orchestrator → Runner)
路径:signals/{agent_name}/current_task.json
{
"task_id": "01HW5T3M7Z9A2B3C4D5E6F7G8H",
"task_file": "/path/to/tasks/doing/01HW5T3M7Z9A2B3C4D5E6F7G8H.md",
"workspace_root": "/home/laohuang/projects",
"project_path": "/home/laohuang/projects/knowledge-shop",
"company_rules": "/path/to/company/AGENT_WORK_RULES.md",
"memory_path": "/path/to/memory/laohuang",
"logs_path": "/path/to/logs/laohuang",
"outbox_path": "/path/to/outbox/laohuang/01HW5T3M7Z9A2B3C4D5E6F7G8H",
"assigned_at": "2026-04-26T13:35:00Z"
}设计决策:Orchestrator 与 Runner 之间通过信号文件通信,不依赖 tmux send-keys 理由:Claude Code 交互式运行,send-keys 无法可靠注入复杂上下文;文件信号可靠且可审计
Heartbeat(Runner → Orchestrator)
路径:agents/{agent_name}/heartbeat.json
{
"agent": "laohuang",
"task_id": "01HW5T3M7Z9A2B3C4D5E6F7G8H",
"status": "working",
"progress": "implementing hero section",
"started_at": "2026-04-26T13:35:00Z",
"updated_at": "2026-04-26T13:45:00Z"
}四、任务状态机
4.1 状态流转
[todo] ─pickup──→ [doing] ──done──→ [review]
↑ │ │
└──retry────────────┘ │
↓
[blocked] ←max_retry exceeded [done]
4.2 流转规则
| 当前状态 | 触发条件 | 目标状态 | 操作者 |
|---|---|---|---|
| todo | Orchestrator pickup | doing | Orchestrator |
| doing | Runner 写 DONE 信号 | review | Orchestrator(检测到 DONE 后执行) |
| doing | 超时(30min)/ Runner 报错 | blocked | Orchestrator |
| doing | Runner 主动放弃 | blocked | Orchestrator |
| blocked | Human 重试 | todo | Human(hermes task move) |
| blocked | max_retry 达到(默认 3) | done (failed) | Orchestrator |
| review | Human 验收通过 | done | Human |
| review | Human 打回重做 | todo | Human |
4.3 状态变更原子性
所有状态变更通过 task.move() 原子函数:
def move_task(task_id: str, from_state: str, to_state: str) -> None:
# 1. 验证当前状态
# 2. 读取原始文件
# 3. 更新 state 字段
# 4. 写回目标目录
# 5. 删除源文件
# 6. 记录日志
# 若任何步骤失败则 rollback五、Orchestrator 调度逻辑
5.1 主循环
class Orchestrator:
def run(self):
while self.running:
self.sync_agent_status() # 读取所有 runtime.json
self.process_blocked_tasks() # 检查 blocked 任务是否可重试
self.scan_and_assign() # 扫描 todo,分配给 idle agent
self.monitor_task_progress() # 检测 DONE 信号 / 超时
self.sleep(self.poll_interval)5.2 任务分配算法
优先级:
1. owner 精确匹配(task.owner == agent.name)
2. agent status == "idle"
3. agent.current_task_id == null
4. FIFO(任务创建时间早的优先)
5. priority(P1 > P2 > P3)
5.3 分配流程(原子操作)
def assign_task(agent: str, task_id: str) -> None:
# 1. 写 signals/{agent}/current_task.json(包含完整上下文)
# 2. 写 tasks/{task_id}.lock(锁定信息)
# 3. 移动 tasks/todo/{task_id}.md → tasks/doing/{task_id}.md
# 4. 更新 agents/{agent}/runtime.json(status=busy, current_task_id=xxx)
# 5. 记录日志5.4 完成检测
def check_completion(agent: str, task_id: str) -> bool:
done_file = f"outbox/{agent}/{task_id}/DONE"
return Path(done_file).exists()5.5 并发控制
MAX_CONCURRENT_AGENTS = 3 # 最多同时分配任务给多少个 agent
MAX_TASK_RUNTIME = 1800 # 单任务超时(秒,30min)
MAX_RETRIES = 3 # blocked 后最大重试次数
POLL_INTERVAL = 10 # 扫描间隔(秒)六、tmux 架构
6.1 Session / Pane 结构
Session: hermes
├── pane: orchestrator # Orchestrator 进程(用于观察,可选 detach)
├── pane: agent_laohuang # Runner 常驻循环
├── pane: agent_market01 # Runner 常驻循环
└── pane: agent_content01 # Runner 常驻循环
6.2 Runner 在 pane 中的行为
每个 agent pane 启动后运行:
while true; do
if [ -f signals/{agent}/current_task.json ]; then
TASK=$(cat signals/{agent}/current_task.json)
# 解析并执行任务
claude -p runners/claude_runner.md \
--extra-var "task_id=$(jq -r '.task_id' <<< $TASK)" \
--extra-var "task_file=$(jq -r '.task_file' <<< $TASK)" \
--extra-var "workspace=$(jq -r '.workspace_root' <<< $TASK)" \
# ... 其他变量
# 清理信号文件
rm signals/{agent}/current_task.json
fi
sleep 5
done设计决策:pane 内循环 + 信号文件,而不是 send-keys 理由:Claude Code 是交互式 CLI,send-keys 无法可靠注入多行上下文;信号文件可审计、可重试
6.3 Orchestrator 启动 tmux pane
def ensure_agent_pane(agent: str) -> None:
pane = f"agent_{agent}"
if not tmux.pane_exists("hermes", pane):
tmux.new_window("hermes", pane)
tmux.send_keys(f"cd {WORKSPACE}", pane=pane)
tmux.send_keys(RUNNER_BOOT_SCRIPT.format(agent=agent), pane=pane)七、Agent Runner 规范
7.1 执行流程
1. 读取 signals/{agent}/current_task.json
2. 读取对应 task file
3. 解析 goal 和 context
4. 执行任务(写代码 / 跑命令 / 写文案)
5. 写 logs/{agent}/{date}.md(执行过程)
6. 写 outbox/{agent}/{task_id}/(交付物)
7. 写 outbox/{agent}/{task_id}/summary.md
8. 写 outbox/{agent}/{task_id}/DONE(完成信号)
9. 更新 heartbeat status = "done"
10. 清理 signals/{agent}/current_task.json
7.2 summary.md 格式
# 任务交付总结
- 任务 ID:01HW5T3M7Z9A2B3C4D5E6F7G8H
- 执行 Agent:laohuang
- 开始时间:2026-04-26T13:35:00Z
- 结束时间:2026-04-26T14:20:00Z
- 结果状态:✅ 成功
## 产出清单
| 文件 | 说明 |
|------|------|
| pages/landing.tsx | 落地页主组件 |
| styles/landing.css | 样式文件 |
| package.json | 依赖更新 |
## 执行摘要
1. 阅读了项目文档和设计稿
2. 使用 Next.js App Router 创建落地页
3. 实现了响应式 Hero 区域
4. 集成了价格展示组件
## 遇到的问题(如有)
无7.3 禁止行为(AGENT_WORK_RULES.md)
# Agent 工作规范
## 绝对禁止
1. 删除系统目录:/, /boot, /usr, /etc, /var, /home
2. 执行递归删除:rm -rf /
3. 修改系统配置:/etc/hosts, /etc/passwd, /etc/sudoers
4. 使用未授权的 sudo 命令
5. 修改 Hermes 核心文件:hermes.py, orchestrator.py, lib/
6. 修改其他 Agent 的 profile.json / runtime.json
7. 向未授权的网络地址发送数据
## 允许的操作
- 读写项目文件(workspace_root 内的项目目录)
- 执行 npm/bun/pip 等包管理命令
- 执行 git 命令(commit/push/pull,不强制)
- 创建和删除项目内文件
## 交付要求
- 每任务必须生成 summary.md
- 每任务必须创建 DONE 文件
- 必须记录执行日志八、观测能力
8.1 实时观察
# 查看所有 pane 活动
tmux attach -t hermes
# 监控任务目录变化
watch -n 3 'tree tasks/ outbox/ signals/ -L 2'8.2 Agent 状态查询
hermes agent status laohuang
# → current_task: TASK-xxx, status: working, since: 13:358.3 日志规范
路径:logs/{agent}/YYYY-MM-DD.md
# 工作日志 — laohuang — 2026-04-26
## 任务:01HW5T3M7Z — 开发知识库商品落地页
开始:13:35 | 结束:14:20 | 状态:✅
### 执行记录
| 时间 | 动作 | 详情 |
|------|------|------|
| 13:35 | 读取任务 | 分析 goal 和 context |
| 13:42 | 阅读代码 | 发现需要 Next.js 15 |
| 13:55 | 创建组件 | pages/landing.tsx |
| 14:10 | 测试验证 | npm run build 通过 |
| 14:18 | 写 summary | outbox/laohuang/01HW5T3M7Z/summary.md |
| 14:20 | 完成 | DONE 信号已写 |第二部分:V1 开发 PRD
一、产品定义
1.1 名称
Agent Company OS V1 — "最小闭环"
1.2 核心目标
人类只需创建任务,系统自动分配 → 执行 → 交付。人类角色简化为:提任务 → 审结果 → 做决策。
1.3 V1 范围
做:
- Hermes Core CLI(任务 CRUD、Agent 注册、初始化)
- Orchestrator(轮询调度器)
- Agent Runner 接口规范(Claude Code 模式)
- 文件系统状态存储(无数据库)
- 最多 3 个 Agent 并发
不做:
- 多 VPS 分布式(V2)
- Redis 队列(V3)
- Web Dashboard(V4)
- Agent 记忆进化(V5)
- 任务依赖管理(V2)
1.4 成功标准
✅ hermes task create 后系统自动 pickup
✅ Agent 产出 outbox/{agent}/{task}/summary.md + DONE
✅ 任务状态自动 todo → doing → review
❌ 不需要手动运行 agent
❌ 不需要手动复制粘贴任务上下文
❌ 不需要手动推进流程
二、技术选型
| 组件 | 选择 | 理由 |
|---|---|---|
| Hermes Core | Python 3.11+ / Click | 跨平台、成熟生态、CLI 友好 |
| Orchestrator | Python 3.11+ / asyncio | 异步 IO,适合文件轮询场景 |
| tmux | 系统包 | 已有容器层,无需开发 |
| Agent Runner | Claude Code(-p prompt 模式) |
已有能力,可变参数注入 |
| 配置存储 | YAML + Markdown | 无数据库依赖 |
| 任务 ID | ULID | 时间有序、全球唯一、20 字符紧凑 |
关于 asyncio:Orchestrator 主要瓶颈是 IO(文件读写),用 asyncio 可优雅处理多 agent 监控,代码也比多线程简洁。
三、CLI 接口(Hermes Core)
3.1 命令清单
# 初始化
hermes init # 创建目录结构 + 配置文件
hermes doctor # 检查依赖(tmux、claude CLI)
# 任务管理
hermes task create --title "..." --owner laohuang --project x --priority P1 --goal "..."
hermes task list [--state todo|doing|review|done]
hermes task show <task_id>
hermes task move <task_id> <target_state> [--reason "..."]
hermes task delete <task_id>
# Agent 管理
hermes agent register --name laohuang --role fullstack --engine claude-code
hermes agent list
hermes agent status <name>3.2 hermes init 行为
创建:
tasks/todo tasks/doing tasks/blocked tasks/review tasks/done
agents/
memory/
logs/
outbox/
signals/
config/
company/
runners/
并生成初始配置文件(若不存在):
config/agents.yaml
config/company.yaml
company/AGENT_WORK_RULES.md
runners/claude_runner.md
3.3 hermes doctor 检查项
- tmux 已安装
- claude CLI 已安装(
claude --version) - 目录结构完整
- config/agents.yaml 存在且非空
- 所有注册 agent 有对应 profile.json
四、项目结构(V1 实现)
agent-company/
├── pyproject.toml
├── hermes.py # CLI 入口(Click)
├── orchestrator.py # 调度器(asyncio 主循环)
├── lib/
│ ├── __init__.py
│ ├── task.py # TaskManager 类(CRUD + 状态机)
│ ├── agent.py # AgentManager 类(注册 + 运行时)
│ ├── tmux_ctrl.py # TmuxController(tmux 操作封装)
│ ├── signals.py # SignalManager(信号文件读写)
│ └── ulid.py # ULID 生成工具
├── config/
│ ├── agents.yaml
│ └── company.yaml
├── runners/
│ └── claude_runner.md
├── company/
│ └── AGENT_WORK_RULES.md
├── agents/ # 每个 agent 一个目录
├── tasks/ # 状态分目录
├── memory/
├── logs/
├── outbox/
├── signals/ # Orchestrator → Runner
└── tests/
├── test_task.py
├── test_state_machine.py
└── test_orchestrator.py
五、实现任务拆分
Phase 0:脚手架(1 天)
-
pyproject.toml+ 依赖(click, pyyaml, python-ulid, pytest) - 目录结构创建(hermes init)
- hermes doctor(依赖检查)
-
config/agents.yaml+config/company.yamlschema -
company/AGENT_WORK_RULES.md -
runners/claude_runner.md模板
Phase 1:Hermes Core(2 天)
-
lib/ulid.py(ULID 生成) -
lib/task.py(TaskManager:create/list/show/move/delete) -
lib/agent.py(AgentManager:register/list/status) -
hermes.pyCLI(Click 命令绑定) - 状态变更原子性保证(写-移动-删除事务)
-
.lock文件读写逻辑
Phase 2:tmux 控制层(1 天)
-
lib/tmux_ctrl.py(TmuxController)- session 创建/检查
- pane 创建/检查/发送命令
- pane 内运行 Runner 启动脚本
- Runner 启动脚本(bash,用于每个 pane)
Phase 3:Orchestrator(3 天)
-
lib/signals.py(SignalManager:写 Runner 信号、读 Runner 心跳) -
Orchestrator类(asyncio 主循环)- 扫描 todo + 匹配 idle agent
- 原子分配(写信号 + 移动文件 + 更新 runtime)
- DONE 信号检测
- 超时监控
- blocked 处理
- Graceful shutdown(SIGTERM 处理)
-
--dry-run模式 - 详细日志输出
Phase 4:Runner 集成(1 天)
-
runners/claude_runner.md变量填充逻辑 - Runner 执行后的 outbox/summary.md 格式验证
- 日志格式验证
- DONE 文件创建验证
Phase 5:集成测试(2 天)
- 完整流程:task create → pickup → execute → outbox
- 3 个 agent 并发测试
- 超时 → blocked 测试
- blocked → retry → done 测试
- Orchestrator 重启后状态恢复测试
- dry-run 验证
Phase 6:文档(1 天)
- README.md(快速开始)
- 架构图(ASCII)
- 验收清单
总工期:约 11 个工作日
六、关键设计决策
| 决策 | 选择 | 理由 |
|---|---|---|
| Orchestrator ↔ Runner 通信 | 信号文件(signals/) | tmux send-keys 无法可靠注入交互式 Claude Code;文件信号可审计 |
| 任务文件锁定 | 独立 .lock 文件 | 保持原始 md 纯净;分离调度信息和业务信息 |
| 任务 ID | ULID | 时间有序、支持分布式生成、紧凑(20 字符) |
| Orchestrator 实现 | asyncio 类 | 适合 IO 密集型轮询;比多线程/多进程简洁 |
| Runner 启动方式 | pane 内 bash 循环 | Claude Code 无法后台常驻;循环等待信号文件最稳定 |
| 完成检测 | DONE 文件存在 | 最简可靠信号;比心跳停止检测更明确 |
| 状态存储 | 文件系统 | V1 最小依赖;后续迁移 SQLite 成本低 |
| 调度触发 | 轮询(10s) | 简单可靠;比 Webhook 少依赖 |
七、升级路径
V1 (文件系统 + 轮询)
├── 改进:状态存储 → SQLite(事务保证)
├── 改进:任务依赖 DAG → topological sort
└── 改进:调度策略 → 技能最优匹配
V2 (分布式)
├── 多 VPS SSH 调度
└── 远程 tmux pane(via ssh)
V3 (队列化)
└── Redis Queue + Celery Worker
V4 (可视化)
└── Web Dashboard + REST API
V5 (智能化)
└── Agent 记忆进化 + 主动任务发现
八、验收标准
自动测试必须通过
[ ] hermes init 成功创建所有目录
[ ] hermes doctor 无报错(tmux + claude CLI)
[ ] hermes task create 生成 tasks/todo/{ulid}.md,ID 为 ULID 格式
[ ] hermes task list --state todo 正确显示
[ ] hermes task move task_id doing 原子移动文件
[ ] hermes task show 显示完整信息(含 .lock 扩展)
[ ] hermes agent register 生成 agents/{name}/profile.json
[ ] Orchestrator 启动后持续运行(不退出)
[ ] 创建 todo 任务后 15s 内被 pickup(idle agent 存在时)
[ ] pickup 后 tasks/todo/ → tasks/doing/ 文件已移动
[ ] signals/{agent}/current_task.json 被创建且内容正确
[ ] Agent pane 检测到信号文件并执行
[ ] outbox/{agent}/{task}/summary.md 存在且格式正确
[ ] outbox/{agent}/{task}/DONE 文件存在
[ ] DONE 存在后 tasks/doing/ → tasks/review/ 自动流转
[ ] 任务超时(30min)后进入 blocked 状态
[ ] 3 个 agent 并发无冲突(无重复 pickup)
手动验收场景
场景 1:完全无人值守
$ hermes task create --title "写 hello.py" --owner laohuang --goal "在 /tmp/hello.py 写 print('hello')"
等待 3 分钟
$ hermes task list --state review
→ 任务已在 review
$ cat outbox/laohuang/*/summary.md
→ 有产出内容
场景 2:并发调度
同时提交 5 个任务(owner = laohuang/market01/content01 混合)
3 个 pane 并发执行
无任务丢失,无状态混乱
场景 3:失败恢复
Orchestrator 运行中,Ctrl+C 重启
之前 doing 的任务进入 blocked 或恢复 pickup
附录 A:配置文件格式
config/agents.yaml
agents:
- name: laohuang
role: fullstack_engineer
engine: claude-code
capabilities:
- frontend
- backend
- devops
workspace_root: /home/laohuang/projects
- name: market01
role: marketing_writer
engine: claude-code
capabilities:
- copywriting
- seo
- social_media
workspace_root: /home/laohuang/projects
- name: content01
role: content_creator
engine: claude-code
capabilities:
- article
- video_script
- documentation
workspace_root: /home/laohuang/projectsconfig/company.yaml
company:
name: Hermes AI Company
workspace_root: /home/laohuang/projects
max_concurrent_agents: 3
task_timeout_seconds: 1800
poll_interval_seconds: 10
max_retries: 3
paths:
tasks: tasks
agents: agents
logs: logs
outbox: outbox
memory: memory
signals: signals
runners: runners
company_rules: company/AGENT_WORK_RULES.md附录 B:orchestrator.py 核心逻辑(伪代码)
import asyncio
from lib.task import TaskManager
from lib.agent import AgentManager
from lib.signals import SignalManager
from lib.tmux_ctrl import TmuxController
class Orchestrator:
def __init__(self, config):
self.tasks = TaskManager()
self.agents = AgentManager()
self.signals = SignalManager()
self.tmux = TmuxController()
self.poll_interval = config.poll_interval
self.running = True
async def run(self):
# 确保所有 agent pane 存在
for agent in self.agents.list():
self.tmux.ensure_pane(agent)
while self.running:
await self.step()
await asyncio.sleep(self.poll_interval)
async def step(self):
self.sync_agent_status()
self.process_blocked()
await self.scan_and_assign()
self.detect_completions()
async def scan_and_assign(self):
idle_agents = [a for a in self.agents.list() if a.is_idle()]
for agent in idle_agents:
if self.agents.active_count() >= MAX_CONCURRENT:
break
task = self.tasks.pick_best_todo()
if not task:
break
self.assign_task(agent, task)
def assign_task(self, agent, task):
# 原子操作:
# 1. 写信号文件
self.signals.write_task_signal(agent, task)
# 2. 创建锁文件
self.tasks.lock(task.id, agent)
# 3. 移动任务文件
self.tasks.move(task.id, "todo", "doing")
# 4. 更新 agent 状态
self.agents.assign(agent, task.id)
log(f"Assigned {task.id} to {agent}")
def detect_completions(self):
for agent in self.agents.list_busy():
task_id = agent.current_task_id
if self.signals.check_done(agent, task_id):
self.tasks.move(task_id, "doing", "review")
self.agents.free(agent)
log(f"Task {task_id} completed, moved to review")系统蓝图一句话: Hermes 定义"谁该做什么",Orchestrator 决定"什么时候让谁去做",tmux 承载"他们在哪里做",Claude Code 负责"真正把事情做出来",信号文件连接"调度与执行"。