# pigo 协作 —— 调用文档

> 在 Docker 容器内运行一个 pigo agent（单 agent）完成 /blackboard/task.md 中的任务，工作区为 /blackboard/workspace，完成时通过 blackboard 工具创建 DONE；supervisor 把结果以结构化 JSON（result.json）落盘，供外部调度方直接解析。

---

## 1. 原理与架构

```
                +------------------ docker 容器 pigo-coop ----------------+
                |                                                        |
  TASK/MODEL/   |   +---------- supervisor.sh（单 agent 编排）-------+   |
  API_KEY ──────┼─▶ |  每轮运行一个 pigo 进程：                       |   |
                |   |   └─ agent ──▶ cwd = /blackboard/workspace      |   |
                |   |      (--resume 会话 · 角色 prompt agent.md)      |   |
                |   +──────┬────────────────────────────────----------+   |
                |          ▼                                               |
                |   /blackboard（任务黑板：task.md + workspace + DONE）    |
                +-----------------------------------------------------------+
```

- **单 agent**：每轮一个 pigo 进程串行推进，无评审者；工作区 `/blackboard/workspace` 是普通文件工具（read/write/bash）的根目录。
- **原子完成标记**：`DONE` 只能通过 `blackboard` 工具 `done`（`O_CREATE|O_EXCL`）创建，supervisor 检测到 `DONE` 即收尾。
- **连续上下文**：headless 运行自动持久化会话，supervisor 从 stream-json 首事件提取 `sessionId`，下一轮用 `--resume` 恢复，agent 跨轮记住自己的思考。
- **协议注入**：任务协议（AGENTS.md）副本放入工作区，pigo 自动注入系统提示；角色 prompt 通过 `--append-system-prompt` 注入。
- **结构化结果**：任务结束（成功/未解出/超时/失败）统一写 `$BB/result.json`，字段：`status`、`exit_code`、`summary`、`flag`、`artifacts`。

---

## 2. 前置条件

| 依赖 | 说明 |
| --- | --- |
| Go 工具链 | 版本与 `go.mod` 一致（当前 `go 1.27rc1`），用于交叉编译 pigo 二进制 |
| Docker | 本机已有基础镜像 `pigo-worker:latest`（Alpine，含 bash/git/wget/flock/timeout/CA 证书） |
| 模型后端 | 任意 OpenAI 兼容 API（如 DeepSeek、Ollama、OpenRouter），需可访问的 base-url 与 API key |

---

## 3. 构建

### 3.1 交叉编译 pigo（含 blackboard 工具）

Windows PowerShell：

```powershell
$env:GOOS="linux"; $env:CGO_ENABLED="0"
go build -trimpath -ldflags="-s -w" -o coop/tmp/pigo-linux-amd64 ./cmd/pigo
```

Linux/macOS：

```bash
GOOS=linux CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o coop/tmp/pigo-linux-amd64 ./cmd/pigo
```

产物 `coop/tmp/pigo-linux-amd64` 是纯静态 Linux 二进制（约 30MB）。

### 3.2 构建镜像

```bash
docker build -f coop/Dockerfile -t pigo-coop .
```

> 镜像直接 `FROM pigo-worker:latest`（复用本机已有镜像，不拉取 golang/alpine），只覆盖 pigo 二进制并加入 supervisor 与协作 prompt，构建通常秒级完成。

---

## 4. 环境变量（运行参数）

| 变量 | 必填 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `MODEL` | ✅ | — | 模型名，如 `deepseek-chat` |
| `BASE_URL` | ✅ | — | OpenAI 兼容 API base-url |
| `API_KEY` | ✅ | — | API key |
| `PROTOCOL` | 否 | 按 model 推断 | 协议 `openai` / `anthropic` |
| `TASK` | 二选一 | — | 任务描述；不填则需挂载 `$BB/task.md` |
| `BLACKBOARD` | 否 | `/blackboard` | 黑板根目录（即 `BB`） |
| `PROMPTS` | 否 | `/prompts` | 协作 prompt 目录（镜像内固定，一般不用改） |
| `ROUND_MAX` | 否 | `10` | 最大轮次 |
| `TIMEOUT` | 否 | `600` | 单轮超时秒数，`0`=不超时 |
| `FAIL_MODE` | 否 | `stop` | agent 失败时：`stop`=立即退出（默认）\| `continue`=继续下一轮 |

---

## 5. 运行示例

### 5.1 最小运行（真实模型）

```bash
docker run --rm \
  -e MODEL=deepseek-chat \
  -e BASE_URL=https://api.deepseek.com \
  -e API_KEY=<your-key> \
  -e TASK="请为 XX 编写设计文档并实现原型" \
  -e ROUND_MAX=6 \
  pigo-coop
```

