Skip to main content
Glama

问题

AI 编码助手是无状态的。每次新会话都从零开始。模型不知道昨天构建了什么、哪里出了问题、做了哪些决策,或者接下来要做什么。开发者用 CLAUDE.md 文件和零散的笔记来弥补,但没有标准结构、没有会话连续性,也没有工具支持。

真正的成本不是浪费的搭建时间,而是重复的错误、反复争论的设计决策、幻觉上下文,以及线性而非复利式的工作。

Related MCP server: AI Conversation Logger

理念

每个项目都会有一个 .story/ 目录,存放 JSON 和 markdown 文件。工单、问题、路线图阶段、会话交接和经验教训都存放在那里,由 git 跟踪,任何 AI 都可读取。

  • CLI: storybloq - 从终端检查和修改 .story/。

  • MCP 服务器: Claude Code 和 Codex 可直接调用的结构化工具,启用本地 Bus 时还有五个额外工具。不产生子进程。

  • 技能: Claude Code 中的 /story 或 Codex 中的 $story 会在每次会话开始时加载项目状态。

  • Mac 应用: 原生侧边栏,监视 .story/ 并在你的 AI 客户端工作时实时更新(独立产品,App Store 免费)。

安装

npm install -g @storybloq/storybloq@latest
storybloq setup --client all

需要 Node.js 20+ 和至少一个 AI 客户端:Claude Code 或 Codex CLI 0.130.0+。包位于 npm 上的 @storybloq/storybloq;发布版本标记在本仓库的 github.com/Storybloq/storybloq/releases。

setup --client all 为 Claude 和 Codex 安装 Storybloq 技能,将此包注册为 MCP 服务器,并配置可用的客户端钩子。重复运行是安全的。Codex 会以信任级别 unknown 报告已安装的钩子;在 Codex 中打开 /hooks 以审查并信任它们。setup-skill 仍作为仅 Claude 安装的兼容别名保留。

升级

npm install -g @storybloq/storybloq@latest
storybloq setup --client all

与全新安装相同的两个命令:@latest 拉取最新版本,重新运行 setup 会刷新 Storybloq 技能文件、重新注册 MCP 服务器,并清除先前安装遗留的过期钩子条目。

当 npm 上有更新版本时,你通常会在下次调用 storybloq 时看到一行横幅:

storybloq v1.2.0 is available (you have v1.1.6).
Update: npm install -g @storybloq/storybloq@latest

CLI 还会在升级后的首次运行时静默刷新技能目录,并迁移任何遗留的钩子条目(例如,来自更名前的 @anthropologies/claudestory 包)——无需手动清理。

通过 Claude Code 插件系统的替代安装方式:参见 Storybloq/plugin-archive(遗留路径;推荐使用 storybloq setup --client all 安装)。

引导项目

cd your-project
storybloq init --name "your-project"

对于多仓库项目,请参阅下面的 联邦。

它会生成以下脚手架:

.story/
├── config.json         project config + recipe overrides
├── roadmap.json        phase ordering + metadata
├── tickets/            T-001.json, T-002.json, ...
├── issues/             ISS-001.json, ISS-002.json, ...
├── notes/              N-001.json, N-002.json, ...
├── lessons/            L-001.json, ...
├── handovers/          YYYY-MM-DD-<slug>.md
└── snapshots/          state snapshots (gitignored)

提交除 .story/snapshots/ 之外的所有内容。

日常使用

在 Claude Code 或 Codex 中:

  • Claude Code 中的 /story 或 Codex 中的 $story - 加载项目状态,读取最新的交接记录,展示未关闭的工单和问题,列出受阻的工作,总结最近的变更。当客户端可以运行后台代理且可操作的积压工作较多时,它还会主动展示编排工作风格(仅作为建议,仍需显式选择加入)。

  • /story auto T-001 T-002 ISS-013 / $story auto T-001 T-002 ISS-013 - 限定于这些条目的自主模式。驱动工单依次经过计划 → 计划审查 → 实现 → 测试 → 代码审查 → 提交,并在每个检查点进行交接。

  • /story review T-001 / $story review T-001 - 对工单的 diff 运行多视角审查(参见 Storybloq/lenses)。

  • /story orchestrate / $story orchestrate - 当客户端暴露精确可调用的工作流/子代理工具时,驱动多仓库(或大型单仓库)积压工作。Codex 使用 multi_agent_v1.spawn_agent、其规范化标识符 multi_agent_v1__spawn_agent 或精确的 spawn_agent 工具。已随附基于 Claude Agent View 的 storybloq dispatch 命令;产品管理的 Codex dispatch 后端尚未提供。

  • /story triage / $story triage - 对未关闭的问题积压进行只读分诊:对照固定的当前 HEAD 验证每条发现,标记已修复和重复的问题,将共享同一已验证根因的问题分组,并推荐一个按优先级排序的工单计划。不修改任何问题和工单。

  • /story bus / $story bus - 轮询一个绑定任务的本地 Bus 端点,使实现者和独立审查者无需复制粘贴即可交换建议性发现。

  • /story handover / $story handover - 写入一份会话交接记录,捕获决策、阻塞项和后续步骤。

