【免费下载链接】oneshot-gtm
GTM agent for technical founders. Pay-per-result. Two surfaces: terminal CLI + local web dashboard.
oneshot-gtm 是一个面向技术创始人的开源 GTM(Go-To-Market)外联代理,采用Bun + TypeScript Monorepo构建,以本地SQLite 账本(ledger)为唯一数据源,提供终端 CLI 和本地 Web 仪表盘两个界面。本文带你快速看懂它的 Monorepo 工程组织、分层包结构、SQLite 数据层设计,以及"按结果付费、签名回执"的核心理念。
一、Monorepo 总览:Bun + Turbo 的工程底座
oneshot-gtm 是一个典型的 Bun Monorepo 工程,根目录的 package.json 声明了两个关键点:
- 运行时锁定:
engines要求bun >= 1.3.0,packageManager固定为bun@1.3.13。代码直接使用bun:sqlite原生模块,无法在纯 Node 下运行——这是理解它架构的第一块基石。 - 工作区划分:
workspaces.packages覆盖apps/*和packages/*两大目录,并通过catalog字段统一锁定typescript、vitest等共享依赖版本,保证全仓库版本一致。
任务编排交给Turborepo。turbo.json 定义了build、dev、test、typecheck、lint、fmt六类任务:build依赖上游包的^build并缓存dist/**产物,测试则依赖^build且禁用缓存,确保每次都在真实构建产物上跑。常用入口脚本直接写在根package.json:
bun run cli -- --help # 列出全部 CLI 命令 bun run ui # 启动本地仪表盘 http://127.0.0.1:3030 bun --bun run test # 在 Bun 下跑 vitest测试规模:7250 个测试 / 548 个文件
STATUS.md 披露了当前测试总量:7250 个测试分布在 548 个文件中,且声明所有 CLI 命令、play、finder 和仪表盘页面均已覆盖,并对真实 API 做过端到端验证。对新手来说,这意味着你可以放心地阅读任意模块——每个函数几乎都有对应测试作为"活文档"。
二、三个应用面(apps/):CLI、Server、Web
apps/目录下是三个可独立运行的表面,正好对应项目描述中的"Two surfaces + 共享内核":
| 目录 | 职责 | 技术栈 |
|---|---|---|
| apps/cli | 终端命令行入口 | commander 命令分发 |
| apps/server | 本地 Web 服务与调度器 | Bun.serve+ SSE,仅绑定127.0.0.1 |
| apps/web | 本地 Web 仪表盘 | Vite + React + TanStack + Tailwind |
三者共享同一个 SQLite 账本:CLI 和仪表盘读写的是同一份本地数据,切换操作面不会丢失任何状态。README 中的架构简图可以概括为:
apps/cli apps/server apps/web surfaces commander Bun.serve + SSE Vite + React \ | / packages/* core · intel · plays · find · prompts · doctor · shared-types | @oneshot-agent/sdk email · LinkedIn · SMS · voice · research · enrichment · receipts- CLI 层:apps/cli/src/commands/ 下 35 个命令模块,由 dispatch.ts 统一分发。
- Server 层:apps/server/src/api/ 包含 50 个 REST/SSE 路由模块,scheduler.ts 负责后台 finder 轮询调度。
- Web 层:apps/web/src/routes/ 是 14 个页面路由,组件与库代码分别落在
components/(93 个文件)和lib/(74 个文件)。
三、七个核心包(packages/):分层清晰的领域内核
packages/是架构的"腰身",每个包对应一个清晰的领域边界:
- packages/core— 领域核心。账本读写、发送路由、LinkedIn 漏斗、回执、日历、语音等都在这。其中
ledger-*.ts系列文件按业务域拆分成 20 多个模块(队列、回执、节奏、出站、收件箱……),ledger.ts 负责组装,ledger-schema.ts 负责建表与迁移。 - packages/find— "找人"引擎。各种 finder(Show HN、融资、换工作、招聘信号、GitHub star、本地商户、政府采购……)的实现都在这里,源码以
_前缀组织,如 _newsfeed.ts、_contact.ts。 - packages/plays— 62 个 play 模块。一个 play 就是一个"动作":面向谁、发生了什么、首条消息说什么、如何跟进。
- packages/prompts— 纯 Markdown 提示词库,如 reply-email.md、icp-filter.md。提示词即代码,读文档就能看懂每个动作的"灵魂"。
- packages/intel— LLM 调用与报告层(重试、截断、多 provider 适配)。
- packages/doctor— 健康检查(余额、日历、数据库权限、LinkedIn 会话等),对应
bun run cli -- doctor命令。 - packages/shared-types— 跨包共享的 TypeScript 类型契约。
这种"apps 薄、packages 厚"的结构,让每个领域可以独立测试、独立演进——packages/find下的 200+ 个测试文件就是最好的证明。
四、SQLite 账本:为什么选它
oneshot-gtm 最打动人的架构决策是:全部状态都在你磁盘上的一个 SQLite 文件里。
数据文件布局
按 docs/data-storage.md 的官方清单:
| 文件 | 位置 | 内容 |
|---|---|---|
ledger.sqlite | 每个 workspace 主目录 | 回执、prospects、队列、节奏、回复、退信、会议、交易、草稿、触发器、学习提案 |
config.json | 同上 | 你的画像、ICP、voice card 与设置 |
.env | 同上 | 密钥,权限 600 |
events.jsonl | 同上 | 本地事件日志(永不离开本机) |
shared.sqlite | ~/.oneshot-gtm-shared | 跨 workspace 共享的人群、付费查询缓存、联系记录 |
默认 workspace 主目录为~/.oneshot-gtm,可用ONESHOT_GTM_HOME环境变量迁移。代码开源,但你的 prospects、密钥、账本永远不进 Git——docs/repository-boundaries.md 甚至配套了边界测试来防止误提交。
版本化迁移:账本的"时间机器"
ledger-schema.ts 定义了LedgerMigration接口和LEDGER_MIGRATIONS数组:
{ version: 1, name: "baseline", ... } { version: 2, name: "draft-versions-format-key", ... } { version: 3, name: "triggers-company-batch-seq", ... } ...规则非常工程化:schema 版本记录在PRAGMA user_version,打开旧账本时在单个事务内补跑缺失的迁移,崩溃了也不会留下半迁移状态;新版本构建也永远不会降级旧账本。文件头注释还约定了时间戳格式(UTC 文本、跨列比较用julianday())、金额精度(新列用整数 micro-dollars)、外键强制等细节——这些注释本身就是一份优秀的数据字典。
运维友好性
- WAL 模式:数据库运行在 WAL 模式,备份必须用
sqlite3 ... ".backup"而非cp,否则会丢-wal里的未落盘写入。 - 权限加固:macOS/Linux 上每个数据库创建为
0600,打开时自动重置,doctor会警告任何被其他用户可读的数据库。 - 容量治理:
doctor会在旧回执超过 20 MB 时提示,compact-receipts --apply可安全瘦身。
五、"按结果付费"架构:签名回执
项目的核心商业理念是Pay-per-result(按结果付费),这在架构上落为"签名回执(signed receipt)"机制:
- 每一次付费 API 调用(研究、数据补全、邮件、LinkedIn、短信、语音)都会在 OneShot 平台留下签名回执;
- 本地账本保存每个回执的"信封"(id、成本、消息/线程 id),所以单次回复的成本是记录值而非估算值;
- docs/webhooks.md 描述了仅有的两个对外路由——其余全部服务只绑定在
127.0.0.1,单用户、本地优先。
配合本地events.jsonl事件流(每次 LLM 调用、门控决策、finder 事件各记一行,10 MB 自动滚动三代),你可以用tail -F实时审计系统的每个动作:
tail -F ~/.oneshot-gtm/events.jsonl | jq -c 'select(.kind|startswith("llm."))'六、快速上手:从空仓库到第一份草稿
- 安装运行时并克隆仓库:
curl -fsSL https://bun.sh/install | bash git clone https://gitcode.com/gh_mirrors/on/oneshot-gtm cd oneshot-gtm && bun install- 初始化 workspace(画像与密钥均为可选字段)并做健康检查:
bun run cli -- init bun run cli -- doctor- 构建一次仪表盘并启动:
bun run --cwd apps/web build bun run cli -- ui # 打开 http://127.0.0.1:3030不想克隆仓库?直接bunx oneshot-gtm-server就能跑起仪表盘(见 apps/server/README.md)。docs/getting-started.md 则带你走通"描述业务 → 选信号源 → 选 play → 读第一份草稿"的四步路径。
七、给新手的架构要点回顾
| 问题 | oneshot-gtm 的答案 |
|---|---|
| 为什么必须用 Bun? | bun:sqlite原生绑定 + 更快的冷启动,代码在 Node 下直接失败 |
| 状态存哪? | 每个 workspace 一个ledger.sqlite,跨 workspace 共享数据单独存放 |
| 如何保证数据不泄露? | 文件权限 600 + 仓库边界测试 + 事件日志永不出本机 |
| 如何升级不丢数据? | PRAGMA user_version驱动的单事务迁移 |
| 如何控制成本? | 每次付费调用留签名回执,日花费上限config spend-ceiling |
| 新手从哪读代码? | 先读 packages/prompts/ 的提示词,再看 packages/find/ 的信号源 |
一句话总结:oneshot-gtm 用 Bun Monorepo 保证了工程的统一与快速迭代,用 SQLite 账本把"代理系统的所有状态"收敛为一个可备份、可审计、可迁移的本地文件——这正是"本地优先(local-first)+ 按结果付费"架构的完整答卷。
【免费下载链接】oneshot-gtm
GTM agent for technical founders. Pay-per-result. Two surfaces: terminal CLI + local web dashboard.
相关推荐
客户数据只在你自己的硬盘上:oneshot-gtm 本地 SQLite 存储与备份完全指南
客户数据只在你自己的硬盘上:oneshot gtm 本地 SQLite 存储与备份完全指南 ! oneshot gtm 本地数据管理示意图:Run a play
Trigger.dev 仓库架构解析:pnpm + Turborepo Monorepo 全景指南
Trigger.dev 仓库架构解析:pnpm + Turborepo Monorepo 全景指南 本篇指南以 Trigger.dev 开源仓库内部的仓库概览文
AI Agent后端任务调度开发工具可观测性AI 应用OpenBot 架构深潜:Electron + SolidJS + Bun 技术栈全景解析
OpenBot 架构深潜:Electron + SolidJS + Bun 技术栈全景解析 OpenBot 是一个基于 Electron + SolidJS +
桌面应用AI Agent人工智能多智能体代码智能体浏览器控制本地部署MCP 服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考