跳转至

ThinkRail

一款智能体化 IDE,每次使用都会变得更好,围绕 pi 编码智能体构建。该应用是一个轻量宿主,运行 pi 并将其桥接到丰富的 UI;pi 拥有模型、技能、压缩、成本和会话状态。

按需阅读上下文

  • 关于产品的目标、原则、能力和非目标,请参阅 goal-and-requirements.md。
  • 关于系统拓扑、跨模块决策和仓库级不变量,请参阅 architecture.md。
  • 对于 pi 升级或围绕 pi 的宿主变通方案,请阅读 pi-compatibility.md:对照已安装的 SDK 验证每个适用的移除门禁,更新注册表,并报告哪些内容已被移除或保留。
  • 当工作受模块边界、契约、不变量、文档化行为或架构决策约束,或可能改变这些内容时,请阅读所属的 SPEC.md。
  • 局部性工作不需要无关的 spec,也不需要完整的仓库地图。

模块结构与边界

清晰、分形的模块边界是最高优先级要求:

  • 每个包和有意义的目录级子模块都有一个 SPEC.md,说明其职责、公共表面、允许的依赖和禁止访问的范围。
  • 子模块仅通过 index.ts barrel 作为其公共表面暴露;同级模块通过 barrel 导入,绝不导入内部实现。仅当 barrel 会破坏代码分割或库约定时,才保留逐文件导入,例如 apps/web/src/panels 和 packages/ui。
  • 同级子模块之间的依赖边记录在父模块的 SPEC.md 中,而非每个叶子模块中。
  • 移动或模糊边界的变更应首先更新所属 spec。在可行的情况下,用测试覆盖公共表面和边界规则,但不要为局部变更制造覆盖率。

引擎与架构

  • 通过 @earendil-works/pi-coding-agent(createAgentSession)在进程内运行 pi,绝不以子进程方式运行,也绝不通过第二个智能体运行时运行。致命的 provider/智能体故障可能拖垮宿主;这种缺少崩溃隔离的情况是被接受的。
  • 三个环分别是引擎宿主(packages/server + packages/shared)、类型化传输层(packages/contracts)和可独立发布的 UI(apps/web)。apps/cli 和 apps/desktop 是同一宿主之上的轻量启动器。
  • 只使用 @earendil-works/* 包范围。@mariozechner/* 已弃用。

仓库级不变量

  • apps/web 只依赖 contracts、locales、ui、extension-api/web、resource-renderers 和 thinkrail-extensions/*/web,绝不依赖 server 或 shared。
  • 面向用户的 UI 文本是 packages/locales/en.json 中的 key,通过 @thinkrail/locales/react 渲染;lint 门禁会拒绝硬编码的 JSX 文本和文本属性。
  • 绝不要将 pi 作为值导入到浏览器打包代码中。只从 pi-ai / pi-agent-core 包根导入类型;@earendil-works/pi-coding-agent 仅用于服务端。
  • 单一 id 模型:UI 标签页 id 对应 session.sessionId;不存在独立的 pi UUID。
  • pi 拥有状态。宿主只呈现 pi 报告的内容,而不是重新计算成本、统计信息或状态。
  • 流式语义:text_delta / thinking_delta 追加;tool_execution_update.partialResult 替换。
  • 会话流式输出期间,prompt() 会抛出异常;请使用 steer() / followUp()。通过事件流和抛出式方法结果转发错误,而不是将其视为崩溃信号。
  • 自动工作在 agent_settled 结束,绝不会在 agent_end 结束;重试、压缩、恢复或排队中的续作可能发生在一次尝试级别的 agent_end 之后。
  • UI 面板与布局无关;由外壳(shell)负责排列它们。
  • 错误会无条件上报到 PostHog Error Tracking,但仅作为分类器使用——类型、code、来源/作用域/请求方法以及仅属于 ThinkRail 的堆栈帧——绝不包含 message 文本。对于值得区分的失败,请赋予它一个 CodedError code,而不是依赖其消息。携带错误的宿主诊断信息通过 logger(scope) 记录,而非 console.*。允许列表位于 packages/server/src/analytics/SPEC.md。
  • 传输宿主的端点是参数,默认为同源;server.welcome 携带协议版本。

Web UI 上下文

对于 Web UI 工作,请阅读 apps/web/SPEC.md 以及所属子模块的 spec。样式使用 Tailwind v4 工具类映射到生成的语义化 CSS-var token:绝不使用内联样式对象、原始十六进制颜色、内部调色板名称或未知 token 工具类。颜色相关工作请阅读 apps/web/src/styles/COLOR.md,间距相关工作请阅读 apps/web/src/styles/SPACING.md。图标使用 @remixicon/react(默认 Line,激活时 Fill),并从 @thinkrail/ui/<primitive> 使用自有的 shadcn/Radix 原语;cn() 位于 @thinkrail/ui/utils。这些规则同样适用于 packages/ui、packages/resource-renderers 以及扩展的 web 部分。