两个客户端都支持上下文加载、自主模式、MCP 以及压缩/状态钩子。Codex Desktop 可以打开自主会话的所属任务并向其转发精确的属主响应;Codex CLI 则安全地回退到手动任务切换。自主代码审查默认有 12 轮落地上限(根据工单风险向上调整):未解决的关键发现和拒绝仍会阻塞,而非阻塞性发现在达到上限时变为后续问题。将 recipeOverrides.stages.CODE_REVIEW.maxReviewRounds 设置为 0 可显式禁用该上限。

recipeOverrides.compactThreshold 接受 medium、high(默认)或 critical。该值同时选择压力限制和轮换触发条件:medium 使用较低限制并在中等压力时轮换,而 critical 使用较高限制并等待临界压力。在干净的 COMPLETE 边界处,阈值压力通过 HANDOVER 结束有界会话,因为 Storybloq 无法调用客户端压缩命令。当客户端自行压缩时,PreCompact 和 SessionStart 钩子会保留同一会话;压力仅在 SessionStart 确认 source: compact 后重置。

在 AI 客户端之外,同样的状态只需一次 storybloq 调用即可获取。

用量限制自动恢复

Claude Code 会话会在达到用量限制时停止("你已达到用量限制"),隔夜自主工作也随之悄然终止。Storybloq 通过 Claude Code 的 StopFailure 钩子检测停止,从会话记录中解析重置时间,将停止记录在全局账本(~/.claude/storybloq/limit-ledger.json)中,并在限制重置时恢复会话。安装钩子后默认开启。

  • 自主会话 与压缩一样停放在同一条恢复通道上,并通过完整状态机无头唤醒——所有权重新绑定、git-HEAD 验证和恢复映射全部适用,因此工作区变更后的唤醒是经过验证的,而非盲目重放。在 FINALIZE 中途停止的会话永远不会自动恢复(提交重放未被证明是安全的);你会收到一条包含手动恢复步骤的通知。

  • 普通会话 在重置时会收到桌面通知,包含精确的 claude --resume 命令。按项目选择加入(limitResume.plainMode: "headless")则会改为无头唤醒。

  • 权限姿态永远不会升级。 使用 --dangerously-skip-permissions 运行的会话只有在项目显式选择加入(limitResume.inheritBypass: true)时才会以该标志唤醒;否则只会通知。

唤醒由瞬态分离的唤醒进程驱动,而非守护进程:它每 30 秒轮询一次账本,恢复到期项(有尝试次数上限、错开执行、并发受限),并在没有待处理项时退出。它能挺过笔记本电脑休眠,但无法挺过重启或注销——重启后,任何项目中下一次 storybloq 调用或钩子触发都会重新生成它,因此周级别的等待会在你下次活动时恢复。这就是"无守护进程"的代价。

使用 storybloq limit-status 检查和管理队列(--cancel <key> 销毁待处理的自动恢复,--requeue <key> 重试已停用的记录)。在 ~/.claude/storybloq/config.json 中使用 {"limitResume": {"enabled": false}} 全局禁用,或通过 .story/config.json 中的 limitResume 按项目禁用(还有 maxAttempts、staggerMs、maxConcurrent、notify 等)。

先前工作:检测与重新解析的方法借鉴了 unsnooze(MIT),后者开创了针对 tmux 托管会话的基于记录的用量检测和重置时间解析。Storybloq 的版本去掉了 tmux 层,改用文档化的钩子接口,并通过自己的状态机而非按键来恢复自主会话。

Storybloq Bus

Storybloq Bus 是一个可选的本地协调协议,用于一个实现者任务和一个审查者任务。运行时状态存放在被 git 忽略的 .story/bus/ 下;已确认的发现仍会先成为具有持久来源溯源的标准 Storybloq 问题,然后才作为问题通知发送。

storybloq bus init
storybloq bus join implementer --client codex
storybloq bus join reviewer --client claude
storybloq bus hooks enable --client codex
storybloq bus hooks enable --client claude

Bus 运行时是本地且被 git 忽略的,因此需要在每个将参与的检出中运行一次 storybloq bus init。Status 和 doctor 会将全新检出报告为已启用但未初始化;这种健康的非活动状态不会阻塞提交或自主 FINALIZE。其他 Bus 命令和 MCP 工具绝不会隐式初始化运行时。初始化会拒绝符号链接的忽略文件和否定模式,因为它无法安全地证明 Git 会以其他方式排除完整运行时。

