storybloq
Enables AI coding assistants to persist and manage project context across sessions, including tickets, roadmap, handovers, and lessons learned, via a structured .story/ directory.
README
<p align="center"> <img src="https://raw.githubusercontent.com/Storybloq/storybloq/main/assets/logo.png" width="120" alt="Storybloq logo" /> </p>
<h1 align="center">storybloq</h1>
<p align="center"> <strong>Cross-session context persistence for AI coding.</strong><br /> A file convention, a CLI, an MCP server, and a Claude Code skill that together turn every coding session into a building block instead of a reset. </p>
<p align="center"> <a href="https://www.npmjs.com/package/@storybloq/storybloq"><img src="https://img.shields.io/npm/v/@storybloq/storybloq?color=333&label=npm" alt="npm version" /></a> <a href="https://github.com/Storybloq/storybloq/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-PolyForm--NC%201.0-blue" alt="License" /></a> <img src="https://img.shields.io/badge/node-%E2%89%A520-brightgreen" alt="Node" /> <img src="https://img.shields.io/badge/claude%20code-compatible-orange" alt="Claude Code compatible" /> </p>
<p align="center"> <a href="https://storybloq.com">storybloq.com</a> · <a href="https://storybloq.com/mac">Mac app</a> · <a href="https://github.com/Storybloq/lenses">Review lenses</a> · <a href="https://storybloq.com/privacy">Privacy</a> </p>
<p align="center"> <img src="https://raw.githubusercontent.com/Storybloq/storybloq/main/assets/hero.png" alt="Storybloq Mac app showing a live project sidebar alongside a Claude Code terminal" /> </p>
The problem
AI coding assistants are stateless. Every new session starts from zero. The model doesn't know what was built yesterday, what's broken, what decisions were made, or what to work on next. Developers compensate with CLAUDE.md files and scattered notes, but there's no standard structure, no session continuity, and no tooling.
The real cost isn't wasted setup time. It's repeated mistakes, relitigated design decisions, hallucinated context, and linear instead of compounding work.
The idea
Every project gets a .story/ directory of JSON and markdown files. Tickets, issues, roadmap phases, session handovers, and lessons learned all live there, tracked by git, readable by any AI.
- CLI:
storybloq- inspect and mutate.story/from the terminal. - MCP server: 53 tools Claude Code and Codex can call directly, no subprocess spawning.
- Skill:
/storyin Claude Code or$storyin Codex loads project state at the start of every session. - Mac app: native sidebar that watches
.story/and updates live while your AI client works (separate product, free on the App Store).
Install
npm install -g @storybloq/storybloq@latest
storybloq setup --client all
Requires Node.js 20+ and at least one AI client: Claude Code or Codex CLI 0.130.0+. Package lives on npm at @storybloq/storybloq; releases are tagged on this repo at github.com/Storybloq/storybloq/releases.
setup --client all installs the Storybloq skill for Claude and Codex, registers this package as an MCP server, and configures available client hooks. Re-running it is safe. setup-skill remains as a compatibility alias for Claude-only setup.
Upgrading
npm install -g @storybloq/storybloq@latest
storybloq setup --client all
Same two commands as a fresh install: @latest pulls the newest version, and re-running setup refreshes the Storybloq skill files, re-registers the MCP server, and sweeps any stale hook entries from prior installs.
You'll usually see a one-line banner on the next storybloq invocation whenever a newer version is on npm:
storybloq v1.2.0 is available (you have v1.1.6).
Update: npm install -g @storybloq/storybloq@latest
The CLI also silently refreshes the skill dir and migrates any legacy hook entries (for example, from the pre-rename @anthropologies/claudestory package) on the first run after an upgrade — no manual cleanup needed.
Alternative install via the Claude Code plugin system: see Storybloq/plugin-archive (legacy path; storybloq setup --client all is the recommended install).
Bootstrap a project
cd your-project
storybloq init --name "your-project"
For multi-repo projects, see Federation below.
That scaffolds:
.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)
Commit everything except .story/snapshots/.
<p align="center"> <img src="https://raw.githubusercontent.com/Storybloq/storybloq/main/assets/board.png" alt="Ticket board showing phases, tickets, and in-progress work" /> </p>
Daily use
Inside Claude Code:
/story- loads project status, reads the latest handover, surfaces open tickets and issues, lists blocked work, summarizes recent changes./story auto T-001 T-002 ISS-013- autonomous mode scoped to those items. Drives a ticket through plan -> plan review -> implement -> tests -> code review -> commit with handovers at each checkpoint./story review T-001- runs the multi-lens review (see Storybloq/lenses) against a ticket's diff./story handover- writes a session handover capturing decisions, blockers, and next steps.
Outside Claude Code, the same state is one storybloq invocation away.
<p align="center"> <img src="https://raw.githubusercontent.com/Storybloq/storybloq/main/assets/autonomous.png" alt="Autonomous mode running a ticket through plan, implement, test, review" /> </p>
Federation
Federation coordinates AI agent work across multiple repos. One project becomes the orchestrator. It declares which repos (nodes) are part of the system, how they depend on each other, and how they communicate at runtime. Each node keeps its own .story/ with its own tickets, issues, and handovers. The orchestrator reads across all of them.
# 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
Three relationship types connect nodes:
dependsOnon node config: build-order edges. The web app depends on the API.linkson node config: runtime integration. The web app calls the API over HTTP.crossNodeBlockedByon tickets: a ticket in one repo is blocked until a ticket in another repo is complete. Example:"crossNodeBlockedBy": ["api:T-012"].
From the orchestrator directory:
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
The recommendation engine generates federation-specific suggestions: nodes blocking downstream work, bottleneck nodes depended on by many others, nodes with no handover in two weeks. Tickets with crossNodeBlockedBy refs never surface in recommendations until the blocking ticket is complete.
CLI reference
All commands accept --format json|md (default md). Pipe JSON through jq for scripting, read the markdown variant directly.
Project
| Command | Description |
|---|---|
storybloq init [--name] [--type orchestrator] [--force] |
Scaffold .story/ (add --type orchestrator for multi-repo) |
storybloq status |
Project summary with phase statuses, counts, and risks |
storybloq validate |
Reference integrity + schema checks |
storybloq setup --client claude|codex|all [--skip-hooks] |
Install Storybloq skills, register MCP, and configure client hooks |
storybloq setup-skill [--skip-hooks] |
Compatibility alias for storybloq setup --client claude |
storybloq recommend --count N |
Context-aware work suggestions |
Phases
| Command | Description |
|---|---|
storybloq phase list |
All phases with derived status (status is computed from tickets, never stored) |
storybloq phase current |
First non-complete phase |
storybloq phase tickets --phase <id> |
Leaf tickets for a phase |
storybloq phase create --id --name --label --description [--summary] --after/--at-start |
Create a phase |
storybloq phase rename <id> [--name] [--label] [--description] [--summary] |
Update phase metadata |
storybloq phase move <id> --after/--at-start |
Reorder |
storybloq phase delete <id> [--reassign <target>] |
Delete (reassign contained tickets) |
Tickets
| Command | Description |
|---|---|
storybloq ticket list [--status] [--phase] [--type] |
List leaf tickets (umbrellas excluded) |
storybloq ticket get <id> |
Full ticket detail |
storybloq ticket next |
Highest-priority unblocked ticket |
storybloq ticket blocked |
All currently blocked tickets |
storybloq ticket create --title --type --phase [--description] [--blocked-by] [--parent-ticket] [--node <name>] |
Create (use --node from orchestrator) |
storybloq ticket update <id> [--status] [--title] [--phase] [--cross-node-blocked-by] [--node <name>] ... |
Update |
storybloq ticket meta get|set|unset <id> [path] [value] |
Manage custom passthrough metadata |
storybloq ticket delete <id> [--force] |
Delete |
Issues
| Command | Description |
|---|---|
storybloq issue list [--status] [--severity] |
List issues |
storybloq issue get <id> |
Issue detail |
storybloq issue create --title --severity --impact [--components] [--related-tickets] [--location] |
Create |
storybloq issue update <id> [--status] [--title] [--severity] ... |
Update |
storybloq issue meta get|set|unset <id> [path] [value] |
Manage custom passthrough metadata |
storybloq issue delete <id> |
Delete |
Notes and lessons
| Command | Description |
|---|---|
storybloq note list · note get · note create · note update |
Brainstorming and idea capture |
storybloq lesson list · lesson get · lesson create · lesson update · lesson reinforce |
Reusable patterns and anti-patterns |
storybloq lesson digest |
Compact summary of all active lessons for skill injection |
Handovers, blockers, snapshots
| Command | Description |
|---|---|
storybloq handover list · handover latest · handover get <file> |
Session continuity documents |
storybloq handover create --title --tldr ... |
Write a new handover |
storybloq blocker list · blocker add · blocker clear |
External dependencies blocking progress |
storybloq snapshot · storybloq recap |
Capture state and diff against the last snapshot |
storybloq export [--phase <id>] [--all] [--format json|md] |
Self-contained project document |
Federation (orchestrator projects)
| Command | Description |
|---|---|
storybloq init --type orchestrator |
Scaffold an orchestrator .story/ with a nodes map |
storybloq node add <name> --path <dir> [--stack] [--role] [--depends-on] [--link] |
Register a node repo |
storybloq node remove <name> [--force | --prune] |
Unregister a node (checks for dependents first) |
storybloq node update <name> [--stack] [--role] [--depends-on] [--health] |
Update node metadata |
storybloq node list |
Table of all configured nodes |
storybloq config set-federation --allow-node-writes |
Allow orchestrator to write into node repos |
MCP server reference
Register with Claude Code or Codex (done automatically by setup):
claude mcp add storybloq -s user -- storybloq --mcp
codex mcp add storybloq --env STORYBLOQ_CLIENT=codex -- storybloq --mcp
The server imports the same TypeScript modules as the CLI directly, so there's no subprocess overhead. It auto-discovers the project root by walking up from the working directory to the nearest .story/ parent.
53 tools grouped by responsibility:
Read (no side effects)
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
Write (mutate .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
Autonomous mode + review + observability
storybloq_autonomous_guide drives the autonomous state machine (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 orchestrate the multi-lens review loop (requires @storybloq/lenses).
storybloq_session_report · storybloq_register_subprocess · storybloq_unregister_subprocess surface session health to the Mac app.
Federation (orchestrator projects)
storybloq_node_init bootstraps .story/ in a node repo from the orchestrator context.
storybloq_node_add · storybloq_node_list · storybloq_node_update manage the orchestrator's node registry.
<p align="center"> <img src="https://raw.githubusercontent.com/Storybloq/storybloq/main/assets/handover.png" alt="Handover timeline with AI-summarized date groups" /> </p>
Hooks
PreCompact (Claude-only auto-snapshot, set up by setup)
Runs storybloq snapshot --quiet before context compaction so recap always reflects the latest state. Manually:
{
"hooks": {
"PreCompact": [{
"matcher": "",
"hooks": [{ "type": "command", "command": "storybloq snapshot --quiet" }]
}]
}
}
Skip with storybloq setup --client all --skip-hooks.
SessionStart (optional recap injection)
Auto-inject what changed since last snapshot:
{
"hooks": {
"SessionStart": [{
"matcher": "",
"hooks": [{ "type": "command", "command": "storybloq recap --format md" }]
}]
}
}
Library usage
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
Full type definitions ship with the package (exports.types).
File format examples
Ticket (.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": []
}
Issue (.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"],
"discoveredDate": "2026-04-15",
"resolvedDate": null,
"relatedTickets": []
}
Each record is its own file. IDs are sequential within type (T-001, T-002, ...). Relationships are single-canonical-owner: a ticket's blockedBy field points at blocker tickets, and the reverse (who-blocks-me) is derived by scanning.
Ticket and issue records preserve unknown JSON fields. Use storybloq ticket meta and storybloq issue meta to read or mutate those custom passthrough fields without touching core Storybloq fields. Values are JSON, and dot paths address nested objects, for example storybloq ticket meta set T-001 integration.linear '"ABC-123"'.
Example workflow
# 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, type /story, then work on it
# (or go autonomous: /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 and picks up with full context.
Related projects
- @storybloq/lenses - multi-lens code review MCP server. 8 specialized reviewers run in parallel and return structured verdicts.
- Storybloq for Mac - native macOS app that watches
.story/and updates live while Claude works. Free on the Mac App Store.
Contributing
Issues and PRs welcome. For non-trivial changes, open an issue first so we can align on direction.
Development setup:
git clone https://github.com/Storybloq/storybloq.git
cd storybloq
npm install
npm test
npm run build
License
PolyForm Noncommercial 1.0.0. Free for personal and noncommercial use. For commercial licensing, contact shayegh@me.com.
See LICENSE for the full text and NOTICE for the required copyright notice you must propagate if you redistribute.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。