### 5.2 保留黑板产物与连续会话（推荐）

```bash
mkdir -p blackboard
docker run --rm \
  -v $PWD/blackboard:/blackboard \            # 黑板产物落盘
  -v $HOME/.pigo:/root/.pigo \                # 保留 agent 会话（--resume 依赖）
  -e MODEL=deepseek-chat \
  -e BASE_URL=https://api.deepseek.com \
  -e API_KEY=<your-key> \
  -e TASK="..." \
  pigo-coop
```

> 会话持久化在 `~/.pigo/sessions`（容器内为 `/root/.pigo`）。**不挂载 `$HOME` 时，会话只存在于容器生命周期内**——跨 `docker run` 不保留；每次 `run` 内部跨轮仍有效。

### 5.3 结果与退出码

- 任务完成（检测到 `DONE`）：退出码 `0`，`result.json` 的 `status=solved`。
- 达到 `ROUND_MAX` 仍未完成：退出码 `1`，`status=unsolved`，检查黑板与日志。
- 单轮超时被强杀：`status=timeout`（退出码 124）。
- 参数缺失 / 非法：退出码 `2`。

---

## 6. 黑板目录结构

```
/blackboard/
├── task.md            # 任务描述（勿修改）
├── AGENTS.md          # 任务协议（工作区有副本）
├── workspace/         # agent 工作区 = 其 cwd（产物全部在这里）
├── DONE               # 完成标记（只用 blackboard done 创建）
├── result.json        # 结构化结果（supervisor 结束时生成）
├── sessions/          # agent 的 session id（supervisor 内部维护，供 --resume）
└── logs/              # 每轮运行日志：round-N.log
```

---

## 7. blackboard 工具（agent 侧 API）

pigo 在 `BB` 环境变量存在时自动注册 `blackboard` 工具；普通运行不受影响。agent 通过该工具原子读写黑板：

| 操作 | 参数 | 行为 |
| --- | --- | --- |
| `read` | （可选 `path`） | 无 `path`：返回黑板全局快照（task.md、workspace 清单、DONE 状态、环境）；有 `path`：返回黑板内单文件内容（如 `workspace/exploit.py`） |
| `post` | `file`、`content` | 原子追加消息到 `messages/<file>`；`file` 必须是裸 `*.md` 名（防目录穿越），内容 ≤ 32 KiB |
| `done` | `summary` | 原子创建 `DONE`（`O_CREATE|O_EXCL`）；已存在则报错且不覆盖。仅交付完整时调用 |

环境变量 `BB` / `ROUND` / `NAME` 由 supervisor 注入。

---

## 8. 验证与调试

### 8.1 无模型端到端验证（mock）

`coop/tmp/mock_openai.py` 是一个 OpenAI 兼容 mock server，驱动 agent 依次调用 `blackboard done`，用于验证单 agent 编排与 DONE 原子性：

```bash
# 终端 1：启动 mock（本机）
python coop/tmp/mock_openai.py 8899

# 终端 2：运行容器，base-url 指向 mock（按环境替换宿主地址）
docker run --rm \
  -v $PWD/blackboard:/blackboard \
  -e MODEL=mock -e BASE_URL=http://<host-ip>:8899 -e API_KEY=test \
  -e TASK="验证任务" -e ROUND_MAX=3 -e TIMEOUT=120 \
  pigo-coop
```

预期：agent 完成并创建 `DONE`，容器退出 0，`blackboard/result.json` 中 `status=solved`。

### 8.2 查看日志

```bash
# 黑板挂载后：
cat blackboard/logs/round-1.log   # 第 1 轮的 stream-json 事件
cat blackboard/sessions/agent.session  # 下一轮 --resume 用的 session id
```

### 8.3 常见问题

| 现象 | 原因 / 处理 |
| --- | --- |
| 退出码 `2` 且提示缺 MODEL/BASE_URL/API_KEY | 未传必填环境变量 |
| 容器内报 `DONE already exists` | 正常：DONE 幂等，上一次运行已留标记 |
| 跨 run 后 agent 不记得之前轮次 | 未挂载 `$HOME/.pigo`；会话在容器内 `~/.pigo/sessions`，`--rm` 后丢失 |
| `docker build` 报找不到 `pigo-worker:latest` | 先 `docker pull` 或在目标机导入该基础镜像 |
| 构建期 `chmod` 被拒 | 已用 `COPY --chmod=755` 规避（NTFS 挂载构建上下文会丢可执行位） |

---

## 9. 任务协议要点（详见 `/blackboard/AGENTS.md`）

每轮：**读取 task.md → 检查已有产物 → 推进任务 → 完成后用 blackboard done 创建 DONE**。红线：不直接写 DONE；不伪造命令/提交结果；不修改 task.md 与 AGENTS.md。