前台协议包括发送、轮询、确认、线程状态、状态、doctor、导出和 ship 检查。消息经过哈希链式连接、幂等、有界、绑定任务、秘密筛查,并通过可崩溃恢复的收件人邮箱投递。关键消息默认需要匹配的未解决关键问题。Bus 文本始终是代理间的建议:它绝不授予属主批准,也不授权合并、推送、签名、部署、凭据、支出或破坏性操作。

V1 不包含守护进程、进程生成、无头恢复或自动离线唤醒作为 Bus 投递路径。自然的 SessionStart/Stop 钩子和显式轮询是投递路径。Codex Desktop 仍不可唤醒。(上面的用量限制自动恢复是 Bus 之外的一个限定例外:其瞬态唤醒器恢复因限制而停止的会话,不是消息投递路径。)

联邦

联邦(Federation)协调跨多个仓库的 AI 代理工作。一个项目成为编排者。它声明哪些仓库(节点)属于该系统的一部分,它们如何相互依赖,以及它们在运行时如何通信。每个节点保留自己的 .story/,包含自己的工单、问题和交接记录。编排者跨所有节点进行读取。

# Create an orchestrator
storybloq init --type orchestrator --name "my-platform"

# Register nodes
storybloq node add api --path ../api --stack typescript --role "REST backend"
storybloq node add web --path ../web --stack nextjs --depends-on api
storybloq node add sdk --path ../sdk --stack typescript

三种关系类型连接节点:

  • dependsOn(节点配置上):构建顺序边。Web 应用依赖 API。

  • links(节点配置上):运行时集成。Web 应用通过 HTTP 调用 API。

  • crossNodeBlockedBy(工单上):一个仓库中的工单被阻塞,直到另一个仓库中的工单完成。示例:"crossNodeBlockedBy": ["api:T-012"]。

从编排者目录:

storybloq status              # aggregated view across all nodes
storybloq recommend           # federation-aware suggestions (bottlenecks, stale nodes, blockers)
storybloq ticket list --node api   # list tickets in the api node without cd-ing

推荐引擎生成特定于联邦的建议:阻塞下游工作的节点、被许多其他节点依赖的瓶颈节点、两周内没有交接的节点。带有 crossNodeBlockedBy 引用的工单在阻塞工单完成之前绝不会出现在推荐中。

CLI 参考

所有命令都接受 --format json|md(默认 md)。将 JSON 通过 jq 管道处理以用于脚本,或直接读取 markdown 变体。

项目

命令

描述

storybloq init [--name] [--type orchestrator] [--force]

搭建 .story/(添加 --type orchestrator 用于多仓库)

storybloq status

项目摘要,包含阶段状态、计数和风险

storybloq validate [--integrity-only]

引用、模式、来源溯源和与加载器无关的 JSON 检查

storybloq setup --client claude|codex|all [--skip-hooks]

安装 Storybloq 技能、注册 MCP 并配置客户端钩子

storybloq setup-skill [--skip-hooks]

storybloq setup --client claude 的兼容别名

storybloq recommend --count N

上下文感知的工作建议

阶段

命令

描述

storybloq phase list

所有阶段及其派生状态(状态从工单计算得出,从不存储)

storybloq phase current

第一个未完成的阶段

storybloq phase tickets --phase <id>

某个阶段的叶子工单

storybloq phase create --id --name --label --description [--summary] --after/--at-start

创建阶段

storybloq phase rename <id> [--name] [--label] [--description] [--summary]

更新阶段元数据

storybloq phase move <id> --after/--at-start

重新排序

storybloq phase delete <id> [--reassign <target>]

删除(重新分配包含的工单)

工单

命令

描述

storybloq ticket list [--status] [--phase] [--type]

列出叶子工单(不包括伞形工单)

storybloq ticket get <id>

完整工单详情

storybloq ticket next

最高优先级的未阻塞工单

storybloq ticket blocked

所有当前被阻塞的工单

storybloq ticket create --title --type --phase [--description] [--blocked-by] [--parent-ticket] [--node <name>]

创建(从编排者使用 --node)

storybloq ticket update <id> [--status] [--title] [--phase] [--cross-node-blocked-by] [--node <name>] ...

更新

storybloq ticket meta get|set|unset <id> [path] [value]

管理自定义直通元数据

storybloq ticket delete <id> [--force]

删除

问题

命令

描述

storybloq issue list [--status] [--severity] [--component] [--phase]

列出问题

storybloq issue get <id>

问题详情

storybloq issue create --title --severity --impact [--components] [--related-tickets] [--location] [--source-ref <json>] [--dedupe-key] [--created-by]

创建,可选的持久审查证据和重试身份

storybloq issue update <id> [--status] [--title] [--severity] [--source-ref <json>] ...

更新

storybloq issue meta get|set|unset <id> [path] [value]

