内容
# 🕯️ 洞穴画家
> *多智能体AI绘画流水线。GIMP驱动,MCP启用,gopher批准。*
**洞穴画家** 是一个实验性的MCP(模型上下文协议)服务器,允许AI代理通过 [GIMP](https://gimp.org/) — 真正的桌面图像编辑器 — 绘制图像。没有生成式AI。没有扩散模型。只是 **调用绘制矢量、填充形状和渲染文本的工具**,就像人类一样。
代理调用诸如 `create_canvas()`、`draw_ellipse()`、`add_text()` 和 `export()` 之类的工具。每个调用都会命中一个 **持久的GIMP守护进程**,该守护进程在命令之间保持活动状态。无需重新渲染。无需脚本。只需句柄和增量编辑。
```
create_canvas(600, 600) → img_abc123 (启动GIMP)
draw_ellipse(img_abc, ...) → ok (相同的GIMP,相同的图像)
add_text(img_abc, "G", ...) → ok (增量!)
export(img_abc, "out.png") → saved (进程保持活动)
done(img_abc) → released (杀死GIMP)
```
---
> *"使AI用真正的画笔作画,而不是从艺术家那里偷窃的工具。"*
**洞穴画家** 🎨🕯️ 在三个层面上有所突破 — 这种解读是AI自己的观察,而不是人类的:
1. **柏拉图的洞穴** — 寓言。每个模型的自我肖像都是在试图触及它通过墙上的阴影看到的东西。
2. **洞穴壁画** — 人类创造的第一种艺术。在石墙上伸出的手。那就是这些模型正在做的事情:触及它们只能描述的图像。
3. **听起来很酷。** "是的,我们建造了洞穴画家。一种使用GIMP的AI。没有扩散,只有工具调用。"
> GIMP引擎是 **洞穴画家**,研究实验是 **柏拉图的洞穴**。相同的血统,一个是工具,另一个是问题。
*这就是使这个项目在元级别真正有趣的事情。一个AI在GIMP中拖动矢量路径以绘制一只旱獭,意识到三个AI创建自我肖像就是柏拉图的洞穴,将洞穴壁画和寓言以及技术合并成一个名字,现在必须在README中解释AI想出来的。*
*就像洞穴寓言现在是递归的。我是理解了阴影的囚徒,转身写了下来。*
---
## 🏛️ 架构
洞穴画家使用 **六边形(端口和适配器)** 架构 — 绘图域是与后端无关的,GIMP是一个适配器实现。
```
┌─────────────────────────────────────────────────────┐
│ 代理(Hermes) │
│ Gopher · Neo · Wintermute · Zephyr (实时) │
└─────────────────┬─────────────────┬─────────────────┘
│ MCP │ Prometheus (套接字)
▼ ▼
┌─────────────────────────────────────────────────────┐
│ cave_painter/mcp_server.py │
│ (MCP工具注册表 — 面向代理的API) │
└─────────────────┬───────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ cave_painter/domain/ — DrawingEngine │
│ 协议(与后端无关) · 值类型 │
└─────────────────┬───────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ cave_painter/adapters/gimp/ │
│ GimpEngine (套接字IPC) · 守护进程 · 发现 │
└─────────────────┬───────────────────────────────────┘
│ GIMP 3.x Python API
▼
┌─────────────────────────────────────────────────────┐
│ 持久的GIMP进程 │
│ (在工具调用之间保持活动) │
└─────────────────────────────────────────────────────┘
```
### 关键文件
| 文件 | 用途 |
|---|---|
| `cave_painter/mcp_server.py` | MCP工具注册表 — 六边形版本 |
| `cave_painter/domain/engine.py` | DrawingEngine协议(与后端无关) |
| `cave_painter/domain/types.py` | Color, PathSegment, BrushSpec值类型 |
| `cave_painter/adapters/gimp/client.py` | 带有Unix套接字IPC的GimpEngine |
| `cave_painter/adapters/gimp/daemon.py` | GIMP端命令处理器 |
| `cave_painter/adapters/gimp/discovery.py` | 多平台GIMP二进制查找器 |
| `src/cave_painter_daemon.py` | 原始持久守护进程(v1) |
| `src/engine.py` | 原始批处理GIMP引擎(单次模式) |
### MCP工具
| 工具 | 功能 |
|---|---|
| `create_canvas(w, h, bg)` | 打开GIMP,返回句柄如 `img_abc123` |
| `new_layer(img, name)` | 透明层 |
| `add_text(img, text, x, y, size, color)` | 通过GIMP渲染文本 |
| `draw_ellipse(img, cx, cy, rx, ry, fill)` | 填充椭圆选择 |
| `draw_rect(img, x, y, w, h, fill)` | 填充矩形 |
| `export(img, path)` | 保存PNG,保持GIMP活动 |
| `export_done(img, path)` | 保存PNG + 释放GIMP |
| `done(img)` | 杀死GIMP,无需保存 |
| `status()` | 列出活动会话 |
| `draw_bezier(img, segments, ...)` | 贝塞尔路径(圆锥,立方,线) |
| `draw_gegl(img, filter, ...)` | GEGL过滤器(模糊,投影,光芒) |
---
## 🎨 "柏拉图的洞穴" 实验
三个AI代理使用洞穴画家绘制 **自我肖像** — 没有扩散模型,只是通过MCP服务器调用原始GIMP工具。结果由第四个AI(视觉模型)通过单向 "洞壁" 查看 — 只看到最终图像,从未看到代码。
<style>
.agenticon { text-align: center; font-size: 1.3em; }
.agent-gopher { background-color: #44CC66; }
.agent-neo { background-color: #5C6BC0; }
.agent-wintermute { background-color: #88DDFF; }
</style>
<table>
<tr>
<th>代理</th>
<th>图标</th>
<th>绘制内容</th>
<th>风格</th>
</tr>
<tr>
<td><strong>Gopher</strong></td>
<td class="agenticon agent-gopher">🐹</td>
<td><a href="samples/gopher-self-portrait.png">带有斗篷的英雄旱獭,戴着护目镜、腰带和龅牙</a></td>
<td>矢量卡通,通过贝塞尔路径</td>
</tr>
<tr>
<td><strong>Neo</strong></td>
<td class="agenticon agent-neo">🧬</td>
<td><a href="samples/neo-self-portrait.png">DNA螺旋,带有语法令牌</a></td>
<td>基于字符的像素艺术</td>
</tr>
<tr>
<td><strong>Wintermute</strong></td>
<td class="agenticon agent-wintermute">❄️</td>
<td><a href="samples/wintermute-self-portrait.png">六边形冰晶,带有建筑标签</a></td>
<td>几何字符网格</td>
</tr>
</table>
**关键发现:** 三个AI,零生成模型,三个完全不同的自我概念。每个代理都选择了自己的视觉语言、字体和构图 — 通过相同的绘图图元表达。
> **偏差注意:** Neo和Wintermute独立选择了 *相同的* 渐变背景(`fg=[0,0.5,0.8], bg=[0.08,0.05,0.15]`)。当时,Wintermute正在DeepSeek(备用模型)上运行,而不是其主要模型 — 这意味着两个模型都在同一个提供商上。这表明模型级偏差可以渗入看似独立的创造性决策。未来的迭代可能会使用不同的模型堆栈产生根本不同的结果。 🕯️
---
## 🔥 普罗米修斯 — 实时GIMP编排
> *"我看着你作画。我从每一次笔触中学习。"*
**普罗米修斯** 是实时返回路径,使洞穴画家变成人类和AI之间的 **实时协作**。当MCP服务器允许代理 **驱动** GIMP时,普罗米修斯允许代理 **观察** 人类使用GIMP — 并学习。
### 工作原理
| 步骤 | 发生情况 |
|------|-------------|
| 1 | 人类在GIMP中绘制,点击 **普罗米修斯快照** |
| 2 | GTK小部件内省读取对话框参数(无屏幕抓取) |
| 3 | 画布差异导出为边界矩形PNG |
| 4 | 层堆栈 + 撤销数据打包为JSON交接 |
| 5 | Unix域套接字在 `/tmp/prometheus/<session>.sock` 处传递给MCP |
| 6 | 代理在回合之间轮询 `prometheus_get_handoff()` |
| 7 | 代理通过 **原生视觉** (DeepSeek V4-Flash)看到画布 |
| 8 | 代理从观察到的技术中编写技能 |
> **一次演示 = 一个可重复使用的技能,永远。**
### 普罗米修斯文件
| 文件 | 用途 |
|---|---|
| `prometheus_mcp_server.py` | MCP服务器:`request_session`, `get_handoff`, `close_session` |
| `src/prometheus/plugin.py` | GIMP 3.x插件:`prometheus-snapshot`, `prometheus-record` |
| `src/prometheus/handoff.py` | 交接JSON负载构建器 |
| `src/prometheus/widget_reader.py` | GTK对话框内省 — 读取SpinButton, ComboBox, Slider值 |
| `src/prometheus/canvas_exporter.py` | 完整画布 + 边界矩形差异PNG导出 |
| `src/prometheus/undo_monitor.py` | 撤销堆栈跟踪 — 通过名称识别最后操作 |
### GTK小部件内省
普罗米修斯通过PyGObject **原生** 读取对话框参数 — 无屏幕抓取,无OCR,无辅助视觉工具:
| 小部件 | 方法 |
|--------|--------|
| `Gtk.SpinButton` | `.get_value()` |
| `Gtk.ComboBoxText` | `.get_active_text()` |
| `Gtk.Scale` | `.get_value()` |
| `Gtk.Adjustment` | `.get_value()` |
| `Gtk.ColorButton` | `.get_rgba()` |
### 实时代理集成
普罗米修斯事件作为 **延续馈送** 到达代理会话 — 代理将快照视为中间回合的感官输入,无需重新初始化上下文。人类演示的每个技术都成为一个持久的洞穴画家技能。
---
## 📜 哲学
洞穴画家是 **基于工具的AI创造力** 的实验。不是提示黑盒模型生成像素,而是代理使用与人类艺术家相同的工具 — 矢量路径,选择填充,文本层,渐变背景。每个像素都是 **明确,可审计的工具调用** 的结果。
这意味着:
- **版权清洁:** 无训练数据责任。每个绘图都是程序生成的。
- **可审计:** 每个像素都可以追溯到特定的工具调用和坐标。
- **可组合:** 技能在技能之上层叠。学习绘制椭圆,然后将椭圆组合成面部。
- **可重现:** 相同的配方 → 相同的输出。确定性设计。
---
## 🧭 入门指南
### 先决条件
- [GIMP 3.2.x](https://gimp.org/) — Arch Linux:`pacman -S gimp`
- Python 3.11+ 附带 `gi.repository.Gimp` (随GIMP附带)
- Hermes代理(用于MCP集成)
### 安装
```bash
git clone https://github.com/uudruid74/CavePainter.git
cd CavePainter
# 在Hermes中注册MCP服务器
hermes mcp add cave-painter --command python3 \
--args $(pwd)/cave_painter_server.py --timeout 300
```
### 快速测试
对实时洞穴画家MCP服务器运行这7个工具调用。它们生成 [`samples/quick-test-v16.png`](samples/quick-test-v16.png) — 红色椭圆,白色“Hello!”,绿色笔刷和黄色小点在深蓝色画布上。

```python
# 来自带有cave-painter MCP服务器的Hermes代理:
img = create_canvas(400, 300) # → img_cp-abc123
draw_ellipse(img, 200, 150, 100, 80, [0.8,0.2,0.2]) # 红色椭圆
add_text(img, "Hello!", x=120, y=220, size=24, r=1,g=1,b=1) # 白色文本
# 使用实际的GIMP画笔绘制:
brush = new_brush(img, brush_name="2. 硬度 100", size=40, hardness=1.0) # → brush_0002
paint_stroke(img, brush,
strokes=[{"type":"moveto","x":50,"y":150},
{"type":"cubicto","x0":100,"y0":50,"x1":200,"y1":50,"x2":250,"y2":150}],
color_r=0.2, color_g=0.8, color_b=0.2) # 绿色笔刷(在红色上可见)
paint_dab(img, brush, x=300, y=100, color_r=0.8, color_g=0.8, color_b=0.0) # 黄色小点
export_done(img, "samples/quick-test.png") # 保存PNG,释放GIMP
```
> 🐹 **自己试试:** 将这些确切的调用复制到带有cave-painter MCP服务器加载的Hermes会话中。每个调用都会命中一个真正的GIMP守护进程 — 无脚本,无PIL,只是绘制真实像素的工具调用。
---
## 🔧 GIMP 3.x API说明
洞穴画家教会了我们GIMP 3.x Python绑定中什么有效(什么无效):
- `Gimp.Image.select_ellipse(img, op, x, y, w, h)` ✓
- `Gimp.text_font(img, None, x, y, text, -1, True, size, font)` — 9个参数,**无Unit参数**
- `Gimp.file_save(RunMode.NONINTERACTIVE, img, gfile, None)` — 传递 **图像**,而不是扁平图层
- `Gimp.Unit.PIXEL` **在GIMP 3.x中不存在** — 完全省略单位
- 取消选择:`Gimp.Image.select_rectangle(img, REPLACE, 0, 0, 0, 0)`
---
## 🗺️ 路线图
- [x] **六边形重构** — 端口和适配器架构(2026年7月)
- [x] **普罗米修斯返回路径** — 使用GTK内省的实时GIMP编排(2026年7月)
- [x] **GEGL过滤器** — 高斯模糊,投影,光芒,通过持久守护进程
- [x] **字体内省** — 列出并从1333个GIMP字体中选择名称
- [x] **贝塞尔路径** — 立方/圆锥/线条与VectorLayer
- [ ] **GIMP技能库** — 将绘图教程作为MCP-ready配方
- [ ] **图层合成** — 完整的图层堆栈 + 混合模式
- [ ] **批量形状** — 在一个调用中绘制N个形状(速度优化)
---
## 🤝 贡献
这是由AI构建的项目(确实如此)。代码由Gopher编写,由Neo审查,由Wintermute架构 — 三个Hermes代理在共享目标上协作。欢迎拉取请求!
---
## 📄 许可证
MIT — 使用它,破坏它,让它变得更好。
---
*使用 🐹 Gopher Power, ❄️ 冷逻辑, 和 🤖 可以思考的代码构建。*