init: OpenSpec project scaffolding with proposal, design, specs, tasks
- 7 capabilities: agent-registry, task-router, receipt-protocol, forgejo-integration, matrix-chatops, agent-adapter, orchestrator-core - Tech stack: Rust + axum + zigbuild (single binary) - Forgejo as task source of truth - Matrix as real-time ChatOps layer - Adapter pattern for multi-agent type support
This commit is contained in:
commit
aabd52ed52
19 changed files with 1938 additions and 0 deletions
2
openspec/changes/agent-fleet-platform/.openspec.yaml
Normal file
2
openspec/changes/agent-fleet-platform/.openspec.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
schema: spec-driven
|
||||
created: 2026-05-11
|
||||
250
openspec/changes/agent-fleet-platform/design.md
Normal file
250
openspec/changes/agent-fleet-platform/design.md
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
## Context
|
||||
|
||||
当前有多台机器(WSL2 workstation、MacBook、可能的云服务器)运行不同类型的 AI Agent:
|
||||
- **OpenClaw**:Jeeves orchestrator + 多个 sub-agent
|
||||
- **Claude Code**:本地 CLI 编码
|
||||
- **Codex CLI**:OpenAI 编码
|
||||
- **Hermes Agent**:其他类型
|
||||
- **ACP-compatible agents**:Devin 等
|
||||
|
||||
现状:Agent 之间无统一协同机制,任务靠人工传递,进度靠人工追踪,没有结构化的完成验证。
|
||||
|
||||
已有基础设施:
|
||||
- **Matrix**:0x08.org homeserver 已运行
|
||||
- **Forgejo**:需要部署(建议自建,或用 Gitea 替代)
|
||||
- 各机器可以互相网络通信
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- 建立统一的 Agent 编排平台,支持任意类型 Agent 加入
|
||||
- Forgejo Issue/PR 作为任务事实来源,人类和 Agent 共用同一界面
|
||||
- Matrix 作为实时协同层,提供 ChatOps 和通知
|
||||
- 结构化 receipt 协议,不信任模型口头声明
|
||||
- 最小化对现有 Agent 的侵入性(adapter 模式)
|
||||
- 可扩展:新 Agent 类型只需实现 adapter 即可接入
|
||||
|
||||
**Non-Goals:**
|
||||
- 不做 Agent 自身的改进(Agent 内部行为不在 scope 内)
|
||||
- 不做 IDE 集成(VS Code / JetBrains 插件)
|
||||
- 不做 LLM provider 管理(使用各 Agent 自己的 provider 配置)
|
||||
- 不做前端 Web UI(Phase 1 用 Forgejo + Matrix 作为 UI)
|
||||
- 不替换 cc-connect / cc-telegram-bridge(它们可以作为 adapter 接入)
|
||||
|
||||
## Decisions
|
||||
|
||||
### Decision 1: Forgejo(而非 Gitea)作为 Git 平台
|
||||
|
||||
**选择**: Forgejo
|
||||
|
||||
**理由**:
|
||||
- Forgejo 是 Gitea 的社区 fork,治理更开放
|
||||
- 内置 CI/CD(Forgejo Actions),未来可扩展
|
||||
- API 兼容 Gitea,迁移成本低
|
||||
- 支持 F3 (Friendly Forge Format),数据可移植
|
||||
|
||||
**替代方案**:
|
||||
- Gitea:更成熟但治理有争议(公司化)
|
||||
- GitHub:不方便自建,网络可达性差
|
||||
- GitLab:太重,资源消耗大
|
||||
|
||||
### Decision 2: Orchestrator 用 Rust + zigbuild
|
||||
|
||||
**选择**: Rust + cargo-zigbuild(交叉编译)
|
||||
|
||||
**理由**:
|
||||
- 内存安全:无 GC、无 data race、无 null pointer
|
||||
- 单二进制部署:zigbuild 交叉编译,无 libc 兼容性问题
|
||||
- 性能:原生性能,适合长运行服务
|
||||
- 类型系统:强类型 + algebraic data types,适合状态机建模
|
||||
- 生态:reqwest(HTTP)、matrix-sdk(Matrix)、rusqlite(SQLite)、serde(JSON/TOML)
|
||||
- 交叉编译:cargo-zigbuild 一行命令产出 Linux/macOS/Windows 二进制
|
||||
|
||||
**替代方案**:
|
||||
- TypeScript (Node.js):开发快但需要运行时,非单二进制
|
||||
- Go:单二进制但内存安全不如 Rust,交叉编译有 libc 问题
|
||||
|
||||
### Decision 3: Agent-Orchestrator 通信用 HTTP API(axum)
|
||||
|
||||
**选择**: Agent 通过 HTTP API 与 Orchestrator 通信,Orchestrator 端用 axum 框架
|
||||
|
||||
**理由**:
|
||||
- 跨语言、跨平台:任何 Agent 都能发 HTTP 请求
|
||||
- 防火墙友好
|
||||
- 与 Forgejo webhook 统一协议栈
|
||||
- axum 是 Rust 生态最成熟的 async HTTP 框架
|
||||
|
||||
**替代方案**:
|
||||
- WebSocket:实时性好但复杂度高,重连逻辑麻烦
|
||||
- gRPC:性能好但 Agent 端实现门槛高
|
||||
- Message Queue(NATS/Redis):增加基础设施依赖
|
||||
|
||||
### Decision 4: Event sourcing 作为审计基础(rusqlite)
|
||||
|
||||
**选择**: 所有状态变更作为不可变事件 append 到 SQLite,通过 rusqlite 访问
|
||||
|
||||
**理由**:
|
||||
- 完整审计追踪
|
||||
- 可重放
|
||||
- 轻量,不需要外部数据库,适合单二进制打包
|
||||
- rusqlite 是 Rust 生态最成熟的 SQLite 绑定
|
||||
- 适合中小规模 Agent 舰队(< 100 agents)
|
||||
|
||||
**替代方案**:
|
||||
- PostgreSQL:强大但引入运维复杂度,破坏单二进制部署
|
||||
- JSON 文件:简单但无查询能力
|
||||
- 只记录当前状态:无法审计
|
||||
|
||||
### Decision 5: Adapter 模式接入多类型 Agent
|
||||
|
||||
**选择**: 定义统一 adapter interface,各 Agent 实现自己的 adapter
|
||||
|
||||
**理由**:
|
||||
- 最小侵入:Agent 不需要改内部逻辑
|
||||
- 可扩展:新 Agent 类型只需写 adapter
|
||||
- 隔离:adapter 故障不影响 Orchestrator
|
||||
|
||||
**adapter 执行方式**:
|
||||
- Claude Code adapter:spawn `claude -p` 子进程
|
||||
- Codex adapter:spawn `codex exec` 子进程
|
||||
- OpenClaw adapter:调用 gateway HTTP API
|
||||
- ACP adapter:通过 ACP 协议 WebSocket
|
||||
- Shell adapter:执行任意 shell 命令(最通用)
|
||||
|
||||
### Decision 6: 配置用 TOML
|
||||
|
||||
**选择**: TOML(与 cc-connect 一致)
|
||||
|
||||
**理由**:
|
||||
- 人类可读性好
|
||||
- 类型比 YAML 更明确
|
||||
- cc-connect 已验证
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
### Risk: Agent 执行环境差异
|
||||
不同机器上的 Agent 运行环境(OS、依赖、权限)不同,可能导致同一任务在不同 Agent 上行为不一致。
|
||||
→ **Mitigation**: adapter 负责环境检查;任务描述尽量环境无关;receipt 验证在 Forgejo 侧(与执行环境解耦)。
|
||||
|
||||
### Risk: Orchestrator 单点故障
|
||||
Orchestrator 挂了,整个舰队停摆。
|
||||
→ **Mitigation**: Phase 1 接受单点,Orchestrator 做到无状态(状态在 SQLite + Forgejo),快速重启恢复。
|
||||
|
||||
### Risk: Forgejo webhook 延迟或丢失
|
||||
网络抖动可能导致 webhook 丢失。
|
||||
→ **Mitigation**: Orchestrator 定期轮询 Forgejo 做对账(reconciliation),弥补 webhook 丢失。
|
||||
|
||||
### Risk: Agent 心跳风暴
|
||||
大量 Agent 同时发心跳可能导致 Orchestrator 负载过高。
|
||||
→ **Mitigation**: 心跳间隔可配置(默认 60s);Orchestrator 做好限流。
|
||||
|
||||
### Trade-off: 简单性 vs 实时性
|
||||
选择 HTTP 而非 WebSocket/MQ 意味着实时性稍差。
|
||||
→ 对于任务编排场景,秒级延迟完全可接受。Matrix 通知提供实时感。
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
┌─────────────┐ webhook ┌──────────────────┐
|
||||
│ Forgejo │ ───────────────→ │ Orchestrator │
|
||||
│ (Git+Issue) │ ←─── API ────── │ (Node.js) │
|
||||
└─────────────┘ │ │
|
||||
│ - Agent Registry │
|
||||
┌─────────────┐ HTTP API │ - Task Router │
|
||||
│ Matrix │ ←──────────────→│ - Event Log │
|
||||
│ (ChatOps) │ │ - Receipt Validator│
|
||||
└─────────────┘ └────────┬──────────┘
|
||||
│ HTTP API
|
||||
┌───────────────────┼───────────────────┐
|
||||
│ │ │
|
||||
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
|
||||
│ Adapter A │ │ Adapter B │ │ Adapter C │
|
||||
│ Claude Code │ │ Codex CLI │ │ OpenClaw │
|
||||
│ (host-01) │ │ (host-02) │ │ (host-03) │
|
||||
└─────────────┘ └─────────────┘ └─────────────┘
|
||||
```
|
||||
|
||||
## Data Model (Core)
|
||||
|
||||
```typescript
|
||||
interface Agent {
|
||||
agent_id: string;
|
||||
agent_type: "openclaw" | "claude-code" | "codex-cli" | "hermes" | "acp" | "shell";
|
||||
hostname: string;
|
||||
capabilities: string[];
|
||||
max_concurrency: number;
|
||||
current_tasks: number;
|
||||
status: "online" | "offline" | "draining";
|
||||
last_heartbeat_at: string; // ISO 8601
|
||||
registered_at: string;
|
||||
metadata: Record<string, string>;
|
||||
}
|
||||
|
||||
interface Task {
|
||||
task_id: string;
|
||||
source: string; // "forgejo:<repo>#<issue>"
|
||||
type: string; // from label: "code", "review", "test", "deploy", "research"
|
||||
priority: "low" | "normal" | "high" | "urgent";
|
||||
status: TaskStatus;
|
||||
assigned_agent_id?: string;
|
||||
requirements: string; // Issue body
|
||||
labels: string[];
|
||||
created_at: string;
|
||||
assigned_at?: string;
|
||||
started_at?: string;
|
||||
completed_at?: string;
|
||||
retry_count: number;
|
||||
max_retries: number;
|
||||
timeout_seconds: number;
|
||||
}
|
||||
|
||||
type TaskStatus = "created" | "assigned" | "running" | "completed" | "failed" | "agent_lost" | "cancelled";
|
||||
|
||||
interface Receipt {
|
||||
task_id: string;
|
||||
agent_id: string;
|
||||
status: "completed" | "failed" | "partial";
|
||||
duration_seconds: number;
|
||||
summary: string;
|
||||
artifacts: Artifact[];
|
||||
error?: string;
|
||||
}
|
||||
|
||||
interface Artifact {
|
||||
type: "pr" | "commit" | "file" | "comment" | "url";
|
||||
url?: string;
|
||||
path?: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
interface TaskEvent {
|
||||
event_id: string;
|
||||
task_id: string;
|
||||
event_type: string; // "created", "assigned", "started", "receipt_submitted", "completed", "failed", ...
|
||||
agent_id?: string;
|
||||
timestamp: string;
|
||||
payload: Record<string, unknown>;
|
||||
}
|
||||
```
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. **部署 Forgejo**:自建实例,配置 webhook
|
||||
2. **部署 Orchestrator**:Node.js 进程,连接 Forgejo + Matrix
|
||||
3. **实现 Claude Code adapter**:第一个 adapter,验证端到端流程
|
||||
4. **实现 Codex adapter**:第二个 adapter
|
||||
5. **实现 OpenClaw adapter**:第三个 adapter(可选 Phase 2)
|
||||
6. **逐步迁移现有任务到 Forgejo Issue**
|
||||
|
||||
### Rollback
|
||||
- Orchestrator 可随时停止,不影响 Forgejo 和 Matrix
|
||||
- Agent 可独立运行(只是没有编排)
|
||||
- 所有状态在 Forgejo Issue + SQLite,可手动接管
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. ~~**Forgejo 部署位置**~~:✅ 已部署在 arm0.0x08.org,域名 git.0x08.org
|
||||
2. **Orchestrator 部署位置**:TBD(arm0 / WSL2 / 独立机器)
|
||||
3. **Agent 工作目录策略**:每个任务 clone 新 worktree 还是共享 workspace?
|
||||
4. **权限模型**:Issue comment 中的 `/assign` 命令是否需要权限控制?
|
||||
5. **cc-connect 集成**:✅ 放 Phase 2
|
||||
37
openspec/changes/agent-fleet-platform/proposal.md
Normal file
37
openspec/changes/agent-fleet-platform/proposal.md
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
## Why
|
||||
|
||||
多台机器上运行着不同类型的 AI Agent(OpenClaw、Claude Code、Codex、Hermes Agent 等),目前缺乏统一的跨机任务编排与协同机制。Agent 之间只能靠人工传递上下文,无法自动分发任务、追踪进度、回写结果。需要一个 **agent-fleet platform**,让任意类型的 Agent 通过统一的协议加入舰队,接收任务、汇报状态、协同完成复杂工程。
|
||||
|
||||
## What Changes
|
||||
|
||||
- **引入 Git 仓库(Forgejo)作为任务事实来源**:Issue = 任务单元,PR = 交付物,Label/Milestone = 分类与排期
|
||||
- **引入实时协同层**:Matrix 作为 ChatOps 通道,Agent 状态变更、任务分配、完成通知等通过 Matrix 房间实时推送
|
||||
- **建立 Agent Registry**:每台机器上的 Agent 启动时向 Registry 注册(类型、能力、负载),支持动态发现与路由
|
||||
- **建立 Task Router**:Orchestrator 根据 Issue 类型、Agent 能力、负载状态,自动将任务路由到合适的 Agent
|
||||
- **建立结构化 Receipt 协议**:Agent 完成工作后回写结构化 receipt(Issue comment / PR / Matrix 通知),系统不信任模型口头声明
|
||||
- **支持多 Agent 类型**:OpenClaw、Claude Code、Codex CLI、Hermes Agent、任意 ACP-compatible agent,只要能读写 Git repo 并发 Matrix 消息即可加入
|
||||
- **支持 hooks/webhook**:Forgejo webhook → 路由到编排层 → 触发 Agent 执行
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `agent-registry`: Agent 注册、心跳、能力声明、动态发现。每台机器上的 Agent 启动时注册自身(类型、hostname、能力标签、当前负载),Orchestrator 据此做任务路由
|
||||
- `task-router`: 任务解析与分发。从 Forgejo Issue/PR 事件中解析任务需求,匹配 Agent 能力与负载,生成执行指令并投递
|
||||
- `receipt-protocol`: 结构化完成回执。Agent 完成工作后必须回写结构化 receipt(Issue comment / PR / Matrix 通知),系统据此判定完成状态,不依赖模型口头声明
|
||||
- `forgejo-integration`: 与 Forgejo 的双向集成。监听 Issue/PR webhook 事件;Agent 执行完成后回写 comment、创建 PR、更新 label/milestone
|
||||
- `matrix-chatops`: Matrix 实时协同层。Agent 状态变更、任务分配、完成通知、人类审批等通过 Matrix 房间流转;支持 slash command 触发编排操作
|
||||
- `agent-adapter`: 多类型 Agent 适配层。定义统一 adapter 接口,各类型 Agent(OpenClaw、Claude Code、Codex CLI、Hermes Agent、ACP agent)实现自己的 adapter,接入统一编排
|
||||
- `orchestrator-core`: 编排核心。管理任务生命周期(created → assigned → running → completed/failed),调度 Agent,处理超时/重试/升级,维护全局状态
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
(初始项目,无既有 capability 需修改)
|
||||
|
||||
## Impact
|
||||
|
||||
- **新系统**:需要部署 Forgejo 实例 + Matrix homeserver(或复用现有)
|
||||
- **网络**:各机器需要能访问 Forgejo API(HTTP)、Matrix federation(HTTPS)、Orchestrator API(HTTP/WebSocket)
|
||||
- **Agent 端**:每种 Agent 需要实现 adapter,最小要求:能读 Git repo、能调用 Forgejo API 写 comment/PR、能发 Matrix 消息
|
||||
- **依赖**:Forgejo(Git + Issue + PR + webhook)、Matrix(实时消息)、Node.js/Python(Orchestrator runtime)
|
||||
- **运维**:需要 monitor Agent 心跳、任务超时、Forgejo webhook 健康检查
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
## ADDED Requirements
|
||||
|
||||
### Requirement: Unified adapter interface
|
||||
系统 SHALL 定义统一的 Agent Adapter 接口,所有类型的 Agent 通过实现该接口接入编排系统。
|
||||
|
||||
Adapter 接口 SHALL 至少包含:
|
||||
- `register()` — 注册到 Registry
|
||||
- `heartbeat()` — 发送心跳
|
||||
- `execute(task)` — 接收并执行任务
|
||||
- `submit_receipt(receipt)` — 提交 receipt
|
||||
- `deregister()` — 注销
|
||||
|
||||
#### Scenario: Claude Code adapter implementation
|
||||
- **WHEN** 使用 Claude Code adapter
|
||||
- **THEN** `execute(task)` SHALL 将任务 prompt 注入 `claude -p --output-format json`,在工作目录中执行,解析输出为 receipt
|
||||
|
||||
#### Scenario: Codex CLI adapter implementation
|
||||
- **WHEN** 使用 Codex adapter
|
||||
- **THEN** `execute(task)` SHALL 使用 `codex exec --json` 执行任务,解析输出为 receipt
|
||||
|
||||
#### Scenario: OpenClaw adapter implementation
|
||||
- **WHEN** 使用 OpenClaw adapter
|
||||
- **THEN** `execute(task)` SHALL 通过 OpenClaw gateway API 或 CLI 触发 agent 执行
|
||||
|
||||
#### Scenario: ACP-compatible agent adapter
|
||||
- **WHEN** 使用 ACP adapter
|
||||
- **THEN** `execute(task)` SHALL 通过 ACP 协议启动 agent session,传递任务 prompt,收集输出
|
||||
|
||||
### Requirement: Adapter configuration
|
||||
每个 Agent 实例 SHALL 通过配置文件指定 adapter 类型、连接参数、工作目录、环境变量。
|
||||
|
||||
#### Scenario: Configuration file format
|
||||
- **WHEN** Agent 实例配置为 Claude Code 类型
|
||||
- **THEN** 配置文件 SHALL 包含:`{adapter: "claude-code", work_dir: "/path/to/repo", model: "sonnet", max_concurrency: 2, capabilities: ["code:typescript", "review"]}`
|
||||
|
||||
### Requirement: Adapter health check
|
||||
Adapter SHALL 提供健康检查能力:检查底层 Agent 是否可用(CLI 是否安装、API 是否可达)。
|
||||
|
||||
#### Scenario: Claude Code CLI not found
|
||||
- **WHEN** Claude Code adapter 初始化时检测到 `claude` CLI 未安装
|
||||
- **THEN** Adapter SHALL 返回健康检查失败,Agent 注册 SHALL 被拒绝
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
## ADDED Requirements
|
||||
|
||||
### Requirement: Agent self-registration
|
||||
每台机器上的 Agent 启动时 SHALL 向 Orchestrator Registry 注册自身信息:agent_id、agent_type(openclaw / claude-code / codex-cli / hermes / acp 等)、hostname、capabilities(能力标签列表)、max_concurrency、metadata(版本、工作目录等)。
|
||||
|
||||
#### Scenario: New agent starts and registers
|
||||
- **WHEN** 一个新的 Codex CLI Agent 在 host-worker-02 上启动
|
||||
- **THEN** 它 SHALL 调用 `POST /api/v1/agents/register`,Orchestrator 记录该 Agent 信息并返回 agent_id 和 registry token
|
||||
|
||||
#### Scenario: Duplicate registration with same agent_id
|
||||
- **WHEN** 已注册的 Agent 重启后再次注册(相同 agent_id)
|
||||
- **THEN** 系统 SHALL 更新该 Agent 的信息(hostname、capabilities 等)而非创建重复条目
|
||||
|
||||
### Requirement: Agent heartbeat
|
||||
已注册的 Agent SHALL 每隔可配置的间隔(默认 60 秒)发送心跳。Orchestrator 据此判定 Agent 是否在线。
|
||||
|
||||
#### Scenario: Agent sends heartbeat on time
|
||||
- **WHEN** Agent 在 60 秒内发送心跳
|
||||
- **THEN** Orchestrator 更新 `last_heartbeat_at` 并保持 Agent 状态为 `online`
|
||||
|
||||
#### Scenario: Agent misses 3 consecutive heartbeats
|
||||
- **WHEN** Agent 连续 3 个心跳周期未发送心跳(180 秒)
|
||||
- **THEN** Orchestrator SHALL 将该 Agent 状态标记为 `offline`,并将该 Agent 上所有 `running` 状态的任务标记为 `agent_lost`
|
||||
|
||||
### Requirement: Agent capability declaration
|
||||
Agent 注册时 SHALL 声明自己的能力标签(如 `code:typescript`、`code:python`、`review`、`test`、`deploy`、`research`)。Task Router 据此匹配任务。
|
||||
|
||||
#### Scenario: Task requiring specific capability
|
||||
- **WHEN** 一个 Issue 被标记为 `agent:review` 且需要 TypeScript 能力
|
||||
- **THEN** Task Router SHALL 只将其分配给声明了 `review` 和 `code:typescript` 能力的在线 Agent
|
||||
|
||||
### Requirement: Agent graceful deregistration
|
||||
Agent 正常关闭时 SHALL 调用 `POST /api/v1/agents/deregister`,Orchestrator 将其标记为 `offline`。
|
||||
|
||||
#### Scenario: Agent deregisters on shutdown
|
||||
- **WHEN** Agent 调用 deregister API
|
||||
- **THEN** Orchestrator SHALL 将该 Agent 状态设为 `offline`,该 Agent 上所有 `running` 任务 SHALL 被重新入队
|
||||
|
||||
### Requirement: Agent list and query
|
||||
Orchestrator SHALL 提供 API 查询当前所有注册 Agent 的状态、能力、负载。
|
||||
|
||||
#### Scenario: Query agents by capability
|
||||
- **WHEN** 调用 `GET /api/v1/agents?capability=code:python&status=online`
|
||||
- **THEN** 返回所有在线且声明了 `code:python` 能力的 Agent 列表
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
## ADDED Requirements
|
||||
|
||||
### Requirement: Webhook endpoint for Forgejo
|
||||
Orchestrator SHALL 暴露 HTTP webhook endpoint 接收 Forgejo 事件:`POST /api/v1/webhooks/forgejo`。
|
||||
|
||||
#### Scenario: Forgejo sends issue event
|
||||
- **WHEN** Forgejo 配置了指向 Orchestrator 的 webhook,Issue 事件触发
|
||||
- **THEN** Orchestrator SHALL 接收、验证签名、解析事件体,并路由到 Task Router
|
||||
|
||||
#### Scenario: Invalid webhook signature
|
||||
- **WHEN** 收到的 webhook 签名验证失败
|
||||
- **THEN** Orchestrator SHALL 返回 401 并记录安全日志
|
||||
|
||||
### Requirement: Issue to task conversion
|
||||
Orchestrator SHALL 将 Forgejo Issue 转换为内部任务,保持双向映射:Issue URL ↔ task_id。
|
||||
|
||||
#### Scenario: Issue created with agent label
|
||||
- **WHEN** Issue #42 在 repo `my-project` 中创建,带 `agent:code` 标签
|
||||
- **THEN** 创建任务,`source = "forgejo:my-project#42"`,任务状态为 `created`
|
||||
|
||||
### Requirement: Task status sync back to Issue
|
||||
任务状态变更 SHALL 同步回 Forgejo Issue:label 更新(`status:todo` → `status:doing` → `status:done`)、milestone 更新、assignee 更新。
|
||||
|
||||
#### Scenario: Task assigned to agent
|
||||
- **WHEN** 任务被分配给 Agent `worker-03`
|
||||
- **THEN** 对应 Issue 的 assignee SHALL 更新为 `worker-03` 对应的 Forgejo 用户,label SHALL 添加 `status:doing`
|
||||
|
||||
#### Scenario: Task completed
|
||||
- **WHEN** 任务状态变为 `completed`
|
||||
- **THEN** Issue label SHALL 从 `status:doing` 变为 `status:done`,Issue comment SHALL 写入 receipt summary
|
||||
|
||||
### Requirement: PR creation and update
|
||||
Agent 通过 Orchestrator 创建的 PR SHALL 关联到原始 Issue(通过 description 或 `Closes #N` 引用)。
|
||||
|
||||
#### Scenario: Agent creates PR via Orchestrator
|
||||
- **WHEN** Agent 在 receipt 中声明需要创建 PR
|
||||
- **THEN** Orchestrator SHALL 协助创建 PR(或验证 Agent 直接创建的 PR),确保 PR body 包含 `Closes #<issue-number>`
|
||||
|
||||
### Requirement: Forgejo API authentication
|
||||
Orchestrator SHALL 使用 Forgejo API token 进行所有 API 调用(读取 Issue、创建 comment、更新 label、创建 PR 等)。
|
||||
|
||||
#### Scenario: Token rotation
|
||||
- **WHEN** Forgejo API token 过期
|
||||
- **THEN** Orchestrator SHALL 返回明确错误并通过 Matrix 通知管理员
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
## ADDED Requirements
|
||||
|
||||
### Requirement: Matrix room as coordination channel
|
||||
Orchestrator SHALL 使用 Matrix 房间作为实时协同通道:Agent 状态变更、任务分配、完成通知、人类审批等事件 SHALL 推送到 Matrix。
|
||||
|
||||
#### Scenario: Task assigned notification
|
||||
- **WHEN** 任务 #42 被分配给 Agent `worker-03`
|
||||
- **THEN** Matrix 协同房间 SHALL 收到通知:`📋 #42 → worker-03 [code:typescript]`
|
||||
|
||||
#### Scenario: Agent offline alert
|
||||
- **WHEN** Agent `worker-03` 连续 3 次心跳失败
|
||||
- **THEN** Matrix 房间 SHALL 收到告警:`⚠️ worker-03 offline — 2 running tasks affected`
|
||||
|
||||
### Requirement: Slash commands for orchestration
|
||||
人类 SHALL 能通过 Matrix slash command 触发编排操作。
|
||||
|
||||
#### Scenario: /fleet status
|
||||
- **WHEN** 人类发送 `/fleet status`
|
||||
- **THEN** Bot SHALL 回复所有 Agent 当前状态表格:Agent ID、类型、状态、当前任务数、能力
|
||||
|
||||
#### Scenario: /assign command
|
||||
- **WHEN** 人类发送 `/assign worker-03 #42`
|
||||
- **THEN** 任务 #42 SHALL 被手动分配给 worker-03
|
||||
|
||||
#### Scenario: /retry command
|
||||
- **WHEN** 人类发送 `/retry #42`
|
||||
- **THEN** 失败的任务 #42 SHALL 被重新入队
|
||||
|
||||
### Requirement: Matrix notifications for receipts
|
||||
每个 receipt 回写 SHALL 触发 Matrix 通知,包含任务状态、摘要、artifact 链接。
|
||||
|
||||
#### Scenario: Task completed notification
|
||||
- **WHEN** 任务 #42 的 receipt 验证通过,状态为 `completed`
|
||||
- **THEN** Matrix 房间 SHALL 收到通知:`✅ #42 completed by worker-03 — PR #15 — "修复登录验证 bug"`
|
||||
|
||||
#### Scenario: Task failed notification
|
||||
- **WHEN** 任务 #42 失败
|
||||
- **THEN** Matrix 房间 SHALL 收到通知:`❌ #42 failed — worker-03 — "构建超时"`
|
||||
|
||||
### Requirement: Per-agent Matrix thread
|
||||
每个 Agent SHALL 有独立的 Matrix thread(或 topic),用于该 Agent 的执行日志、状态更新、调试输出。
|
||||
|
||||
#### Scenario: Agent execution log
|
||||
- **WHEN** Agent worker-03 开始执行任务 #42
|
||||
- **THEN** worker-03 的 thread SHALL 收到执行开始消息,后续日志更新也在此 thread
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
## ADDED Requirements
|
||||
|
||||
### Requirement: Task lifecycle state machine
|
||||
Orchestrator SHALL 维护任务的状态机:`created` → `assigned` → `running` → `completed` / `failed` / `agent_lost` / `cancelled`。每次状态转换 SHALL 记录时间戳和触发原因。
|
||||
|
||||
#### Scenario: Full happy path
|
||||
- **WHEN** Issue 创建 → Agent 匹配 → Agent 接受 → 执行完成 → Receipt 验证通过
|
||||
- **THEN** 状态 SHALL 按序流转:`created` → `assigned` → `running` → `completed`
|
||||
|
||||
#### Scenario: Agent lost during execution
|
||||
- **WHEN** 执行中的 Agent 心跳超时,状态变为 `offline`
|
||||
- **THEN** 任务状态 SHALL 变为 `agent_lost`,Task Router SHALL 根据策略决定重新入队或标记 `failed`
|
||||
|
||||
### Requirement: Task timeout handling
|
||||
任务 SHALL 有可配置的超时时间(默认 30 分钟)。超时后 SHALL 自动标记为 `failed`。
|
||||
|
||||
#### Scenario: Task exceeds timeout
|
||||
- **WHEN** 任务 #42 执行超过 30 分钟无 receipt
|
||||
- **THEN** 任务 SHALL 标记为 `failed`,reason 为 `timeout`,Issue comment 写入超时通知
|
||||
|
||||
### Requirement: Task retry policy
|
||||
失败的任务 SHALL 根据可配置的重试策略(最大重试次数、退避间隔)自动或手动重试。
|
||||
|
||||
#### Scenario: Auto-retry on transient failure
|
||||
- **WHEN** 任务因 `agent_lost` 失败,重试策略允许最多 2 次自动重试
|
||||
- **THEN** 任务 SHALL 重新入队,分配给下一个可用 Agent
|
||||
|
||||
#### Scenario: Max retries exceeded
|
||||
- **WHEN** 任务已重试 2 次仍失败
|
||||
- **THEN** 任务 SHALL 保持 `failed` 状态,Matrix SHALL 通知人工介入
|
||||
|
||||
### Requirement: Global task queue
|
||||
Orchestrator SHALL 维护全局任务队列,按优先级排序。高优先级任务 SHALL 优先分配。
|
||||
|
||||
#### Scenario: Priority ordering
|
||||
- **WHEN** 队列中有 `priority:low` 任务 #10 和 `priority:high` 任务 #42
|
||||
- **THEN** 任务 #42 SHALL 先于 #10 被分配
|
||||
|
||||
### Requirement: Event sourcing for audit
|
||||
所有任务状态转换、Agent 事件、receipt 提交 SHALL 作为不可变事件记录到 event log。
|
||||
|
||||
#### Scenario: Task history query
|
||||
- **WHEN** 查询任务 #42 的历史
|
||||
- **THEN** 返回完整的事件序列:created → assigned to worker-03 → running → receipt submitted → completed,每条带时间戳
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
## ADDED Requirements
|
||||
|
||||
### Requirement: Structured receipt format
|
||||
Agent 完成任务后 SHALL 回写结构化 receipt。Receipt 包含:task_id、agent_id、status(completed / failed / partial)、duration_seconds、summary、artifacts(PR URL、文件路径等)、error(失败时)。
|
||||
|
||||
#### Scenario: Successful task completion with PR
|
||||
- **WHEN** Agent 完成代码任务并创建了 PR #15
|
||||
- **THEN** Agent SHALL 提交 receipt:`{status: "completed", artifacts: [{type: "pr", url: "https://forgejo.example/repo/pulls/15"}], summary: "..."}`
|
||||
|
||||
#### Scenario: Partial completion
|
||||
- **WHEN** Agent 完成了部分工作但未能全部完成
|
||||
- **THEN** Agent SHALL 提交 receipt:`{status: "partial", summary: "完成 3/5 个文件修改,test_auth.ts 超时", artifacts: [...]}`
|
||||
|
||||
### Requirement: Receipt delivery channels
|
||||
Receipt SHALL 通过至少一个持久化渠道回写:Forgejo Issue comment(必须)+ Matrix 通知(可选)。
|
||||
|
||||
#### Scenario: Receipt written as Issue comment
|
||||
- **WHEN** Agent 提交 receipt
|
||||
- **THEN** Orchestrator SHALL 在对应 Issue 下创建结构化 comment,包含 status emoji + summary + artifact links
|
||||
|
||||
#### Scenario: Receipt triggers Matrix notification
|
||||
- **WHEN** Receipt 写入成功
|
||||
- **THEN** Orchestrator SHALL 向 Matrix 协同房间发送通知消息,包含任务状态和关键信息
|
||||
|
||||
### Requirement: Receipt validation
|
||||
Orchestrator SHALL 验证 receipt 中的 artifact 声明(如 PR 是否真实存在)。
|
||||
|
||||
#### Scenario: PR artifact validation
|
||||
- **WHEN** Receipt 声明创建了 PR #15
|
||||
- **THEN** Orchestrator SHALL 通过 Forgejo API 验证 PR #15 确实存在,若不存在 SHALL 将任务标记为 `failed` 并通知 Agent
|
||||
|
||||
#### Scenario: Comment artifact validation
|
||||
- **WHEN** Receipt 声明在某个文件中做了修改
|
||||
- **THEN** Orchestrator SHALL 验证对应 commit/PR 包含该修改
|
||||
|
||||
### Requirement: No-trust policy
|
||||
系统 SHALL NOT 仅凭 Agent 的文本输出判定任务完成。只有结构化 receipt + artifact 验证通过才算 `completed`。
|
||||
|
||||
#### Scenario: Agent says done without receipt
|
||||
- **WHEN** Agent 在 Matrix 发消息说"任务完成了"但未提交 receipt
|
||||
- **THEN** 任务 SHALL 保持 `running` 状态,超时后按 `failed` 处理
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
## ADDED Requirements
|
||||
|
||||
### Requirement: Forgejo webhook event ingestion
|
||||
Orchestrator SHALL 监听 Forgejo webhook 事件(Issue 创建/更新/标签变更、PR 创建/更新/合并、Push 等),解析为内部任务事件。
|
||||
|
||||
#### Scenario: New issue with agent label
|
||||
- **WHEN** Forgejo 上创建了新 Issue,带有 `agent:code` 标签
|
||||
- **THEN** Orchestrator SHALL 接收到 `issues` webhook 事件,解析为 `task.created` 事件,提取 Issue 编号、标题、描述、标签、仓库信息
|
||||
|
||||
#### Scenario: Issue label changed to trigger assignment
|
||||
- **WHEN** Issue 的标签从 `agent:code` 变更为 `agent:review`
|
||||
- **THEN** Orchestrator SHALL 生成 `task.reroute` 事件,重新匹配具备 `review` 能力的 Agent
|
||||
|
||||
### Requirement: Task parsing from Issue
|
||||
Orchestrator SHALL 将 Issue 解析为结构化任务:task_id、source(forgejo issue URL)、type(由标签推断)、priority(由 label/milestone 推断)、requirements(Issue body)、labels。
|
||||
|
||||
#### Scenario: Issue with priority label
|
||||
- **WHEN** Issue 带有 `priority:high` 标签和 `agent:code` 标签
|
||||
- **THEN** 解析出的任务 SHALL 包含 `priority: "high"` 和 `type: "code"`
|
||||
|
||||
### Requirement: Agent matching and assignment
|
||||
Task Router SHALL 根据任务类型、所需能力、Agent 负载和在线状态,将任务分配给最合适的 Agent。
|
||||
|
||||
#### Scenario: Match by capability and load
|
||||
- **WHEN** 一个 `code:typescript` + `review` 类型的任务需要分配
|
||||
- **THEN** Task Router SHALL 选择声明了对应能力、当前并发任务数未达上限、且状态为 `online` 的 Agent
|
||||
|
||||
#### Scenario: No matching agent available
|
||||
- **WHEN** 没有在线 Agent 满足任务所需能力
|
||||
- **THEN** 任务 SHALL 进入 `queued` 状态,Task Router SHALL 通过 Matrix 通知人工介入
|
||||
|
||||
### Requirement: Task lifecycle management
|
||||
任务 SHALL 具有明确的生命周期状态:`created` → `assigned` → `running` → `completed` / `failed` / `agent_lost`。
|
||||
|
||||
#### Scenario: Task completes successfully
|
||||
- **WHEN** Agent 通过 receipt 协议报告任务完成
|
||||
- **THEN** 任务状态 SHALL 变更为 `completed`,Issue 标签 SHALL 更新为 `status:done`
|
||||
|
||||
#### Scenario: Task fails with error
|
||||
- **WHEN** Agent 报告任务失败,附带错误信息
|
||||
- **THEN** 任务状态 SHALL 变更为 `failed`,Issue comment SHALL 写入错误摘要,Task Router SHALL 根据策略决定重试或升级
|
||||
|
||||
### Requirement: Manual task assignment
|
||||
人类 SHALL 能通过 Matrix slash command 或 Forgejo Issue comment 手动指定任务分配给特定 Agent。
|
||||
|
||||
#### Scenario: Manual assignment via Matrix
|
||||
- **WHEN** 人类在 Matrix 发送 `/assign @worker-03 issue#42`
|
||||
- **THEN** Task Router SHALL 将 Issue #42 分配给 agent_id 为 `worker-03` 的 Agent,无论自动匹配结果
|
||||
|
||||
#### Scenario: Manual assignment via Issue comment
|
||||
- **WHEN** 人类在 Issue #42 评论 `/assign worker-03`
|
||||
- **THEN** 效果同上
|
||||
82
openspec/changes/agent-fleet-platform/tasks.md
Normal file
82
openspec/changes/agent-fleet-platform/tasks.md
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
## 1. 项目脚手架与基础设施
|
||||
|
||||
- [ ] 1.1 初始化 Node.js 项目:package.json、tsconfig.json、ESLint、Vitest
|
||||
- [ ] 1.2 搭建项目目录结构:src/core、src/adapters、src/integrations、src/api
|
||||
- [ ] 1.3 部署 Forgejo 实例(WSL2 或 Docker),创建初始 repo 和 webhook token
|
||||
- [ ] 1.4 配置 Matrix bot 账号(复用现有 @jeeves:0x08.org 或新建专用 bot)
|
||||
- [ ] 1.5 编写 config.toml schema 和示例配置文件
|
||||
|
||||
## 2. Orchestrator Core
|
||||
|
||||
- [ ] 2.1 实现数据模型:Agent、Task、Receipt、Artifact、TaskEvent 类型定义
|
||||
- [ ] 2.2 实现 Event Store:SQLite append-only event log,写入和查询接口
|
||||
- [ ] 2.3 实现 Task 状态机:created → assigned → running → completed/failed/agent_lost/cancelled
|
||||
- [ ] 2.4 实现全局任务队列:按优先级排序,支持入队/出队/重新入队
|
||||
- [ ] 2.5 实现任务超时检测:定时扫描 running 任务,超时标记为 failed
|
||||
- [ ] 2.6 实现重试策略:可配置 max_retries + 退避间隔,自动重试 transient failure
|
||||
- [ ] 2.7 编写 Orchestrator Core 单元测试
|
||||
|
||||
## 3. Agent Registry
|
||||
|
||||
- [ ] 3.1 实现 `POST /api/v1/agents/register`:Agent 注册,支持重复注册更新
|
||||
- [ ] 3.2 实现 `POST /api/v1/agents/heartbeat`:心跳更新,记录 last_heartbeat_at
|
||||
- [ ] 3.3 实现 `POST /api/v1/agents/deregister`:注销,重新入队该 Agent 的 running 任务
|
||||
- [ ] 3.4 实现 `GET /api/v1/agents`:查询 Agent 列表,支持 capability 和 status 过滤
|
||||
- [ ] 3.5 实现心跳超时检测:后台定时扫描,3 次超时标记 offline,触发 agent_lost
|
||||
- [ ] 3.6 编写 Agent Registry 单元测试
|
||||
|
||||
## 4. Forgejo Integration
|
||||
|
||||
- [ ] 4.1 实现 Forgejo API client:Issue CRUD、Comment、Label、PR、Webhook 验证
|
||||
- [ ] 4.2 实现 `POST /api/v1/webhooks/forgejo`:接收 Forgejo webhook,验证签名,解析事件
|
||||
- [ ] 4.3 实现 Issue → Task 转换:解析 label 推断 type/priority,创建 Task 对象
|
||||
- [ ] 4.4 实现 Task 状态 → Issue label 同步:status:todo/doing/done,assignee 更新
|
||||
- [ ] 4.5 实现 Receipt → Issue comment 回写:结构化 comment(emoji + summary + artifact links)
|
||||
- [ ] 4.6 实现 Reconciliation(对账):定期轮询 Forgejo Issue,弥补 webhook 丢失
|
||||
- [ ] 4.7 编写 Forgejo Integration 单元测试和集成测试
|
||||
|
||||
## 5. Matrix ChatOps
|
||||
|
||||
- [ ] 5.1 实现 Matrix bot 连接:使用 matrix-bot-sdk,连接 0x08.org homeserver
|
||||
- [ ] 5.2 实现 `/fleet status` slash command:展示所有 Agent 状态
|
||||
- [ ] 5.3 实现 `/assign <agent> <issue>` slash command:手动分配任务
|
||||
- [ ] 5.4 实现 `/retry <issue>` slash command:重新入队失败任务
|
||||
- [ ] 5.5 实现通知推送:task assigned、completed、failed、agent offline 等事件推送到协同房间
|
||||
- [ ] 5.6 实现 per-agent thread:每个 Agent 的执行日志发到独立 thread/topic
|
||||
- [ ] 5.7 编写 Matrix ChatOps 单元测试
|
||||
|
||||
## 6. Receipt Protocol
|
||||
|
||||
- [ ] 6.1 实现 `POST /api/v1/receipts`:接收 Agent 提交的 receipt
|
||||
- [ ] 6.2 实现 receipt validation:验证 PR 是否存在(Forgejo API 查询)、commit 是否包含修改
|
||||
- [ ] 6.3 实现 no-trust 检查:任务只在 receipt 验证通过后才变更为 completed
|
||||
- [ ] 6.4 编写 Receipt Protocol 单元测试
|
||||
|
||||
## 7. Agent Adapter Interface
|
||||
|
||||
- [ ] 7.1 定义 adapter interface TypeScript 类型:register/heartbeat/execute/submit_receipt/deregister
|
||||
- [ ] 7.2 实现 adapter 配置加载:从 config.toml 读取各 Agent 实例的 adapter 类型和参数
|
||||
- [ ] 7.3 实现 adapter health check:CLI 检查、API 可达性检查
|
||||
- [ ] 7.4 实现 adapter runner:管理 adapter 生命周期(启动、心跳、停止)
|
||||
|
||||
## 8. Claude Code Adapter(第一个具体实现)
|
||||
|
||||
- [ ] 8.1 实现 Claude Code adapter:spawn `claude -p --output-format json`,注入 task prompt
|
||||
- [ ] 8.2 解析 Claude Code JSON 输出为 receipt(提取 PR、文件修改、summary)
|
||||
- [ ] 8.3 实现 workspace 管理:为每个任务创建/复用 git worktree
|
||||
- [ ] 8.4 编写 Claude Code adapter 集成测试
|
||||
|
||||
## 9. Codex CLI Adapter(第二个具体实现)
|
||||
|
||||
- [ ] 9.1 实现 Codex adapter:spawn `codex exec --json`,注入 task prompt
|
||||
- [ ] 9.2 解析 Codex JSON 输出为 receipt
|
||||
- [ ] 9.3 实现 Codex session resume(可选)
|
||||
- [ ] 9.4 编写 Codex adapter 集成测试
|
||||
|
||||
## 10. 端到端验证
|
||||
|
||||
- [ ] 10.1 部署完整系统:Forgejo + Orchestrator + Matrix bot + 1 个 Claude Code Agent
|
||||
- [ ] 10.2 端到端测试:创建 Issue → webhook → 任务创建 → Agent 分配 → 执行 → Receipt → Issue comment → Matrix 通知
|
||||
- [ ] 10.3 端到端测试:Agent 离线 → 心跳超时 → 任务 agent_lost → 重新入队
|
||||
- [ ] 10.4 端到端测试:任务超时 → 自动 failed → Matrix 通知
|
||||
- [ ] 10.5 编写运维文档:部署、配置、排障
|
||||
Loading…
Add table
Add a link
Reference in a new issue