管理自定义直通元数据

storybloq issue delete <id>

删除

笔记和经验教训

命令

描述

storybloq note list · note get · note create · note update

头脑风暴和想法捕捉

storybloq lesson list · lesson get · lesson create · lesson update · lesson reinforce

可复用的模式和反模式

storybloq lesson digest

所有活跃经验教训的紧凑摘要,用于技能注入

交接、阻塞项、快照

命令

描述

storybloq handover list · handover latest · handover get <file>

会话连续性文档

storybloq handover create --title --tldr ...

编写新的交接文档

storybloq blocker list · blocker add · blocker clear

阻塞进度的外部依赖

storybloq snapshot · storybloq recap

捕获状态并与上次快照进行差异比较

storybloq export [--phase <id>] [--all] [--format json|md]

自包含的项目文档

storybloq limit-status [--cancel <key>] [--requeue <key>]

待处理的用量限制自动恢复(跨项目全局)

Storybloq Bus(可选加入)

命令

描述

storybloq bus init

启用本地 Bus 并创建被 git 忽略的运行时状态

storybloq bus join implementer|reviewer [--client] [--replace]

将当前客户端任务绑定到一个独占角色

storybloq bus send ...

创建线程或发送带有必需幂等键的回复

storybloq bus poll

读取任务绑定端点的未确认消息

storybloq bus ack <message-id> --disposition ...

记录已接受、已拒绝或延迟的投递状态

storybloq bus thread show|update ...

检查或转换参与者线程

storybloq bus hooks enable|disable [--client]

控制此项目的受保护实时投递

storybloq bus status|doctor

检查状态并验证完整性

storybloq bus check --ship

当关键的 Bus 工作阻塞发布时失败

storybloq bus export <thread-id>

显式导出一个运行时记录

联邦(编排者项目)

Command

Description

storybloq init --type orchestrator

使用节点映射搭建编排器 .story/ 脚手架

storybloq node add <name> --path <dir> [--stack] [--role] [--depends-on] [--link]

注册节点仓库

storybloq node remove <name> [--force | --prune]

注销节点(先检查依赖项)

storybloq node update <name> [--stack] [--role] [--depends-on] [--health]

更新节点元数据

storybloq node list

所有已配置节点的表格

storybloq config set-federation --allow-node-writes

允许编排器写入节点仓库

团队(团队模式项目)

这些命令所操作的合并模型请参阅团队模式。

Command

Description

storybloq team init [--id-allocator local|git-refs] [--claim-staleness-hours N]

在此项目上启用团队模式

storybloq team setup

在此克隆中安装 git 合并驱动(每位队友,每次检出一次)

storybloq team doctor [--ci]

团队健康检查;--ci 在发现错误时以非零状态退出

storybloq team config show · team config set <key> <value>

查看或更改团队配置

storybloq team reserve <type> --count N

通过远程引用保留显示 ID(仅限 git-refs 分配器)

storybloq reconcile [--dry-run] [--ci]

检测并重新编号重复的显示 ID

storybloq conflicts list · conflicts show <id>

检查未解决的合并冲突

storybloq resolve <id> [--field <f>] [--use ours|theirs] [--value <json>]

解决冲突(也支持 resolve config、resolve roadmap)

storybloq gc [--apply] [--retention-days N]

清除超过保留期的已删除项墓碑记录;不带 --apply 时进行试运行(默认保留 30 天)

MCP 服务器参考

与 Claude Code 或 Codex 注册(由 setup 自动完成):

claude mcp add storybloq -s user -- storybloq --mcp
codex mcp add storybloq --env STORYBLOQ_CLIENT=codex -- storybloq --mcp

服务器直接导入与 CLI 相同的 TypeScript 模块,因此没有子进程开销。它通过从工作目录向上遍历到最近的 .story/ 父目录来自动发现项目根目录。

基础工具按职责分组。启用 Bus 的项目在 MCP 进程启动时注册五个附加工具;在 storybloq bus init 后重启已连接的客户端。

读取(无副作用)

storybloq_status · storybloq_phase_list · storybloq_phase_current · storybloq_phase_tickets · storybloq_ticket_list · storybloq_ticket_get · storybloq_ticket_meta_get · storybloq_ticket_next · storybloq_ticket_blocked · storybloq_issue_list · storybloq_issue_get · storybloq_issue_meta_get · storybloq_note_list · storybloq_note_get · storybloq_lesson_list · storybloq_lesson_get · storybloq_lesson_digest · storybloq_handover_list · storybloq_handover_latest · storybloq_handover_get · storybloq_blocker_list · storybloq_validate · storybloq_recap · storybloq_recommend · storybloq_export · storybloq_selftest

写入(修改 .story/)

