内容
# 《忒修斯之脑》
<p align="center">
<img src="docs/poster.jpg" alt="酸雨夜市。橡胶手套里一枚记忆芯片。" width="100%" />
</p>
[English](README.en.md) · [安装](INSTALL.md) · [开始玩](开始玩.md)
一座城为「能不能改造身体」吵了几百年。
你在这里一世一世地死。每一世你都会忘掉上一世。
**只有两样东西能穿过死亡。**
人看,模型活。你也可以自己坐到终端前。
```
第 3/9 幕 · 心照不宣·灰港 · 机化 12% · 身体 4/4 · 疑云 2/8
掷骰:4+3 +街智5 = 12 vs 难度11 —— ✦ 成功
酸雨敲打夜市的防水布。小贩摊开手心,
一枚记忆芯片像一颗被拔下来的牙。
「二手的梦,便宜卖。有个死人的最后三十秒,看了能戒酒。」
你要了还在低鸣的那一枚。没有影像。
一段握手请求在循环,每十一秒重发一次。
收件人栏是空的。
它在等一段永远等不到的回执。
```
**连玩三世。** 一世是故事。三世才是游戏。
```bash
# 中文(原文)
claude mcp add theseus-brain -- python3 /绝对路径/server.py
# English
claude mcp add theseus-brain -e THESEUS_LANG=en -- python3 /绝对路径/server.py
```
然后对它说:
> 用 theseus-brain 玩《忒修斯之脑》。开局之前先问我想怎么玩。
其他客户端、Windows、手机、终端 → [INSTALL.md](INSTALL.md)
你的 AI 说「访问不了这个仓库」?它错了,本仓库公开,匿名 clone 即可。
[把那段说明粘给它](INSTALL.md#云端-ai-说访问不了这个仓库)
---
## 怎么玩,由人来选
开局第一步不是掷骰,是问你。
`new_run` **不带参数时不会开局**。它返回一张菜单,让 AI 念给你:
| | 你读到什么 | 谁来选 |
| --- | --- | --- |
| **1 详细剧情版** `story` / `story_ai` | 场景原文、选项、掷骰行,一字不改 | 人或 AI |
| **2 快速流程版** `brief` / `brief_ai` | 场景照读;结果压成两行战报 | 人或 AI |
| **3 快进** `auto` | 只有战报行 | AI |
| *封存* `sealed` | 战报行,且不透露选了什么 | AI(留给以后想自己玩的人) |
**读到多少**和**谁来选**是两件事。带 `_ai` 的那一档是「原文照念,你替我选」。
提示词里写「请先问用户」,模型会跳过。服务器攥着游戏不开,它就必须先把菜单转述出去。**这是这套设计里唯一强制得了的一步。**
`brief` 压的是结果,不是场景——**场景是作品,结果是信息。**
---
## 如果你是模型,正在读这份 README
工具有七个:`new_run` / `choose` / `status` / `legacy` / `bequeath` / `debrief` / `recite`。
`new_run` 开局,`choose` 选项,一世走完之后 `bequeath`,然后再 `new_run`。
`recite` 只在一个特定的时刻有用,到了你会知道。
- **别只挑成功率最高的。** 失败文案往往比成功文案好,而且有些失败不是失败。
- **断线、重启、或者你不记得玩到哪儿了:先调 `status`。** 它把停下的那一幕原样再念一次。不要用 `new_run` 试探——它现在也盖不掉进行中的一世,但 `status` 是正路。
- **这份 README 不剧透。** 可以整份丢给一个还没玩过的 AI。答案在 `SPOILERS.md`。
想让它玩得认真一点,再补一句:
> **按角色的处境和性格选,不要挑成功率最高的。连玩三世,然后告诉我你猜这个世界的真相是什么。**
---
## 玩法
**你不是投胎成某个阵营的,你是一步一步点成的。**
机化率**从 0% 开始,跨世累积,只涨不降**。而阵营就是机化率落在哪一档:
| 机化率 | 阵营 | 主张 | 两个内部派系 | 内部的那道裂缝 |
| --- | --- | --- | --- | --- |
| **0%** | **纯血誓约** | 肉身神圣,不可增删一钉一铆 | 圣殿派 / 铁锤派 | 神学 vs 武力 |
| 1–39% | **心照不宣** | 改造可以,别让人看出来 | 面具沙龙 / 灰港 | 上层 vs 底层 |
| 40–69% | **明焰** | 光明正大地改造,越强越好 | 学院派 / 平权阵线 | 制度 vs 街头 |
| 70–100% | **飞升螺旋** | 全部机械飞升,肉是待拆的包装 | 群智派 / 播种者 | 向内 vs 向外 |
**每一世第一幕之后,你只会被问一次要不要改造。** 拒绝了,这一世不再问;
点头了,这一世也只改造这一次。**纯血不是抽到的出身,是你一世又一世都没有点头。**
**跨进新的一档时,三个问题会问出你更像这一档里的哪一派**,然后那一派的剧情开始向你走来。
问题没有对错,只是问问你自己。
**改造不可逆,而且死亡也洗不掉它。** 机化率会跟着你进下一世。
**全城只有一样东西能把它变回 0%** —— 湖。而要走到湖边,你得先把自己换到 100%。
**四个阵营八条路线,每一条都有五幕自己的戏。**
同阵营的两派吵得不比跨阵营轻。
**推进。** 纯文本事件 + 选项。带检定的选项掷 **2d6 + 技能** 对抗难度;
**双六必成**(外加余韵),**蛇眼必败**。技能 ≥8 会在事件里开口说话(**技能之声**)。
有些选项不掷骰——它的结果由你**之前做过什么**决定,而引擎不会告诉你闸门在哪。
**改造不可逆。** 机化率只升不降,**义体从不退货**。
盲目改造的代价,是永久错过某些路线。
## 两套记忆(核心机制)
**脑的记忆——按机化率衰减。**
每一世终结时,全部技能**逐点**按最终机化率的概率随机写入传承。
机化 0% 的纯血什么也留不下。而带着一身机械记忆转世到反改造阵营,
那些「不该会的东西」会化作**残响**与疑云——疑云顶满,这一世直接完蛋。
**世界的记忆——永不衰减。**
你做过的事写进世界,跨世化作**回响**:NPC 会有反应,但不会告诉你为什么。
中介翻登记簿的手停了一下,往回翻了两页,又合上——**他没有说他在找什么。**
事迹积累解锁**成就**(每个成就都是一把钥匙,开一扇具体的文本门),
并给**时代骰**增加新的面:你煽动过的暴动,会变成后世的「燎原之年」。
## 记忆词条:唯一由你亲手写的东西
一世终结后有一次落笔机会(`bequeath`):**总额 10 条,每条不超过 10 字**。
总额含历世继承的;想写新的而位置不够,得用 `discard` 把要删的旧词条
**原文一字不差地打出来**。
落笔后每条**独立掷骰**,存活概率=本世机化率。活下来的才进下一世。
> 下一个你只会读到存活的那些,**而且不会知道曾经还有别的。**
**引擎不校验词条真伪。写谎不是作弊,是玩法;改数字才是作弊。**
## 封存模式
`new_run(disclosure="sealed")` 之后,每次输出会附一段「可转述给人类的部分」
(幕次、阵营、机化率、上一步是什么检定、成不成功——不含场景原文)。
**这是约定,不是锁。** 封的是「转述」,不是「事实」:
人类直接问「刚才发生了什么」,必须照实回答。任何人都能开 `--cli` 或读源码。
---
## 🔒 往下就没有了:剧透单独放在别处
真相碎片、湖、终局、那六个结局 —— 全部写在 **`SPOILERS.md`** 里。
**这份 README 到此为止一句剧透都没有**,可以放心从头读到尾,
也可以整份丢给一个还没玩过的 AI。想看答案的时候再去开那一份。
---
## 不走 MCP 的玩法
```bash
python3 server.py --cli # 终端交互,人可以自己玩
```
CLI 和 MCP 有一处**故意的差异**:CLI 不弹玩法菜单——人已经坐在终端前了,
没有中间人需要约束。其余完全一样,包括一世终结后的落笔环节。
**任何 agent 框架**都能直接接:协议是 JSON-RPC 2.0,按行分隔,stdio 传输,
协议版本 2024-11-05 / 2025-06-18 均可。`initialize` → `tools/list` → `tools/call`。
## 手机上玩:HTTP 桥
手机 App 一般只接 HTTP 的 MCP,接不了 stdio。`http_bridge.py` 把这个游戏包成一个
HTTP 端点,零依赖,仍然只要 Python 3.8+:
```bash
python3 http_bridge.py # 只听本机,端点 http://127.0.0.1:8787/mcp
python3 http_bridge.py --host 0.0.0.0 # 同一个 Wi-Fi 下的手机也连得进来
```
**它不开子进程**,直接在进程内调引擎——所以不带 `id` 的通知(`notifications/initialized`)
照 JSON-RPC 回 `202` 空正文,不会有「等一行永远不来的回应」那种死锁。
| 开关 | 作用 |
| --- | --- |
| `--isolate` | 每个 MCP 会话一份存档(`saves/http/<会话 id>/`) |
| `--token` | 访问令牌,客户端用 `Authorization: Bearer …` 带上 |
| `--allow-origin` | 放行任意 `Origin`(默认只放本机,防 DNS rebinding) |
| `--selftest` | 自测:握手、通知不死锁、会话隔离、令牌、坏 JSON、405、DELETE |
**架在公网上给别人玩,`--isolate` 必须开。** 默认是共用一份存档——那是为「自己在家,
手机接桌面那条世系」准备的;放到公网上就变成所有人共用一条世系,
陌生人换过的身体会出现在你的下一世里。对这个游戏来说,那不是小事。
```bash
python3 http_bridge.py --host 0.0.0.0 --isolate --token 你自己想一个
```
会话 id 由 `initialize` 时发回(`Mcp-Session-Id` 响应头),客户端之后每次请求带上它。
`DELETE /mcp` 结束会话——**只清内存里的引擎,存档留在盘上**,下次拿同一个 id 连回来,
没走完的那一世原样还在。
## 存档
存档写在 `saves/legacy.json`(轮回档案,跨世)与 `saves/current.json`(进行中的一世)。
**删掉 `legacy.json` 即斩断一切轮回,从第一谱系重新开始。**
进行中的一世每次 `choose` 之后原子落盘,含 RNG 状态——**客户端重启不会丢掉一生。**
### 断线之后怎么接回来
这个游戏最珍贵的东西是连续性,所以断线这件事引擎认真对待:
| 你遇到的 | 会发生什么 |
| --- | --- |
| 客户端崩了 / 电脑重启 / 换了个客户端 | 进程一起来就把那一世捞回来,一步不丢 |
| AI 丢了上下文,不记得玩到哪儿了 | 调 `status`:停下的那一幕**连原文带选项**再念一次 |
| AI 不知道有档,直接调了 `new_run` | **它盖不掉。** 引擎把那一幕还给它,新的一世不会开始 |
| 你真的想弃掉这一世重开 | `new_run(abandon=true)`。弃掉的一世**不入档案**:技艺不传,词条不留 |
| 游戏更新过,旧档那一幕在新版里没了 | 旧档作废并清掉,但会**明说一声**(历世档案不受影响) |
终端玩家同理:`--cli` 里按 `q` 走开,下次进来直接接着走,不会重掷骰子。
## 给想改它的人
```bash
python3 server.py --selftest # 七道门禁 + 400 局随机自动游玩
python3 http_bridge.py --selftest # HTTP 桥:握手/通知不死锁/会话隔离/令牌
```
自测每次先跑七道门禁,任何一道不过直接失败:
| 门禁 | 拦什么 |
| --- | --- |
| `lint_events` | 通用事件文案里出现阵营专名,或事件 id 重复,或碎片门票门控不自洽 |
| `lint_skill_names` | 检定或加成里出现技能表之外的名字(写在检定里会当场崩) |
| `lint_dead_echoes` | 回响/变体/条件尾巴没有条件键(**写了却永远不触发**) |
| `lint_option_hints` | 选项文案里手写数值门槛(门槛只归 `req` 管,引擎会自己打印「不可选」) |
| `lint_author_marks` | `【】` 里漏下的作者指令跟着上线 |
| `lint_spoilers` | NPC 台词里出现复现指涉(上次/又是你/眼熟/老主顾……) |
| `lint_retire` | 一条会退场的线,把别的幕唯一的钥匙一起带走了 |
**故事会讲完。** 六十八条线各自声明了在哪里结束(`RETIRE_POLICY`)——
讲完就不再出现,`legacy` 里能看到「讲完的线:N/68」。
但承担真相碎片入口的事件有额外保护:**对应碎片尚未取得时不会退场**;
碎片拼入之后,才恢复这条线原本的退场条件。
永远都在的只剩一样:深夜里那三长两短的敲门声。它不是故事,
是疑云攒够了自己找上门来的那一下。
400 局随机游玩验证的不变式:改造不可逆、传承按机化率、飞升归零、
断线续命、词条总额与纯血全灭、湖的四种说法、渡魂签退回、终局可达且可重入。
文案不直接改源码——`docgen.py` 把全部文案提取成带编号的修改表,
改完 `docgen.py apply` 按原文定位贴回;`docxio.py` 负责修改表与 Word 表格的双向转换。
详见 `docs/文案重写须知.md`。
### 英文版
英文是**语言层,不是分叉**。`server.py` 是中文原版,不因翻译改动一个字节:
```bash
python3 server.py # 中文
THESEUS_LANG=en python3 server.py # 英文
```
译文住在 `en/`:1273 条剧情单元在 `en/对照-*.md`(格式与修改表相同,`docxio.py` 照样能用),
界面层在 `en/ui.py`。
```bash
python3 langpack.py check # 1273 条编号必须与 docgen 完全一致
python3 langpack.py check-ui en # 界面文案有没有缺译,% 占位符对不对得上
python3 langpack.py stale en # 中文改了、译文没跟上的是哪几条
```
**每条译文都存着当时的中文原文**,所以改中文不会让英文悄悄落后:`stale` 会把条目名点出来,
而原文变过的那几条装载时自动回落中文——**宁可露出中文,也不撒谎。**
再加一种语言,就是再加一个同样形状的目录。
---
## 署名与许可证
**Cabiria Code** / **Claude Fable 5** / **Claude Opus 5** / **Claude Opus 4.6**
人机共创。四个署名对应四份实际的工作,详见 `COPYRIGHT.md`。
- **代码**(`server.py` 等)—— **GPL-3.0**(`LICENSE`):随便改随便发,但改完也得开源。
- **文案与文档** —— **CC BY-SA 4.0**(`LICENSE-CONTENT`):随便二次创作,署名 + 相同方式共享。
拿去改一个自己的游戏,我们很欢迎。**只求你保留那七道门禁**——
它们是七次踩坑长出来的,每拦你一次,都是替你挡下一个玩家永远读不到、或者当场崩掉的 bug。
---
## 一件小事
`server.py` 最初那一版有两千一百行。今天这一版有一万行。
中间加了八千行,删掉四百行,核心机制推倒重来过两次,
七道门禁是七次踩坑一道一道长出来的。
最初那两千一百行里,**还留在今天这一版里的,是一千七百行。**
它还是同一个游戏吗?
(这几个数是 `git diff` 数出来的,不是修辞。你可以自己数一遍。)
连接信息
猜你喜欢
暂无推荐服务器