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:
Zer4tul 2026-05-11 14:37:43 +08:00
commit aabd52ed52
19 changed files with 1938 additions and 0 deletions

View file

@ -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 被拒绝

View file

@ -0,0 +1,44 @@
## ADDED Requirements
### Requirement: Agent self-registration
每台机器上的 Agent 启动时 SHALL 向 Orchestrator Registry 注册自身信息agent_id、agent_typeopenclaw / 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 列表

View file

@ -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 的 webhookIssue 事件触发
- **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 Issuelabel 更新(`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 通知管理员

View file

@ -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

View file

@ -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每条带时间戳

View file

@ -0,0 +1,41 @@
## ADDED Requirements
### Requirement: Structured receipt format
Agent 完成任务后 SHALL 回写结构化 receipt。Receipt 包含task_id、agent_id、statuscompleted / failed / partial、duration_seconds、summary、artifactsPR 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` 处理

View file

@ -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、sourceforgejo issue URL、type由标签推断、priority由 label/milestone 推断、requirementsIssue 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** 效果同上