storybloq_snapshot · storybloq_handover_create · storybloq_ticket_create · storybloq_ticket_update · storybloq_ticket_meta_set · storybloq_ticket_meta_unset · storybloq_issue_create · storybloq_issue_update · storybloq_issue_meta_set · storybloq_issue_meta_unset · storybloq_note_create · storybloq_note_update · storybloq_lesson_create · storybloq_lesson_update · storybloq_lesson_reinforce · storybloq_phase_create

自主模式 + 审查 + 可观测性

storybloq_autonomous_guide 驱动自主状态机(PICK_TICKET -> PLAN -> PLAN_REVIEW -> WRITE_TESTS -> IMPLEMENT -> TEST -> CODE_REVIEW -> FINALIZE -> COMPLETE)。

storybloq_review_lenses_prepare · storybloq_review_lenses_judge · storybloq_review_lenses_synthesize 编排多视角审查循环(需要 @storybloq/lenses)。

storybloq_session_report · storybloq_register_subprocess · storybloq_unregister_subprocess 将会话健康状态呈现给 Mac 应用。

Storybloq Bus(功能门控)

storybloq_bus_send · storybloq_bus_poll · storybloq_bus_ack · storybloq_bus_thread_get · storybloq_bus_thread_update

每次调用都需要稳定的端点 ID 和当前已验证的客户端任务 ID。轮询和线程输出将对等内容标记为咨询权威。storybloq_bus_poll 和 storybloq_bus_thread_get 相对于规范的已跟踪项目状态是只读的;轮询可能会协调 git 忽略的 .story/bus/ 运行时元数据。其余三个保留正常的 MCP 写入审批。

联邦(编排器项目)

storybloq_node_init 从编排器上下文在节点仓库中引导 .story/。

storybloq_node_add · storybloq_node_list · storybloq_node_update 管理编排器的节点注册表。

钩子

PreCompact(压缩准备,由 setup 设置)

在上下文压缩之前运行 storybloq session compact-prepare,以便在客户端支持 PreCompact 钩子的情况下,快照和恢复面包屑保持最新。Codex 设置使用 storybloq session compact-prepare --client codex 并带有 manual|auto 匹配器,因此 Codex 钩子无法压缩 Claude 拥有的会话;Claude Code 设置将匹配器留空。

{
  "hooks": {
    "PreCompact": [{
      "matcher": "manual|auto",
      "hooks": [{ "type": "command", "command": "storybloq session compact-prepare" }]
    }]
  }
}

使用 storybloq setup --client all --skip-hooks 跳过。

SessionStart(恢复提示注入)

注入感知压缩的恢复提示。Codex 设置使用相同的命令,带有 --codex-hook-json 和匹配器 startup|resume|clear|compact;其钩子 JSON 还携带当前任务 ID,因此同一任务的 COMPACT 恢复可以在无需复制/粘贴 Resume 令牌的情况下继续。setup 无法验证钩子信任,因此安装后在 Codex 中检查 /hooks。

{
  "hooks": {
    "SessionStart": [{
      "matcher": "compact",
      "hooks": [{ "type": "command", "command": "storybloq session resume-prompt" }]
    }]
  }
}

storybloq bus hooks enable 是单独的项目选择加入。它向 SessionStart 添加端点元数据和待处理计数,并允许同步 Stop 钩子为每个新邮箱游标阻塞一次。对等负载字节永远不会出现在钩子输出中。Claude 的共享钩子结构升级一次,并继续受项目本地策略保护;Codex 使用 storybloq hook-status --client codex。

Stop(Mac 应用的实时状态)

在每轮结束时运行 storybloq hook-status,刷新 git 忽略的 .story/status.json,Mac 应用和 iOS 配套应用读取该文件以获取实时会话状态。

写入是内容门控的:当负载与文件已有内容相同时(忽略观察时间戳和产生它的写入者),不会写入任何内容,文件的时间戳和 inode 保持不变。因此,空闲轮次完全不会改动工作树。真正的更改——工作流转换、新的 MCP 调用、健康或租约更改——仍会立即写入。

测试框架将运行期间任何写入视为失败的项目可以完全关闭轮次结束写入器:

{ "statusWriter": { "stopHook": false } }

在 .story/config.json 中。钩子随后完全不执行状态工作:不扫描会话、不构建负载、不自我修复 gitignore、不写入。自主会话会在自身的 MCP 转换时持续刷新状态,因此会话运行期间 Mac 应用仍会显示实时状态——只是在普通交互工作的轮次之间停止更新。该标志默认为开启,任何不可读或格式错误的配置都会使其保持开启。

StopFailure(用量限制检测)

当 Claude Code 会话因速率限制停止时运行 storybloq session limit-stop,记录停止以便自动恢复(请参阅上面的用量限制自动恢复)。setup 还添加了第二个 SessionStart 匹配器组("resume"),携带相同的 session resume-prompt 命令,因此手动重新打开因限制而停止的会话时会获得感知限制的指导。两个条目仅限 Claude,每次升级时协调,并在设置全局总开关时自动移除。

