关于 museum-documentation
面向 Grove 读者的技术文档写作技能,通过导览式结构先说明系统的背景与设计原因,再介绍实现细节。适合帮助中心、架构介绍和入门文档,不用于 API 参考或技术规格。
主要功能
- 01先交代背景与读者受益
- 02以原因解释技术设计
- 03用导览结构组织文档
- 04结合代码、图示与表格
- 05区分适用文档与不适用文档
适用场景
- 01撰写系统工作原理说明
- 02编写面向读者的代码库文档
- 03制作帮助中心与架构入门内容
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ autumnsgrove/ lattice --skill museum-documentation安装后在 Claude Code 中输入/museum-documentation确认已加载。
详细介绍
博物馆式文档
以待客之道编写文档。以策展方式呈现代码。
将技术系统转化为亲切导览的艺术。博物馆式文档将作者定位为向导,陪伴读者先探索“为什么”,再深入了解实现细节。
这是 Grove 优雅的文档风格,面向任何经验水平、希望了解构成 Grove 的技术、模式和决策的 Wanderers。
何时启用
- 创建面向 Wanderers、而非开发者的文档
- 撰写介绍系统工作原理的知识库文章
- 为好奇的访客记录代码库、功能或系统
- 为帮助中心创建“工作原理”内容
- 撰写应让人感到亲切而非望而生畏的技术内容
- 为未来的知识库章节构建展览
- 编写引导读者了解架构的入门文档
不适用于:
- API 参考(使用 grove-documentation)
- 技术规范(使用 grove-spec-writing)
- 快速参考指南
核心理念
文档应体现 待客之道。
读者进入代码库或系统时,就像走进一处不熟悉其架构和设计决策的场所。博物馆式文档将作者定位为向导,而不是参考资料汇编者,陪伴读者先探索“为什么”,再深入了解实现细节。
博物馆的比喻
🌲 Welcome 🌲
╭─────────────────────╮
│ │
│ ╭─────────────╮ │
│ │ EXHIBIT A │ │
│ │ │ │
│ │ How Login │ │
│ │ Works │ │
│ │ │ │
│ ╰─────────────╯ │
│ │ │
│ ═════╪═════ │
│ │ │
│ ╭─────────────╮ │
│ │ EXHIBIT B │ │
│ ╰─────────────╯ │
│ │
╰─────────────────────╯
Walk through. Take your time.
Every exhibit tells a story.
博物馆不会递给你一份目录就任你自便,而是会 引导 你体验精心策划的展览,先呈现背景,再介绍复杂内容;先讲述故事,再列出规范。
核心原则
先介绍背景,再作解释
介绍展览时,先交代背景。在展示代码或架构之前,告诉读者:
- 他们正在看的是什么
- 它为何存在
- 谁会从中受益
不要这样写:
TokenRefreshMap 按用户 ID 存储正在进行的令牌刷新操作。
可以这样写:
当某人的登录过期时,我们需要刷新其凭据,同时不让其退出登录。这个映射会协调整个过程——当多个标签页同时打开时,它可以防止重复尝试刷新。
解释原因,而非只陈述事实
代码展示 是什么。文档解释 为什么。
与其说 Map 存储了令牌刷新操作,不如描述它解决的协调问题。将抽象概念与它带来的体验联系起来。
使用通俗易懂的比喻
将技术概念与熟悉的体验联系起来:
| 技术概念 | 博物馆式比喻 |
|---|---|
| 数据库 | 抽屉分类整理的文件柜 |
| 缓存 | 门边方便快速查找的架子 |
| 中间件 | 必须经过的安检站 |
| 队列 | 请求排队等候的队伍 |
| 工作进程 | 在后台处理任务的得力助手 |
| Webhook | 有事情发生时会响起的门铃 |
展示真实代码,然后进行分析
先展示实际代码片段,再清晰说明其意义:
const pending = this.refreshInProgress.get(userId);
if (pending) return pending;
如果这个人的刷新操作已经在进行,我们就等待现有操作完成,而不是再启动一个。一个厨房,一个厨师。
结构框架
博物馆展览遵循一致的结构:
1. 标题与标语
# The Authentication Exhibit
> Where login happens. Where trust begins.
2. “您正在看的是什么”部分
立即为读者介绍背景:
## What You're Looking At
This is where login happens. When someone proves they own an email
address, this code decides what they can access and how long that
access lasts.
You'll see OAuth flows, session management, and token refresh logic.
Nothing scary—just careful choreography.
3. 组织有序的导览结构
使用展厅、部分或章节来组织导览内容:
## The Tour
### Gallery 1: The Front Door
How visitors arrive and prove who they are.
### Gallery 2: The Memory Room
How we remember who's logged in.
### Gallery 3: The Renewal Office
How sessions stay fresh without interrupting work.
4. “值得借鉴的模式”
强调可迁移的经验:
## Patterns Worth Stealing
**The "already in progress" check.** Before starting an expensive
operation, check if it's already running. Simple, but easy to forget.
**Centralized error handling.** All auth failures flow through one
function. One place to fix, one place to log.
5. “经验总结”
坦诚地分享反思:
## Lessons Learned
We tried stateless JWTs first. Simpler, they said. Scalable, they
promised. But logout was impossible—tokens couldn't be revoked.
Session-based auth is older, but it works. Sometimes boring is right.
6. “继续您的导览”
链接到相关展览:
## Continue Your Tour
- **[The Database Exhibit](./database.md)** — Where sessions are stored
- **[The API Exhibit](./api.md)** — How protected routes check access
- **[The Security Exhibit](./security.md)** — Rate limiting and protection
7. 有意义的结尾署名
---
_— Autumn, January 2026_
或用一句诗意的话结尾:
---
_Trust is built one verified request at a time._
视觉元素
ASCII 流程图
展示流程和关系:
Visitor Grove Google
│ │ │
│ "Log me in" │ │
│ ───────────────────────>│ │
│ │ "Who is this?" │
│ │ ────────────────────────>│
│ │ │
│ │ "It's autumn@..." │
│ │ <────────────────────────│
│ │ │
│ "Welcome back" │ │
│ <───────────────────────│ │
│ │ │
供快速参考的表格
| File | What It Does | Why It Matters |
| --------------- | -------------------- | -------------- |
| `auth.ts` | Handles OAuth flow | The front door |
| `session.ts` | Manages login state | The memory |
| `middleware.ts` | Checks every request | The bouncer |
带上下文的代码块
不要单独展示代码。始终在代码前或后进行说明:
// Every request passes through this checkpoint
export async function authGuard(request: Request): Promise<Response | null> {
const session = await getSession(request);
if (!session) {
return redirect("/login");
}
return null; // Continue to the page
}
如果你尚未登录,就会前往登录页面。如果已登录,就继续操作。简单的检查点逻辑。
语气与风格
建议
- 自然地使用“你”和“我们”,以对话式的语气写作
- 承认不完美之处(“我们先试了 X,但没成功。”)
- 加入个人感受(“我们试了三次才弄对。”)
- 使用较短的段落(2 到 4 句)
- 让句子节奏有所变化
避免
完整列表请参阅 owl-archive/references/anti-patterns.md。博物馆式写作尤其要避免以下问题:
- 使用长破折号(改用句号、逗号或括号)
- 企业行话(“强大”“无缝”“杠杆”“利用”“精简”)
- 生硬的过渡语(“此外”“而且”“另外”“值得一提的是”)
- “不是 X,而是 Y”句式及其变体(“不是 X。不是 Y。只是 Z。”)
- 明明可以用主动语态表达,却使用被动语态
- 模棱两可的措辞(“这或许可能有所帮助……”)
- 陈腐的隐喻(不要在每个段落里重复同一种隐喻)
- 反复总结(不要每个章节都预告、陈述,然后再次总结)
- “事情是这样的”/“关键在于”这类故弄玄虚的说法
- 连串使用动名词片段(“修复 Bug。编写功能。发布代码。”)
- 迅速堆叠历史类比(“Apple……Facebook……Uber……”)
- 叙述性列表中每条都以粗体开头的写法
区别
普通写法(避免):
此模块利用业界标准的 OAuth 协议,以无缝的方式提供强大的身份验证流程处理功能。
博物馆式写法(推荐):
登录就在这里进行。当有人证明自己拥有某个电子邮件地址时,这段代码会决定他们可以访问什么。
组织模式
完整代码库:MUSEUM.md
为整个代码库编写文档时,创建一个作为入口的中心文件 MUSEUM.md:
# Welcome to the Grove Museum
> A guided tour of how this forest grows.
## The Wings
- **[The Architecture Wing](./docs/exhibits/architecture.md)** — The big picture
- **[The Authentication Exhibit](./docs/exhibits/auth.md)** — Trust and identity
- **[The Database Galleries](./docs/exhibits/database.md)** — Where data lives
单个目录:EXHIBIT.md
用于记录单个复杂功能或目录:
# The Editor Exhibit
> Where words become posts.
This directory contains everything that powers the writing experience...
复杂功能:展厅结构
对于由多个部分组成的系统,使用展厅:
## Gallery 1: Data Layer
How posts are stored and retrieved.
## Gallery 2: API Endpoints
The doors visitors knock on.
## Gallery 3: The Editor Component
Where the magic happens in the browser.
## Gallery 4: Security Considerations
Keeping things safe.
验证清单
完成任何博物馆式文档前:
结构
- 标题包含标语
- “你正在看的内容”能帮助读者了解概况
- 按照逻辑划分为展厅/章节
- “值得借鉴的模式”突出可迁移的经验
- “继续参观”链接到相关内容
- 结尾有意义(署名或诗意的句子)
视觉多样性
- 至少有一个 ASCII 图表或流程图
- 适合比较的地方使用表格
- 代码块附有说明性上下文
- 不要出现超过 4 到 5 段的长篇文字墙
语气(参阅 grove-documentation)
- 不使用长破折号
- 不使用企业行话
- 直接说明动机
- 如实承认不完美之处
- 清楚说明系统各部分之间的联系
读者体验
- 新手能够跟上参观流程
- 先回答“为什么”,再回答“怎么做”
- 技术细节有上下文说明
- 路径清晰,便于浏览
与其他技能集成
写作前
- walking-through-the-grove — 如果展览需要命名
- grove-documentation — 查看语气指南,尤其是“避免”列表
写作时
- grove-spec-writing — 借鉴绘制图表的 ASCII 艺术技巧
- grove-documentation — 检查术语(Wanderer、Rooted 等)
- GroveTerm 组件 — 如果展览的 UI 中包含 Grove 术语,请使用
@autumnsgrove/lattice/ui中的GroveTerm、GroveSwap或GroveText,不要将术语硬编码。新访客默认会看到标准术语;Grove Mode 用户则会看到以自然为主题的词汇。在 Markdown 内容中使用[[term]]语法,通过 rehype-groveterm 插件自动转换。
写作之后
- 以新手的视角阅读 — 像从未接触过这些内容一样,通读文档
- 路径是否合乎逻辑?你会想继续探索吗?
示例:完整的展品
# The Session Exhibit
> How Grove remembers who you are.
## What You're Looking At
When you log in, Grove needs to remember you. Not forever—just long
enough for your visit. This exhibit shows how that memory works.
You'll see cookies, database tables, and the careful dance of
"who are you?" that happens with every page load.
---
## Gallery 1: The Cookie Jar
A session starts with a cookie. Not the chocolate chip kind—a small
piece of text your browser holds onto.
```typescript
const SESSION_COOKIE = "grove_session";
const SESSION_DURATION = 7 * 24 * 60 * 60 * 1000; // 7 days
```
七天。时间足够方便,也足够短,能确保安全。
登录时,我们会生成一个随机 ID,并将其存储在这个 Cookie 中。 ID 本身没有任何意义——它只是一个用于查找你的密钥。
展厅 2:记忆簿
实际的会话数据存储在数据库中:
| 列 | 存储内容 |
|---|---|
id | Cookie 中的随机密钥 |
user_id | 此会话所属的用户 |
created_at | 登录时间 |
expires_at | 此会话结束时间 |
每次加载页面时,我们都会在此表中查找 Cookie 的 ID。 如果找到了(并且尚未过期),你就仍处于登录状态。
展厅 3:刷新之舞
会话会过期。但每周都要登录一次很烦人。
因此,我们会悄悄刷新:当会话已过半时, 我们会延长会话。你不会察觉,只要保持活跃, 就能一直处于登录状态。
if (session.expiresAt < Date.now() + SESSION_DURATION / 2) {
await extendSession(session.id);
}
活跃访客会留下。弃用的会话则会过期。
值得借鉴的模式
“过半刷新”模式。 不要等到会话过期才延长。 趁访客仍活跃时延长会话。
使用随机 ID,而非顺序 ID。 会话 ID 应当不可预测。 切勿将自动递增的数字用作安全令牌。
经验教训
我们以前会把会话数据存储在 Cookie 本身中(JWT)。我们当时觉得这样更简单。 但这样一来,我们就无法撤销会话——如果某人的令牌泄露, 我们就没有办法使其失效。
数据库会话是较旧的技术。有时候,旧技术更可靠。
继续参观
— Autumn,2026 年 1 月
---
## The Underlying Purpose
Museum documentation respects readers' time and intelligence while acknowledging that code is knowledge deserving careful stewardship.
Wanderers who read these exhibits should leave understanding not just *what* Grove does, but *why* it does it that way. They should feel like they've been welcomed into the workshop, not handed a manual.
*Every codebase has stories. Museum documentation tells them.*