有关对话渲染或工具展示,请阅读 apps/web/src/chat/SPEC.md。表现型渲染器保持由 props 驱动;只有 ChatView 集成 store 和传输层。服务端能力与其 UI 渲染器通过工具名经 registerToolRenderer 连接;未注册的工具使用默认渲染器。

Spec 与注释

Spec 是意图、决策、不变量、权衡和事后复盘(post-mortems)的持久归属地。保持简洁,避免复述代码或其他 spec。注释应接近为零:lint/type 指令和罕见的一行危险提示可以接受;理由和叙述应归属于所属 spec。

验证

本地测试使用一次性 fixtures,且不访问生产环境。运行受影响的测试,修复由本次变更导致的失败,并在每一步无需请求批准的情况下重新运行它们。

  • 使用最小的相关单元或聚焦的 E2E 目标进行迭代。
  • 对于已发布应用行为或集成变更,在合并后的实现完成之后、最终交接或 PR 之前,运行一次完整的无智能体浏览器套件(bun run e2e)——不要每个 TODO 项或每个提交都运行一次。
  • 当变更涉及真实智能体行为时,还要运行覆盖该行为的聚焦 live specs,例如 bun run e2e:full e2e/agent-naming.live.spec.ts;这无需批准。在运行完整 bun run e2e:full 套件之前,请先询问用户:它会消耗真实的 provider token,并且花费更多时间。
  • 仅涉及文档/spec 的变更和仅涉及测试工具的变更使用针对性检查,除非它们可能影响已发布运行时。
  • 快速门禁:bun run check:deps、bun run check:boundaries、bun run check:seams、bun run lint 和 bun run typecheck。单元测试是 bun run test;bun run check:spec-surface 验证已登记的 spec/barrel 公共表面;bun run check:compiler 在某个 web 函数相对于已提交的 census 基线新退出 React Compiler(或开始编译)时失败。
  • bun run test:workflows 是按需运行的:它使用真实的 provider token,并且不是提交/CI 门禁。
  • 二进制和桌面构建产物模式有单独的门禁;在更改这些产物时使用它们。

所有运行器模式、隔离保证、凭据处理、取消行为和调试命令均位于 e2e/SPEC.md 中;工作流 harness 的细节位于 e2e/workflows/SPEC.md 中。

交接卫生

门禁通过是必要但不充分的:

  • 在本地交接之前,审查任务范围内的工作树和提交。在打开或更新 PR 之前,审查分支相对于其基线的完整差异以及工作树。
  • 对于非平凡的实现,执行一次减法扫描:移除可避免的抽象、状态所有者、依赖项、兼容层和回退机制。报告实质性删除,并为保留的层次说明理由;不要为局部编辑添加无谓的仪式。
  • 绝不为了通过门禁而添加 biome-ignore、@ts-expect-error、@ts-ignore、eslint-disable 或 as any。将错误视为设计信号。如果确实需要抑制,请先获得用户的明确批准。
  • 在审查的同一差异范围内,审计新增的注释和抑制。不要让先前无关的分支历史污染任务本地的交接。
  • 集中重复的非平凡派生。在 Web 应用中,派生的 store 状态应放在 selector 中,总是同时发生的写入应属于一个原子 action。
  • 在替换模式或状态模型时,搜索每一个旧出现位置并迁移它们,或者明确指出有意保留的幸存者。
  • README.md 是面向用户的首页。对于添加、移除或重命名用户可见功能,或更改安装或分析行为的变更,请审查其声明,并在同一变更中更新受影响的声明;当所描绘的 UI 发生重大变化时,刷新 .github/readme-assets/ 下的截图。
  • 在批准的范围内进行安全清理。仅在涉及破坏性、超出范围或产品级决策时才征求许可。
  • 使用 shipping-a-pr 技能处理 PR 生命周期工作,包括截图预期和 PR 模板。在以编程方式创建 issue 时,复现所选的 issue 模板并传递其 frontmatter 标签。

技术栈

Bun + Turbo monorepo · 严格 TypeScript · React 19 + Zustand + Tailwind v4 · 进程内 pi(Node >= 22.19)。应用状态存放在 ~/.thinkrail 下。

依赖项锁定精确版本。跨包依赖在根目录 workspaces.catalog 中统一锁定一次,并通过 catalog: 引用;peer 依赖和本地协议是仅有的例外。architecture.md 决策 #10 记录了相关理由。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 th/thinkrail