{
  "hooks": {
    "StopFailure": [{
      "matcher": "rate_limit",
      "hooks": [{ "type": "command", "command": "storybloq session limit-stop" }]
    }]
  }
}

库使用

import { loadProject } from "@storybloq/storybloq";

const { state, warnings } = await loadProject("/path/to/project");
console.log(state.tickets.length);           // all tickets
console.log(state.phaseTickets("p1"));       // leaf tickets in phase p1
console.log(state.umbrellaChildren("T-014")); // children of an umbrella

完整的类型定义随包一起提供(exports.types)。

文件格式示例

工单(.story/tickets/T-001.json):

{
  "id": "T-001",
  "title": "Add search to sidebar",
  "type": "task",
  "status": "inprogress",
  "phase": "p2",
  "order": 10,
  "description": "Fuzzy match over ticket title + description.",
  "createdDate": "2026-04-12",
  "completedDate": null,
  "blockedBy": [],
  "parentTicket": null,
  "crossNodeBlockedBy": []
}

问题(.story/issues/ISS-001.json):

{
  "id": "ISS-001",
  "title": "Drag handle hit target too small on trackpad",
  "status": "open",
  "severity": "medium",
  "components": ["mac-app"],
  "impact": "Dragging tickets on trackpad requires multiple tries.",
  "location": ["macos/Views/KanbanCard.swift:42"],
  "sourceRefs": [{
    "path": "macos/Views/KanbanCard.swift",
    "startLine": 42,
    "revision": "5ac37f94f7023b18f72d8e3fcf43dd64f54c11d7",
    "contentHash": "f5b1b1b65dca3d9d86adf7c5d49082aa4dc09e7903ab46ce50e8cc6b4812e4cf",
    "reviewId": "review-2026-04-15"
  }],
  "dedupeKey": "review-2026-04-15:finding-3",
  "createdBy": "external-reviewer",
  "discoveredDate": "2026-04-15",
  "resolvedDate": null,
  "relatedTickets": []
}

每条记录都是独立的文件。ID 在类型内按顺序排列(T-001、T-002、...)。关系是单一规范所有者:工单的 blockedBy 字段指向阻塞工单,反向关系(谁阻塞了我)通过扫描推导得出。

创建操作可以安全地并行运行。ID 分配和创建写入在项目锁下一起发生,因此并发创建者被串行化,每个创建者都会获得不同的顺序 ID。创建永远不会静默覆盖现有记录;在高度并发争用下,创建者会明确失败并报错,而不是发生冲突。

问题的 sourceRefs 独立于可变的 path:line 显示字符串保留审查证据。Storybloq 仅对规范化后的引用行范围进行哈希,并且从不存储源代码摘录。提供的修订版本会解析为 Git 提交;否则 Storybloq 捕获工作树范围,并且仅在这些字节匹配时才记录 HEAD。当原始证据无法解析时,storybloq validate 报告错误;当有效的历史证据在 HEAD 处移动或更改时报告警告;当仍然匹配时不报告发现。

当损坏的 config.json 或 roadmap.json 阻止正常加载时,使用 storybloq validate --integrity-only。这种只读预检一次性扫描每个 .story/**/*.json 文件,在可用时报告解析器位置,并将关键的单例失败与可跳过的项目和辅助文件失败区分开来。它从不重写损坏的文件。

已确认的手动或外部审查发现应直接作为未解决问题提交。先搜索,在 createdBy 中传递审查者归属,通过 sourceRefs 附加审查 ID 和修订版本,并使用稳定的 dedupeKey(如 <review-id>:<finding-id>),以便重试是幂等的。将不确定的设计问题保留为笔记或所有者问题;实施代理负责问题状态和解决。

工单和问题记录保留未知的 JSON 字段。使用 storybloq ticket meta 和 storybloq issue meta 读取或修改这些自定义透传字段,而无需触及 Storybloq 核心字段。值是 JSON,点路径寻址嵌套对象,例如 storybloq ticket meta set T-001 integration.linear '"ABC-123"'。

每个工单的自主计划审查深度可通过 reviewRisk 元数据(low、medium 或 high)进行预设。例如,storybloq ticket meta set T-001 reviewRisk '"high"' 要求至少进行三轮计划审查。旧的 risk 元数据也能被识别,但 reviewRisk 是规范键。此设置仅改变审查深度,绝不会跳过任何审查阶段。

示例工作流

# Initialize
storybloq init --name "my-app"

# Add the first phase
storybloq phase create --id bootstrap --name "Bootstrap" --label "PHASE 1" \
  --description "Get the app running end-to-end"

# Add a ticket
storybloq ticket create --title "Scaffold Next.js" --type task --phase bootstrap

# Start Claude Code and type /story, or invoke $story in Codex, then work on it
# (or go autonomous: /story auto T-001 / $story auto T-001)

# At the end of a session, commit your changes including .story/
git add .
git commit -m "T-001: scaffold Next.js"

# Session ends. Next session starts with /story or $story and picks up with full context.

团队模式

.story/ 是由 git 跟踪的纯 JSON,因此共享它的团队会遇到任何共享状态都会遇到的两个问题:对同一记录进行并发编辑,以及并发创建新记录。团队模式解决了这两个问题。

storybloq team init     # once per project; commit the result
storybloq team setup    # once per clone, by every teammate

team init 为团队工作配置项目(模式版本、声明过期时间、ID 分配器、所需客户端功能),并为你的本地克隆运行设置。team setup 将 storybloq-json git 合并驱动程序安装到克隆的本地 git 配置中,并写入 .story/.gitattributes,使 .story/ JSON 文件通过该驱动程序路由。git 配置是按克隆的,因此每个团队成员需要在每个检出中运行一次 setup。storybloq team doctor 检查整个配置(重复的显示 ID、未解决的冲突、过期的声明、合并驱动程序是否已安装),并在使用 --ci 时以非零退出码退出;有关合并门控工作流,请参阅下面的团队 CI。

并发编辑:合并模型

当 git 合并两个都修改了同一 .story/ 记录的分支时,合并驱动程序会对每条记录执行结构化的三方合并,而不是基于行的文本合并。字段独立合并:如果一个团队成员更改了工单的 status,而另一个成员编辑了其 description,则两个更改都会生效。当同一字段在两侧出现分歧时,驱动程序不会选择任何一侧。它会将分歧记录为记录内的结构化 _conflicts 块,因此文件保持有效的 JSON,没有冲突标记;git 仍会将路径报告为冲突,因此请 git add 该文件并提交以完成合并,然后按自己的节奏解决记录的冲突(这些冲突会在后续合并中一直保留,直到解决)。存在未解决 _conflicts 的项目将被阻止写入,直到所有冲突都解决:

storybloq conflicts list                     # every item with unresolved conflicts
storybloq conflicts show T-042               # field-level detail: base, ours, theirs
storybloq resolve T-042 --field status --use theirs
storybloq resolve T-042 --field title --value '"Merged title"'
storybloq resolve config                     # config.json merges the same way
storybloq resolve roadmap                    # so does roadmap.json

并发创建:显示 ID 冲突

两个团队成员在并行分支上创建项目是另一种失败模式。新记录存储在随机规范 ID 文件名下(例如 t-8f2kq0v3n1xw9d4e.json),因此独立创建的项目在文件级别永远不会冲突;只有旧的顺序文件名(ISS-041.json,来自规范 ID 之前的项目)仍可能发生路径冲突。可能冲突的是面向用户的显示 ID:两个分支都在本地计算“下一个空闲编号”,并且都生成 T-042。这不是合并冲突,而是重复项,它有自己专门的工具:

storybloq reconcile          # renumber duplicates; the copy already on the protected ref, else the earlier one, keeps the number
storybloq reconcile --ci     # detect only: exit non-zero if duplicates exist, mutate nothing

重新编号的项目会在 previousDisplayIds 中保留其旧显示 ID,因此对旧编号的现有引用仍然可以解析。

选择 ID 分配器

team init --id-allocator local|git-refs 选择显示 ID 的分配方式。权衡如下:

local(默认)

git-refs

分配方式

从本地检出计算的下一个空闲编号

使用前在共享 git 远程上保留为引用的 ID

冲突

分歧分支可能生成重复的显示 ID

在源头防止

恢复

合并后运行 storybloq reconcile;使用 reconcile --ci 门控合并

对于 ID 不需要

要求

无;可离线工作

可访问的共享远程,具有引用推送权限

旧客户端

任何客户端都可以创建项目

未声明保留能力的客户端将失败关闭(请参阅下面的注意事项)

使用 git-refs 时,team init 还会将 remote-ref-reservations 添加到 team.requiredFeatures,因此未声明该能力的客户端将拒绝创建项目,而不是在 git-refs 团队中本地分配并导致冲突。一个注意事项:当前 Mac 应用版本在声明该能力的同时早于保留功能,因此在 Mac 端更新发布之前,请避免在 git-refs 团队中从 Mac 应用创建项目。storybloq team reserve tickets --count 5 会预先保留一批 ID。

模式版本和旧客户端

team init 在 .story/config.json 中标记 schemaVersion: 3。1.5.0 之前的 CLI 版本会干净地拒绝 schemaVersion-3 项目,无论是读取还是写入,并显示升级消息(Config schemaVersion 3 exceeds max supported 2. Run: npm update -g @storybloq/storybloq)。硬性失败是故意的:这些客户端不理解团队模式数据,在混合版本团队中,它们之前会产生静默的部分读取而不是错误。

在围栏之前创建的团队仓库带有 schemaVersion: 2。要升级现有的团队仓库:等待每个团队成员运行 1.5.0+ CLI,然后手动将 schemaVersion 设置为 3(或重新运行 storybloq team init,它会执行相同的升级)。较旧的 Mac 应用版本会将 schemaVersion-3 项目显示为只读,直到更新;不会丢失任何数据。

升级早于 .story/.gitignore 的仓库

team init 和 team setup 会写入 .story/.gitignore,涵盖机器本地文件(sessions/、snapshots/、status.json、federation-cache.json、channel-inbox/)。gitignore 不会取消跟踪已跟踪的文件,因此在 gitignore 存在之前采用 storybloq 的项目可能已经在 git 历史中包含了临时文件。检查一次并取消跟踪它们:

git ls-files .story/ | grep -E 'sessions/|snapshots/|status\.json|federation-cache\.json|channel-inbox/'
git rm -r --cached --ignore-unmatch .story/sessions .story/snapshots .story/status.json .story/federation-cache.json .story/channel-inbox

提交删除。会话状态记录绝对路径(包括你的用户名),因此值得在首次共享推送之前执行此操作。

删除会留下墓碑

在团队模式下删除工单、问题、笔记或课程不会将其从共享仓库中移除。文件会保留,包含其完整原始内容,外加生命周期标记:lifecycle: "deleted"、deletedAt 时间戳,以及 deletedBy 设置为删除者的 git user.email。解决删除与编辑冲突同样可以在合成的墓碑上标记解决者的电子邮件作为 deletedBy。墓碑会保留在仓库中,直到有人运行 storybloq gc --apply(默认保留期为 30 天)。

要点:删除项目会将其从正常视图中隐藏,但不会从团队成员的克隆中移除内容或你的身份标记。运行 storybloq gc 预览符合条件的墓碑,然后在它们通过保留期后运行 storybloq gc --apply 将其清除。

你的团队会看到什么

团队模式通过仓库共享状态,因此提交到 .story/ 下的所有内容对拥有仓库访问权限的每个人都是可见的:

  • 工单、问题、笔记和课程,包括所有自由文本字段。

  • 交接文档:叙述性会话文档,通常是最详细的事件记录和原因。

  • 进行中项目上的声明块:声明成员的 git 身份(user.email)、分支名称和声明时间戳,以及自主会话处理项目时的 claimedBySession UUID。

  • 未解决的合并冲突:分歧合并后,受影响的记录会在其 _conflicts 块中携带双方的冲突值(base、ours 和 theirs),直到有人解决。团队成员编写但后来在仲裁中丢失的文本在解决之前会保留在文件中可见。

一旦 gitignore 就位,机器本地文件就不会进入仓库:sessions/(自主会话状态,包括每个会话的 events.log)、snapshots/、status.json、federation-cache.json 和 channel-inbox/。对待已提交的 .story/ 内容要像对待提交消息和代码注释一样谨慎;它会随仓库一起传播。

团队 CI

对于团队模式项目,添加 CI 验证以在合并前捕获重复的 displayId 和过期的引用。有关即用型 GitHub Actions 工作流,请参阅 TEAM_CI.md。

相关项目

  • @storybloq/lenses - 多镜头代码审查 MCP 服务器和库。9 个专业审查器并行运行并返回结构化裁决;storybloq 自主镜头后端直接使用它。

  • Storybloq for Mac - 原生 macOS 应用,监视 .story/ 并在你的 AI 客户端工作时实时更新。在 Mac App Store 上免费。

支持

如有任何问题,请发送电子邮件至 shayegh@me.com:设置问题、疑问、功能请求,或者只是告诉我们你在构建什么。也欢迎通过 GitHub issues 提交错误报告。

贡献

欢迎提交问题和 PR。对于非平凡的更改,请先打开一个问题,以便我们就方向达成一致。

开发设置:

git clone https://github.com/Storybloq/storybloq.git
cd storybloq
npm install
npm test
npm run build

许可证

PolyForm Shield 1.0.0 - 一种源代码可用、禁止竞争使用的许可证(非 OSI 开源)。

你可以将 storybloq 用于任何目的,包括:

  • 个人和业余项目

  • 开源项目

  • 公司内部使用

  • 你正在构建的商业软件

未经单独许可,你不得使用 storybloq 构建与其竞争的产品:重新打包、转售、将其作为托管服务提供,或进行白标。如需此类用途,请联系 shayegh@me.com。

完整文本请参阅 LICENSE,重新分发时必须传播的所需版权声明请参阅 NOTICE。

Related MCP Connectors

Related MCP Servers