Doramagic 项目包 · 项目说明书
stoa 项目
生成时间:2026-05-13 16:44:51 UTC
项目概述
stoa 是一个基于 Markdown 文件系统的知识库管理系统(Knowledge Vault System),通过结构化的组织方式管理包含前端matter 的 markdown 文件。该系统提供了页面索引、维基链接解析、合成页面生成、语法检查、CLI 命令工具以及 MCP(Model Context Protocol)服务等核心功能。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
项目简介
stoa 是一个基于 Markdown 文件系统的知识库管理系统(Knowledge Vault System),通过结构化的组织方式管理包含前端matter 的 markdown 文件。该系统提供了页面索引、维基链接解析、合成页面生成、语法检查、CLI 命令工具以及 MCP(Model Context Protocol)服务等核心功能。
系统的核心设计理念是将知识以标准化的页面形式存储在文件系统中,通过索引和工具层实现高级的知识管理操作,如跨页面引用、批量合成、部署漂移检测等。
核心架构
系统层次结构
stoa 采用分层架构设计,主要包含以下层次:
graph TD
A[CLI 层] --> B[工具层]
B --> C[核心业务层]
C --> D[传输层]
D --> E[文件系统]
F[lint-checks] --> C
G[index] --> C
H[pages] --> C
I[synthesize] --> C目录结构
项目源码按功能模块组织:
| 目录 | 职责 |
|---|---|
src/core/ | 核心业务逻辑,包含索引、页面操作、合成、链接解析等 |
src/tools/ | MCP 工具实现,如 profile-register 等 |
src/cli/ | 命令行接口实现 |
src/transport/ | 传输层实现,如 stdio 服务器 |
src/core/lint-checks/ | 各种语法检查规则实现 |
核心模块
页面管理(pages)
页面是 stoa 的基本存储单元,每个页面对应一个 markdown 文件。
graph LR
A[page id] --> B[pathForPage]
B --> C[文件系统路径]
D[readPage] --> E[返回页面对象]
F[writePage] --> G[持久化到磁盘]页面对象包含以下字段:
| 字段 | 类型 | 说明 |
|---|---|---|
id | string | 页面唯一标识符 |
path | string | 文件系统路径 |
frontmatter | Record | YAML 前端配置 |
body | string | markdown 正文内容 |
updated | string | ISO 日期格式的更新时间 |
页面读取时会解析文件的前端matter,提取元数据并规范化更新时间为 ISO 格式:
const raw = readFileSync(path, "utf8");
const { frontmatter, body } = parseFrontmatter(raw);
return {
id, path, frontmatter, body,
updated: toIsoDate(frontmatter.updated ?? frontmatter.created)
};
索引系统(index)
索引系统是 stoa 的核心组件,负责维护页面元数据的索引以支持高效查询。
graph TD
A[VaultIndex] --> B[pages]
A --> C[wikis]
A --> D[links]
A --> E[profiles]
A --> F[tokens]索引数据结构 VaultIndex 包含以下子索引:
| 索引 | 用途 |
|---|---|
pages | 所有页面的元数据数组 |
wikis | wiki 列表及其配置 |
links | 页面间链接关系 |
profiles | profile 相关数据 |
tokens | 全文搜索令牌索引 |
查询支持多维度过滤:
if (f.wiki && wikiSet && !wikiSet.has(p.wiki)) return false;
if (f.type && p.type !== f.type) return false;
if (f.channel && p.channel !== f.channel) return false;
if (f.layer && f.layer !== "all") {
const set = f.layer === "knowledge" ? KNOWLEDGE_TYPES : EXECUTION_TYPES;
if (!set.includes(p.type)) return false;
}
维基链接解析(wikilinks)
维基链接是 stoa 实现页面间关联的核心机制,支持 [[wikis/<wiki>/<type>/<id>(|alias)]] 格式的链接。
graph TD
A[markdown 内容] --> B[wikilinkExtractor]
B --> C{代码块检查}
C -->|顶层代码块| D[跳过]
C -->|普通内容| E[正则匹配]
E --> F[WikilinkRef]
F --> G[body]
F --> H[frontmatter]解析结果 WikilinkRef 接口定义:
| 字段 | 类型 | 说明 | 来源 | |
|---|---|---|---|---|
raw | string | 原始链接文本 | body 或 frontmatter | |
wiki | string | wiki 名称 | 路径解析 | |
type | string | 页面类型 | 路径解析 | |
id | string | 页面 ID | 路径解析 | |
alias | string? | 可选别名 | 管道后文本 | |
source | "body" \ | "frontmatter" | 链接来源位置 | 提取位置 |
资料来源:src/core/wikilinks.ts:1-40
代码块感知:顶层代码块(行首的 ``` )内的链接会被跳过,但嵌套在列表项中的缩进代码块不会被剥离。
合成系统(synthesize)
合成功能用于将多个相关页面聚合成一篇综合性的 synthesis 页面。
graph TD
A[输入: topic/by_agent] --> B[查询候选页面]
B --> C[按类型过滤]
C --> D[构建 synthesis 元数据]
D --> E[生成 summary]
E --> F[写入 synthesis 页面]合成的页面元数据包含:
| 字段 | 示例值 |
|---|---|
type | synthesis |
wiki | 目标 wiki |
status | draft |
tags | 根据作用域确定 |
sources | 来源页面的 wikilink 数组 |
last_compiled | ISO 日期 |
scope | "memory"(可选) |
资料来源:src/core/synthesize.ts:1-80
合成陈旧度追踪(syntheses)
系统追踪合成页面的陈旧程度,基于 last_compiled 时间戳计算滞后期。
graph TD
A[所有 synthesis 页面] --> B[读取 last_compiled]
B --> C{时间戳存在?}
C -->|是| D[计算 lag_days]
D --> E{超过 min_lag_days?}
E -->|是| F[加入结果集]
C -->|否| G[标记为从未编译]
E -->|否| H[过滤掉]陈旧度数据结构 SynthesisStaleness 包含:
pageId: 页面标识wiki: 所属 wikilastCompiled: ISO 日期或 nulllagDays: 自上次编译以来的天数或 null
资料来源:src/core/syntheses.ts:1-60
Family 解析(family)
Family 是 wiki 的上层组织单元,支持多 wiki 的批量操作。
graph TD
A[FamilyResolveCtx] --> B{解析优先级}
B --> C[1. 显式 familyArg]
B --> D[2. ctx.defaultFamily]
B --> E[3. .active-family 文件]
B --> F[4. 返回 null]
C --> G{类型检查}
G -->|wikiArg 存在| H[FamilyMismatchError]
G -->|仅 familyArg| I[返回 familyArg]解析上下文 FamilyResolveCtx:
interface FamilyResolveCtx {
vaultPath: string;
defaultFamily?: string;
}
语法检查系统(lint-checks)
lint 系统提供多维度的页面质量检查。
#### 主要检查规则
| 检查规则 | 严重程度 | 说明 |
|---|---|---|
| SYNTHESIS_DEBT | warn | 标记缺乏对应 synthesis 的硬知识聚类 |
| CLAIM_WITH_NO_SCOPE | warn | 标记无作用域的 claim 页面 |
| ACTIVE_WIKI_DIVERGENCE | info | 提示 defaultWiki 与 .active-wiki 不一致 |
#### SYNTHESIS_DEBT 详解
该检查识别满足以下条件的硬知识聚类:
- 至少 N 个(默认 3)页面共享同一 tag
- 这些页面都属于"硬知识"类型(concept、decision、spec)
- 该 wiki 下没有任何 synthesis 页面使用该 tag
const HARD_KNOWLEDGE_TYPES = new Set(["concept", "decision", "spec"]);
const DEFAULT_MIN_CLUSTER_SIZE = 3;
资料来源:src/core/lint-checks/synthesis-debt.ts:1-50
前端matter 模式(frontmatter)
系统定义了严格的前端matter 验证模式。
#### 页面类型(NoteType)
export const NoteType = z.enum([
"concept", "guide", "decision", "source",
"idea", "question", "journal", "move",
"claim", "map", "synthesis"
]);
#### 页面状态(PageStatus)
export const PageStatus = z.enum([
"draft", "active", "accepted", "superseded", "archived"
]);
#### 置信度(Confidence)
export const Confidence = z.enum(["high", "medium", "low"]);
#### 编排优先级(CurationPriority)
用于标记需要人工关注的草案页面:
export const CurationPriority = z.enum(["high", "medium", "low"]);
资料来源:src/core/frontmatter.ts:1-50
技能平台(skills-platform)
技能平台管理技能的部署和漂移检测。
graph TD
A[DriftDeployment] --> B[detectDriftAt]
B --> C{文件状态}
C -->|canonical 缺失| D[抛出错误]
C -->|deployed 缺失| E[kind: missing]
C -->|哈希不匹配| F[kind: hash-mismatch]
C -->|哈希匹配| G[无报告]检测规则:
| 情况 | 处理方式 |
|---|---|
| canonical 缺失 | 抛出异常(vault 完整性问题) |
| deployed 缺失 | 报告 kind: "missing" |
| 哈希不匹配 | 报告 kind: "hash-mismatch" |
| 哈希匹配 | 不报告 |
技能文件路径约定:
- canonical:
<vaultPath>/wikis/_agents/moves/<moveId>/SKILL.md - deployed:
<deployment.skills_dir>/<moveId>/SKILL.md
资料来源:src/core/skills-platform.ts:1-60
MCP 服务(transport/stdio)
MCP 服务通过 stdio 传输层提供工具接口。
graph TD
A[stdio 输入] --> B[JSON-RPC 解析]
B --> C[工具路由]
C --> D[profile-register]
C --> E[其他工具]
D --> F[StadiumClient]
F --> G[平台 API]
D --> H[更新 frontmatter]
C --> I[返回 JSON-RPC 响应]服务启动时通过 walkInitablePaths 预热状态缓存:
function walkInitablePaths(vaultPath: string): string[] {
// 递归遍历 wikis/ 目录
// 返回所有 .md 文件路径
// 用于构建初始状态
}
资料来源:src/transport/stdio.ts:1-60
状态缓存(eventbus/state-cache)
状态缓存为事件处理提供内存状态存储。
class StateCache {
private states = new Map<string, unknown>();
private key(source: string, wiki: string, id: string): string {
return `${source}:${wiki}:${id}`;
}
}
缓存键格式:source:wiki:id,支持按源、wiki、ID 三维定位状态。
资料来源:src/core/eventbus/state-cache.ts:1-30
工具注册(tools/profile-register)
profile-register 工具将 profile 页面注册到 Stadium 平台。
流程:
- 读取
wikis/<wiki>/profiles/<profile_id>.md - 提取
pokemon或species_name字段 - POST 到
/profiles/register - 更新文件的
platform_profile_id和platform_stats
资料来源:src/tools/profile-register.ts:1-50
CLI 命令
系统通过 commander 提供命令行接口:
| 命令 | 功能 |
|---|---|
new-wiki <name> | 创建新 wiki,需指定 --mode 和 --scope |
创建 wiki 时的模式选项:
idea-mapproject-doclearningmixed
资料来源:src/cli/commands/new-wiki.ts:1-30
页面类型对应文件命名
| 类型 | 文件命名规则 |
|---|---|
| concept, guide, source, idea, question, claim, synthesis | <type>-<slug>.md |
| decision | decision-YYYY-MM-DD-<slug>.md |
| journal | journal-YYYY-MM-DD-HHMM-<slug>.md |
| move | <move>/SKILL.md(目录) |
| map | map.md(固定名称) |
资料来源:src/core/ids.ts:1-30
总结
stoa 是一个功能完备的知识库管理系统,其核心价值在于:
- 文件系统优先:所有数据以标准 markdown 文件存储,便于版本控制和人工编辑
- 结构化索引:通过前端matter 和索引提供高效的元数据查询
- 链接驱动:通过 wikilink 实现页面间的语义关联
- 质量保障:多层 lint 检查确保知识库的一致性
- 工具扩展:MCP 架构支持与其他系统的集成
系统的设计遵循单一职责原则,各模块边界清晰,便于维护和扩展。
资料来源:[src/core/pages.ts:1-50]()
核心概念
Stoa 是一个知识管理 MCP (Model Context Protocol) 服务器,旨在对笔记库 (vault) 进行索引、检索和一致性检查。以下文档详细介绍其核心概念与架构。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
页面类型系统
Stoa 采用结构化的页面类型体系,每种类型具有特定语义和存储约定。
页面类型定义
根据 src/core/frontmatter.ts 的定义,核心页面类型包括:
| 类型 | 语义 | 文件命名规则 |
|---|---|---|
concept | 概念性知识 | concept-<slug>.md |
decision | 决策记录 | decision-YYYY-MM-DD-<slug>.md |
journal | 日志条目 | journal-YYYY-MM-DD-HHMM-<slug>.md |
guide | 操作指南 | guide-<slug>.md |
source | 外部引用 | source-<slug>.md |
idea | 想法 | idea-<slug>.md |
question | 问题 | question-<slug>.md |
spec | 规格说明 | spec-<slug>.md |
synthesis | 综合页面 | synthesis-<slug>.md |
move | 技能移动 | move-<slug>/SKILL.md (目录结构) |
map | 维基地图 | map.md (固定文件名) |
资料来源:src/core/frontmatter.ts:1-30
页面状态
页面状态使用枚举定义:
export const PageStatus = z.enum([
"draft", "active", "accepted", "superseded", "archived"
]);
- draft: 草稿状态
- active: 活跃状态
- accepted: 已接受
- superseded: 已替代
- archived: 已归档
资料来源:src/core/frontmatter.ts:35-37
置信度等级
export const Confidence = z.enum(["high", "medium", "low"]);
资料来源:src/core/frontmatter.ts:39-40
整理优先级
用于标记草稿页面的整理优先级,帮助人类注意力分配:
export const CurationPriority = z.enum(["high", "medium", "low"]);
资料来源:src/core/frontmatter.ts:48-49
维基与家族体系
Wiki 结构
Stoa 使用多 Wiki 架构,每个 Wiki 存储在 vaultPath/wikis/<wiki>/ 目录下。
家族解析顺序
src/core/family.ts 定义了家族 (family) 解析的优先级:
- 显式
familyArg参数 - MCP CLI 参数
--default-family vaultPath/.active-family文件null→ 回退到单 Wiki 解析
export function resolveFamily(
ctx: FamilyResolveCtx,
familyArg?: string,
wikiArg?: string,
knownWikis?: Record<string, { family?: string | null }>
): string | null
Wiki 与家族校验
当同时提供 familyArg 和 wikiArg 时,系统会校验 Wiki 所属家族是否匹配:
if (wikiFamily !== familyArg) {
throw new FamilyMismatchError(
`wiki '${wikiArg}' has family '${wikiFamily ?? "(none)"}' which does not match requested family '${familyArg}'`
);
}
Wiki 链接系统
Wikilink 格式
Wiki 链接采用标准化格式:
[[wikis/<wiki>/<type>/<id>(|alias)?]]
例如:[[wikis/_meta/concepts/concept-trust-gradient-axes]]
Wikilink 提取器
src/core/wikilinks.ts 提供了结构化的链接引用接口:
export interface WikilinkRef {
raw: string;
wiki: string;
type: string;
id: string;
alias?: string;
source: "body" | "frontmatter";
}
资料来源:src/core/wikilinks.ts:22-29
代码块感知
Wikilink 提取器具有代码块感知能力:
- 顶层 fenced 代码块 (
`) 内的链接会被跳过 - 缩进代码块(如列表项内的 4 空格缩进)不会被剥离
- 内联单反引号代码 span 不会被剥离
资料来源:src/core/wikilinks.ts:24-34
Wikilink 职责分离
- 提取职责 (
wikilinks.ts):仅提取结构化链接引用 - 完整性检查 (
lint-checks/cross-wiki-link-broken.ts):检查目标页面是否存在
资料来源:src/core/wikilinks.ts:14-16
页面索引与查询
VaultIndex 结构
索引文件 _index/pages.json 存储所有页面的元数据:
interface VaultIndex {
pages: IndexedPage[];
wikis: IndexedWiki[];
}
页面查询
使用 queryPages 函数进行多条件过滤:
export function queryPages(
idx: VaultIndex,
f: PageFilter
): IndexedPage[]
支持的过滤条件:
| 过滤器字段 | 说明 |
|---|---|
wiki | Wiki 名称精确匹配 |
wikis | Wiki 名称集合 |
type | 页面类型精确匹配 |
channel | 频道名称精确匹配 |
status | 页面状态精确匹配 |
layer | "knowledge" 或 "execution" 或 "all" |
全文搜索
upsertTokenize 函数使用 Porter Stemmer 进行词干提取和停用词过滤:
const UPSERT_STOP_WORDS = new Set([
"the","and","of","a","an","in","to","is","for","on",
"with","as","at","by","or","be","this","that","it",
"from","are","was","were","not","but","if"
]);
页面读写操作
读取页面
readPage 函数根据 ID 解析页面路径:
export function readPage(
vaultPath: string,
wiki: string,
id: string
): ReadPageResult
路径解析顺序:
写入页面
export interface WritePageInput {
id: string;
type: NoteType;
wiki: string;
frontmatter: Record<string, any>;
body: string;
expectedUpdated?: string; // 乐观锁
}
export function writePage(
vaultPath: string,
input: WritePageInput
): WritePageResult
乐观锁机制:若提供 expectedUpdated,系统会验证现有文件的 updated 时间戳,防止并发覆盖。
频道系统
频道日志
频道 (channel) 用于聚合 journal 类型页面的活动摘要:
interface ChannelSummary {
name: string;
wiki: string;
lastEntry: ChannelEntry | null;
count24h: number;
}
资料来源:src/core/channel.ts:20-24
频道条目
interface ChannelEntry {
id: string;
channel: string;
wiki: string;
author: string;
ts: string;
excerpt: string; // 前 240 字符
pageId: string;
}
资料来源:src/core/channel.ts:26-33
综合页面 (Synthesis)
Synthesis 创建
synthesize 命令生成综合页面:
const fm: Record<string, any> = {
id,
title: `${input.topic} — synthesis`,
type: "synthesis",
wiki,
status: "draft",
created: today,
updated: today,
summary: `Synthesis of ${inputIds.length} pages on "${input.topic}".`,
tags: [],
last_compiled: today,
资料来源:inputIds.map(i => `[[wikis/${wiki}/${typeFolderForId(i)}/${i}]]`)
};
资料来源:src/core/synthesize.ts:60-75
Synthesis 陈旧度检测
detectSynthesisStaleness 函数计算页面"过时"程度:
if (lastCompiled) {
const compiledMs = new Date(lastCompiled).getTime();
lagDays = Math.floor((now - compiledMs) / MS_PER_DAY);
}
资料来源:src/core/syntheses.ts:55-58
Synthesis 债务检测
当同标签的硬知识页面聚类缺少对应的综合页面时,触发警告:
export const DEFAULT_MIN_CLUSTER_SIZE = 3;
const HARD_KNOWLEDGE_TYPES = new Set([
"concept", "decision", "spec"
]);
资料来源:src/core/synthesize.ts:30-40
标记渲染系统
托管区域契约
Marker 系统用于在文档中维护"托管区域":
- 起始标记:
<!-- markerName:start (rendered: YYYY-MM-DD, half-life: Nd) --> - 结束标记:
<!-- markerName:end --> - 幂等性: 相同输入产生字节级相同的输出
export interface MarkerOptions {
renderedDate?: string; // ISO 日期
halfLifeDays?: number; // 半衰期(天)
}
资料来源:src/core/marker-render.ts:20-24
使用场景
- Claims 汇总 (
synthesize) - 技能/代理文档补丁 (
sync-skills,bootstrap-repo)
资料来源:src/core/marker-render.ts:6-10
状态缓存
StateCache 提供简单的内存状态缓存:
export class StateCache {
private states = new Map<string, unknown>();
private key(source: string, wiki: string, id: string): string {
return `${source}:${wiki}:${id}`;
}
get<T>(source: string, wiki: string, id: string): T | undefined;
set<T>(source: string, wiki: string, id: string, state: T): void;
has(source: string, wiki: string, id: string): boolean;
size(): number;
}
资料来源:src/core/eventbus/state-cache.ts:1-25
MCP 预热机制
walkInitablePaths 函数在接收变更事件前预热状态缓存:
function walkInitablePaths(vaultPath: string): string[] {
// 遍历 wikis/ 目录,收集所有 .md 文件路径
}
命名规范
ID 格式
| 类型 | ID 格式要求 |
|---|---|
| 普通页面 | 小写字母、数字、连字符 ^[a-z0-9-]+$ |
| Channel | 小写 kebab-case ^[a-z0-9]+(-[a-z0-9]+)*$ |
| 日期 | ISO 格式 ^\d{4}-\d{2}-\d{2}$ |
资料来源:src/core/frontmatter.ts:41-44
架构总览
graph TD
subgraph "MCP 接口层"
STDIO[STDIO 传输]
MCP[MCP 服务器]
end
subgraph "核心处理层"
IDX[索引系统]
QUERY[查询引擎]
LINT[Lint 检查]
SYNC[同步引擎]
end
subgraph "存储层"
PAGES[Pages 读写]
FRONT[Frontmatter 解析]
WIKI[Wikilinks]
CHAN[Channel]
end
subgraph "文件系统"
VAULT[Vault 目录]
WIKIS[wikis/ 目录]
INDEX[_index/ 目录]
end
STDIO --> MCP
MCP --> IDX
IDX --> QUERY
IDX --> LINT
SYNC --> PAGES
PAGES --> FRONT
PAGES --> WIKI
IDX --> CHAN
QUERY --> INDEX
IDX --> VAULT
VAULT --> WIKIS
IDX --> INDEX术语表
| 术语 | 定义 |
|---|---|
| Vault | 根目录下的笔记库,包含 wikis/ 和 _index/ |
| Wiki | 某个主题领域的页面集合,位于 wikis/<wiki>/ |
| Family | Wiki 的分组,用于批量操作 |
| Synthesis | 综合页面,聚合多个同标签页面的内容 |
| Hard Knowledge | 核心知识类型 (concept, decision, spec) |
| Soft Knowledge | 非核心类型 (guide, source, idea, question) |
| Marker | 托管区域的边界标记 |
| Channel | 聚合日志条目的频道 |
资料来源:[src/core/frontmatter.ts:1-30]()
系统架构
Stoa 是一个基于 Model Context Protocol (MCP) 的知识库管理系统,通过 STDIO 传输层与 LLM 代理进行通信。其核心功能围绕页面索引、合成(Synthesis)管理、代码检查(Lint) 和技能平台四大模块展开。系统采用 vault 结构的 Markdown 文件存储,页面之间通过 wikilink 互相引用,形成一个自包含的知识图谱。...
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
Stoa 是一个基于 Model Context Protocol (MCP) 的知识库管理系统,通过 STDIO 传输层与 LLM 代理进行通信。其核心功能围绕页面索引、合成(Synthesis)管理、代码检查(Lint) 和技能平台四大模块展开。系统采用 vault 结构的 Markdown 文件存储,页面之间通过 wikilink 互相引用,形成一个自包含的知识图谱。资料来源:src/transport/stdio.ts:30-35
核心设计理念
Stoa 采用单职责原则设计,各模块职责明确划分:
| 模块 | 职责 | 核心文件 |
|---|---|---|
| 索引系统 | 页面元数据提取、全文搜索、token 管理 | src/core/index.ts |
| 页面操作 | 页面读写、路径解析、版本控制 | src/core/pages.ts |
| 合成引擎 | 多页面聚合、摘要生成、来源追踪 | src/core/synthesize.ts |
| Lint 系统 | 规则检查、诊断报告、错误修复 | src/core/lint.ts |
| 技能平台 | 技能部署、漂移检测、版本管理 | src/core/skills-platform.ts |
| 家族解析 | 多 wiki 聚合、家族范围查询 | src/core/family.ts |
系统层次架构
graph TD
subgraph 传输层["传输层 (Transport)"]
STDIO[STDIO Server Transport]
end
subgraph 服务层["服务层 (Service)"]
MCP[MCP Server]
Tools[Tools Layer]
end
subgraph 核心业务["核心业务 (Core)"]
Index[索引系统]
Pages[页面管理]
Synthesize[合成引擎]
Lint[代码检查]
Skills[技能平台]
Family[家族解析]
end
subgraph 数据层["数据层 (Data)"]
Vault[Vault 存储]
IndexFiles[_index 索引文件]
Frontmatter[Frontmatter 元数据]
end
STDIO --> MCP
MCP --> Tools
Tools --> Index
Tools --> Pages
Tools --> Synthesize
Tools --> Lint
Tools --> Skills
Tools --> Family
Index --> IndexFiles
Pages --> Vault
Synthesize --> Index
Lint --> Index索引系统
索引数据结构
系统维护多个索引文件用于快速查询:
graph LR
subgraph _index["_index/ 目录"]
PagesIdx[_index/pages.json]
TokensIdx[_index/tokens.json]
LinksIdx[_index/links.json]
WikisIdx[_index/wikis.json]
ProfilesIdx[_index/profiles.json]
end
subgraph 源数据["Vault 源文件"]
Markdown[*.md 文件]
Frontmatter[Frontmatter]
end
Markdown -->|解析| Frontmatter
Frontmatter -->|提取| PagesIdx
Frontmatter -->|分词| TokensIdx
Frontmatter -->|链接提取| LinksIdx
WikisIdx -->|Wiki 配置| ProfilesIdx索引系统通过 VaultIndex 接口提供统一的数据访问:
export interface VaultIndex {
pages: IndexedPage[];
wikis: IndexedWiki[];
profiles: IndexedProfile[];
links: IndexedLink[];
tokens: Record<string, string[]>;
}
页面类型体系
Stoa 定义了严格的页面类型系统:
| 类型 | 说明 | 文件命名规范 |
|---|---|---|
concept | 概念页面 | concept-<slug>.md |
decision | 决策记录 | decision-YYYY-MM-DD-<slug>.md |
guide | 操作指南 | guide-<slug>.md |
source | 外部引用 | source-<slug>.md |
idea | 想法记录 | idea-<slug>.md |
question | 问题记录 | question-<slug>.md |
journal | 日志条目 | journal-YYYY-MM-DD-HHMM-<slug>.md |
move | 技能移动 | move-<slug>/SKILL.md |
map | 地图页面 | map.md (固定命名) |
synthesis | 合成页面 | 自动生成 |
资料来源:src/core/ids.ts:1-25
搜索与查询
系统支持多维度查询过滤:
export interface PageFilter {
wiki?: string;
type?: NoteType;
channel?: string;
status?: PageStatus;
layer?: "knowledge" | "execution" | "all";
}
全文搜索使用 Porter Stemmer 算法进行词干提取,支持停用词过滤:
function upsertTokenize(text: string): string[] {
return text.toLowerCase()
.replace(/[^a-z0-9\s]/g, " ")
.split(/\s+/)
.filter(t => t.length > 1 && !UPSERT_STOP_WORDS.has(t))
.map(t => upsertStemmer.stem(t));
}
页面管理系统
页面读写流程
graph TD
A[请求读写页面] --> B{页面是否存在}
B -->|不存在| C[新建页面]
B -->|存在| D{是否有 expectedUpdated}
D -->|有| E[乐观锁检查]
E -->|版本匹配| F[写入文件]
E -->|版本不匹配| G[抛出错误]
D -->|无| F
C --> H[生成路径]
F --> I[更新索引]
H --> I页面路径解析
路径生成遵循以下规则:
| 页面类型 | 路径模板 |
|---|---|
| 普通页面 | wikis/{wiki}/{type}/{id}.md |
| 地图页面 | wikis/{wiki}/map.md |
| 技能移动 | wikis/_agents/moves/{id}/SKILL.md |
| 技能档案 | wikis/_agents/profiles/{id}.md |
Frontmatter 验证
验证模式
系统使用 Zod 进行运行时验证:
const draftSchema = z.object({
id: z.string().regex(/^[a-z0-9-]+$/),
title: z.string().min(1),
type: NoteType,
created: z.string().regex(ISO_DATE),
channel: z.string().regex(KEBAB).optional(),
});
export const PageStatus = z.enum([
"draft", "active", "accepted", "superseded", "archived"
]);
export const Confidence = z.enum(["high", "medium", "low"]);
export const CurationPriority = z.enum(["high", "medium", "low"]);
资料来源:src/core/frontmatter.ts:1-50
状态流转
| 状态 | 说明 | 允许的转换 |
|---|---|---|
draft | 草稿状态 | active |
active | 活跃状态 | accepted, archived |
accepted | 已接受 | superseded, archived |
superseded | 已废弃 | 无 |
archived | 归档 | 无 |
合成引擎
合成类型
系统支持两种合成模式:
| 模式 | 说明 | 生成条件 |
|---|---|---|
topic | 主题合成 | 按标签聚合相关页面 |
memory | 记忆合成 | 按代理聚合其 authored 页面 |
合成数据结构
graph TD
subgraph 合成输入["合成输入"]
Topic[Topic 标签]
Tags[多个 Tag]
Pages[源页面列表]
end
subgraph 合成过程["合成过程"]
Extract[提取引用]
Generate[生成摘要]
Render[渲染标记区域]
end
subgraph 合成输出["合成输出"]
Synthesis[Synthesis 页面]
Sources[Sources 列表]
Markers[标记区域]
end
Topic --> Extract
Tags --> Extract
Pages --> Extract
Extract --> Generate
Generate --> Render
Render --> Synthesis合成页面的 frontmatter 结构:
id: <auto-generated>
title: "{topic} — synthesis"
type: synthesis
wiki: <target-wiki>
status: draft
created: <today>
updated: <today>
summary: "Synthesis of {count} pages on \"{topic}\"."
tags: [<tags>]
last_compiled: <today>
资料来源:[wikilinks to source pages]
资料来源:src/core/synthesize.ts:1-80
合成陈旧度检测
系统可检测长时间未重新编译的合成页面:
export interface SynthesisStaleness {
id: string;
wiki: string;
lag_days: number | null;
last_compiled: string | null;
}
陈旧度计算基于 last_compiled 字段与当前时间的差值:
if (lastCompiled) {
const compiledMs = new Date(lastCompiled).getTime();
lagDays = Math.floor((now - compiledMs) / MS_PER_DAY);
}
资料来源:src/core/syntheses.ts:1-60
Lint 检查系统
检查规则体系
graph LR
subgraph 规则类型["规则分类"]
Error[Error 级规则]
Warning[Warning 级规则]
Info[Info 级规则]
end
subgraph 检查范围["检查范围"]
Frontmatter[Frontmatter 检查]
Content[内容检查]
Filename[文件名检查]
Links[链接检查]
CrossWiki[跨 Wiki 检查]
end
Frontmatter -->|验证| Error
Content -->|验证| Warning
Filename -->|验证| Warning
Links -->|验证| Info核心检查规则
| 规则代码 | 严重级别 | 说明 |
|---|---|---|
FILENAME_ID_MISMATCH | warning | 文件名与 ID 不匹配 |
BAD_CHANNEL_FORMAT | warning | Channel 格式非法(需 kebab-case) |
CLAIM_WITH_NO_SCOPE | warn | Claim 无作用域定义 |
SYNTHESIS_DEBT | info | 存在未合成的知识集群 |
SNIPPET_NO_IMPLEMENTATION | warning | 代码片段缺少实现引用 |
CROSS_WIKI_LINK_BROKEN | error | 跨 Wiki 链接目标不存在 |
MISSING_CURATION_PRIORITY | info | Agent 创作的草稿缺少整理优先级 |
特定 Wiki 检查
针对 _agents wiki 有专门的检查逻辑:
- Profile 检查:验证 profile 页面存在且格式正确
- Move 检查:验证 move 目录结构符合规范(需包含
SKILL.md) - 别名漂移检查(ALIAS_DRIFT):检测 agent 别名与实际页面的不一致
技能平台
技能部署架构
graph TD
subgraph 源端["Vault 源端"]
Canonical[Canonical SKILL.md]
MoveDir[move-{id} 目录]
end
subgraph 部署端["Deployment 端"]
DeployDir[部署目录]
Deployed[Deployed SKILL.md]
end
subgraph 检测机制["漂移检测"]
Hash1[源文件哈希]
Hash2[部署文件哈希]
Compare[比较结果]
end
Canonical --> Hash1
Deployed --> Hash2
Hash1 --> Compare
Hash2 --> Compare
Compare -->|匹配| OK[无需更新]
Compare -->|不匹配| Drift[报告漂移]
Compare -->|缺失| Missing[报告缺失]漂移报告类型
| 类型 | 说明 | 触发条件 |
|---|---|---|
missing | 部署端缺失 | 部署目录中无对应 SKILL.md |
hash-mismatch | 哈希不匹配 | 源文件与部署文件内容不一致 |
export interface DriftReport {
move_id: string;
kind: "missing" | "hash-mismatch";
actual_hash: string | undefined;
}
资料来源:src/core/skills-platform.ts:1-60
家族解析系统
家族解析优先级
系统按以下顺序解析家族范围:
graph TD
A{是否有显式 family 参数?} -->|是| B[使用显式参数]
A -->|否| C{是否有 defaultFamily?}
C -->|是| D[使用 defaultFamily]
C -->|否| E{是否有 .active-family 文件?}
E -->|是| F[使用文件内容]
E -->|否| G[返回 null, 单 Wiki 解析]家族不匹配检测
当同时提供 family 和 wiki 参数时,系统会验证一致性:
if (wikiFamily !== familyArg) {
throw new FamilyMismatchError(
`wiki '${wikiArg}' has family '${wikiFamily}' which does not match requested family '${familyArg}'`
);
}
Wikilink 处理
链接格式规范
系统支持 vault-root 绝对路径格式的 wikilink:
[[wikis/{wiki}/{type}/{id}(|alias)?]]
链接提取规则
| 场景 | 是否提取 |
|---|---|
| 顶层代码块内链接 | ❌ 跳过 |
| 嵌套代码块内链接 | ✅ 提取(v1.6 Phase 1 限制) |
| 单反引号行内代码 | ✅ 提取 |
| Frontmatter related 数组 | ✅ 提取 |
export interface WikilinkRef {
raw: string;
wiki: string;
type: string;
id: string;
alias?: string;
source: "body" | "frontmatter";
}
资料来源:src/core/wikilinks.ts:1-30
链接重写
支持批量前缀重写,保持语义一致性:
export interface RewriteScope {
body: boolean;
frontmatter: boolean;
}
export interface PageRewrite {
page_id: string;
links_rewritten: number;
new_body: string;
new_related: string[] | undefined;
}
资料来源:src/core/rewrite-links.ts:1-40
传输层
STDIO 服务器
系统通过 STDIO 与 MCP 客户端通信:
graph LR
subgraph MCP客户端["MCP Client (LLM Agent)"]
JSONRPC[JSON-RPC Requests]
end
subgraph STDIO传输["STDIO Transport"]
Stdin[stdin]
Stdout[stdout]
Stderr[stderr (日志)]
end
JSONRPC -->|输入| Stdin
Stdout -->|输出| JSONRPC
Stderr -->|诊断| Console服务器初始化输出:
vault-mcp stdio server ready (vault={path}, default-wiki={wiki}, default-family={family})
资料来源:src/transport/stdio.ts:1-60
配置与扩展
运行时配置
| 配置项 | 说明 | 来源 |
|---|---|---|
vaultPath | Vault 根目录路径 | 必需参数 |
defaultWiki | 默认 Wiki 名称 | CLI 参数 |
defaultFamily | 默认家族名称 | CLI 参数 |
扩展机制
- Marker 渲染:支持在文件中维护可编辑区域,工具与人类共同编辑
- Zod 验证:所有输入通过 schema 验证,确保类型安全
- 模块化检查:Lint 规则以插件形式注册
关键技术栈
| 技术 | 用途 |
|---|---|
| TypeScript | 核心开发语言 |
| Zod | 运行时 schema 验证 |
| Node.js fs 模块 | 文件系统操作 |
| MCP SDK | 模型上下文协议实现 |
| Porter Stemmer | 全文搜索分词 |
总结
Stoa 的系统架构体现了以下设计原则:
- 单一职责:每个模块只负责一个明确的领域
- 数据与逻辑分离:索引系统与业务逻辑解耦
- 可验证性:通过 Zod schema 确保数据完整性
- 幂等性:所有写操作均可安全重试
- 可观测性:Lint 系统提供诊断能力
整个系统以 vault 目录为数据源,通过 MCP STDIO 传输层对外提供服务,形成了完整的知识管理闭环。
资料来源:[src/core/index.ts:1-50]()
传输层实现
Stoa 的传输层是 MCP(Model Context Protocol)服务器与外部客户端之间的通信桥梁,负责处理请求的接收、路由和响应返回。该层采用插件化架构,支持多种传输协议,当前实现包括 STDIO 标准输入输出传输和 HTTP 传输两种模式。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
Stoa 的传输层是 MCP(Model Context Protocol)服务器与外部客户端之间的通信桥梁,负责处理请求的接收、路由和响应返回。该层采用插件化架构,支持多种传输协议,当前实现包括 STDIO 标准输入输出传输和 HTTP 传输两种模式。
传输层的核心职责:
- 初始化并管理 MCP 服务器连接
- 预热状态缓存以支持增量事件处理
- 处理文件系统变化事件并维护索引一致性
- 提供可插拔的传输适配器接口
资料来源:src/transport/stdio.ts:1-20
架构设计
传输类型概览
| 传输类型 | 用途 | 特点 |
|---|---|---|
| STDIO | 本地 CLI 集成 | 进程间通信,低延迟,适合桌面工具 |
| HTTP | 远程服务 | 支持网络访问,适合服务器部署 |
| UI Routes | Web 界面 | 提供读写路由的 HTTP 端点 |
状态缓存机制
传输层依赖 StateCache 类实现内存状态缓存,用于在处理文件系统变更事件时提供基准状态对比。
graph TD
A[文件系统变更] --> B{StateCache.has?}
B -->|是| C[获取历史状态]
B -->|否| D[返回 undefined]
C --> E[计算差异]
E --> F[触发增量更新]
D --> G[处理初始事件]StateCache 关键方法:
| 方法 | 签名 | 说明 | |
|---|---|---|---|
| get | `<T>(source, wiki, id) => T \ | undefined` | 按复合键获取缓存状态 |
| set | <T>(source, wiki, id, state) => void | 存储状态到缓存 | |
| has | (source, wiki, id) => boolean | 检查键是否存在 | |
| size | () => number | 返回缓存条目总数 |
复合键格式:${source}:${wiki}:${id},确保不同来源、维基和页面的状态隔离。
资料来源:src/core/eventbus/state-cache.ts:1-30
STDIO 传输实现
工作流程
STDIO 传输是 Stoa 的主要本地通信方式,通过标准输入/输出流与 MCP 客户端交互。
sequenceDiagram
participant Client as MCP 客户端
participant Server as StdioServerTransport
participant Cache as StateCache
participant Vault as 文件系统
Client->>Server: 连接建立
Server->>Vault: walkInitablePaths()
Server->>Cache: 预热缓存
Note over Cache: 加载历史状态
Client->>Server: 请求消息
Server->>Cache: 查询/更新状态
Server->>Client: 响应消息缓存预热机制
在接收实时事件前,传输层会遍历 wikis/ 目录结构,将现有文件路径加载到状态缓存中,确保第一次变更事件有有效的基准状态可供对比。
function walkInitablePaths(vaultPath: string): string[] {
const root = join(vaultPath, "wikis");
if (!existsSync(root)) return [];
let entries: Array<{
isFile(): boolean;
name: string;
parentPath?: string;
path?: string;
}>;
entries = readdirSync(root, { recursive: true, withFileTypes: true });
const paths: string[] = [];
for (const e of entries) {
if (!e.isFile()) continue;
if (!e.name.endsWith(".md")) continue;
// ... 收集有效路径
}
return paths;
}
预热流程说明:
资料来源:src/transport/stdio.ts:25-55
类型兼容性处理
代码对 Node.js v22 的类型定义进行了显式处理:
// @types/node 22 声明 Dirent<NonSharedBuffer> 作为默认值
// 'name' 在运行时是字符串,但类型表现为 buffer-like
let entries: Array<{
isFile(): boolean;
name: string;
parentPath?: string;
path?: string;
}>;
entries = readdirSync(root, { recursive: true, withFileTypes: true })
as unknown as typeof entries;
此处的类型断言确保了运行时字符串类型与 TypeScript 类型定义的一致性。
资料来源:src/transport/stdio.ts:40-45
HTTP 传输
HTTP 传输层通过 Web 服务器方式暴露 MCP 服务,支持远程客户端连接。该传输方式适用于将 Stoa 作为独立服务部署的场景。
HTTP 传输的核心能力:
- 接受外部 HTTP 请求
- 路由到对应的工具处理器
- 返回 JSON 格式响应
注:详细 HTTP 传输实现请参考 src/transport/http.ts。
UI 路由层
UI 路由层提供基于 HTTP 的读写接口,供 Web 前端或其他 HTTP 客户端使用。
| 路由文件 | 职责 |
|---|---|
routes-read.ts | 页面读取操作 |
routes-write.ts | 页面写入操作 |
index.ts | 路由聚合与中间件 |
注:详细路由实现请参考 src/transport/ui/ 目录。
页面路径解析
传输层与核心页面模块协作,将页面 ID 解析为实际文件系统路径:
export function pathForPage(
vaultPath: string,
id: string,
type: NoteType,
wiki: string
): string {
// 特殊页面类型处理
if (id === `map-${wiki}` || id === "map") {
return join(vaultPath, "wikis", wiki, "map.md");
}
// 标准页面路径
return join(vaultPath, "wikis", wiki, typeFolderForId(id), `${id}.md`);
}
索引与缓存协同
传输层的事件处理依赖底层的写穿式索引更新机制:
graph LR
A[变更事件] --> B[upsertPage]
B --> C[解析 frontmatter]
C --> D[更新 pages.json]
D --> E[更新 tokens.json]
E --> F[StateCache 同步]索引更新是原子操作,保证了在并发访问下的数据一致性。
配置参数
| 参数 | 来源 | 说明 |
|---|---|---|
vaultPath | CLI --vault= 或 STOA_VAULT_PATH | 保险库根目录 |
defaultWiki | CLI --default-wiki= | 默认维基名称 |
defaultFamily | CLI --default-family= | 默认家族名称 |
服务器启动时会输出配置确认信息到 stderr:
vault-mcp stdio server ready (vault=/path/to/vault, default-wiki=<unset>, default-family=<unset>)
资料来源:src/transport/stdio.ts:20-25
错误处理
传输层的错误处理策略:
| 场景 | 处理方式 |
|---|---|
| 目录不存在 | 返回空数组 |
| 读取失败 | 吞没异常并返回空结果 |
| 文件损坏 | 交由调用方处理 |
| 状态缓存未命中 | 返回 undefined |
这种防御性编程确保了传输层在异常情况下的健壮性,不会因单个文件问题导致整个服务中断。
扩展传输类型
Stoa 的传输层设计支持添加新的传输适配器。实现新传输类型的步骤:
- 实现传输类,实现
connect方法 - 注册传输处理器到 MCP 服务器
- 在入口文件选择合适的传输类型
- 添加对应的启动日志输出
当前支持的传输类型已覆盖本地集成(STDIO)和远程访问(HTTP)两种主要场景。
资料来源:[src/transport/stdio.ts:1-20]()
事件总线系统
事件总线系统是 stoa 项目的核心基础设施之一,提供基于文件系统观察的发布-订阅事件处理机制。该系统使 MCP 工具能够以阻塞等待(push 原语)而非轮询的方式响应 vault 中的文件变更,实现了实时事件驱动的工具调用模式。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
事件总线系统是 stoa 项目的核心基础设施之一,提供基于文件系统观察的发布-订阅事件处理机制。该系统使 MCP 工具能够以阻塞等待(push 原语)而非轮询的方式响应 vault 中的文件变更,实现了实时事件驱动的工具调用模式。
事件总线在以下场景中发挥关键作用:
- 任务状态变更检测(status/owner 变化)
- wiki 内容变更监听
- 通道(channel)消息通知
- 跨实例协调通信
资料来源:src/core/eventbus/types.ts
核心架构
模块结构
事件总线系统由以下子模块组成:
| 模块 | 文件 | 职责 |
|---|---|---|
| 类型定义 | types.ts | 定义 VaultEvent、VaultEventFilter、事件派生器接口 |
| 事件总线 | bus.ts | 核心事件发布-订阅引擎,文件系统监视器集成 |
| 匹配器 | match.ts | 过滤器匹配逻辑,实现事件筛选条件 |
| 注册表 | registry.ts | 管理事件监听器订阅和取消订阅 |
| 事件派生器 | event-deriver.ts | 从原始文件事件派生语义化 vault 事件 |
| 等待处理 | handle-wait.ts | 实现 wait-for 系列阻塞原语 |
| 内置匹配器 | matchers/task.ts | 任务状态变更检测匹配器 |
graph TD
subgraph "文件系统层"
FS[文件系统观察者]
end
subgraph "事件总线核心"
EB[EventBus]
REG[Registry]
DER[EventDeriver]
MATCH[Matcher]
end
subgraph "等待原语"
WF[wait-for]
WFA[wait-for-any]
WFL[wait-for-all]
WFM[wait-for-many]
end
FS -->|原始文件变更| EB
EB --> REG
EB --> DER
DER --> MATCH
MATCH -->|过滤后事件| WF
MATCH -->|过滤后事件| WFA
MATCH -->|过滤后事件| WFL
MATCH -->|过滤后事件| WFM
REG -->|订阅管理| EB资料 Error with Openai API: output new_sensitive (1027)
Please check that you have set the OPENAI_API_KEY environment variable with a valid API key.
资料来源:[src/core/eventbus/types.ts]()
召回与检索系统
召回与检索系统是 stoa 知识库系统的核心基础设施,负责从结构化索引中高效定位符合查询条件的页面、Claims 和综合文档。该系统采用写穿透(Write-Through)索引更新策略,确保索引数据与文件系统保持同步,同时将完整性检查(目标页面是否存在、Wiki 是否存在)的职责委托给上层消费者。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
召回与检索系统是 stoa 知识库系统的核心基础设施,负责从结构化索引中高效定位符合查询条件的页面、Claims 和综合文档。该系统采用写穿透(Write-Through)索引更新策略,确保索引数据与文件系统保持同步,同时将完整性检查(目标页面是否存在、Wiki 是否存在)的职责委托给上层消费者。
核心设计原则:
- 单一职责:召回模块仅负责提取结构化链接引用,不进行完整性验证 资料来源:src/core/wikilinks.ts:11-12
- 幂等性:重新渲染相同输入产生字节级相同的输出 资料来源:src/core/marker-render.ts:19-21
- 分层架构:索引管理层与工具层分离,索引层负责数据持久化,工具层负责业务逻辑编排
核心数据模型
索引页面结构(IndexedPage)
interface IndexedPage {
id: string;
wiki: string;
type: string;
path?: string;
channel?: string;
status?: string;
title?: string;
tags?: string[];
created?: string; // ISO日期 YYYY-MM-DD
updated?: string; // ISO日期 YYYY-MM-DD
last_validated?: string;
confidence?: Confidence;
authored_by?: string;
}
VaultIndex 主索引结构
interface VaultIndex {
pages: IndexedPage[];
wikis: IndexedWiki[];
profiles: IndexedProfile[];
links: LinkEdge[];
tokens: TokenIndex;
}
页面查询系统
queryPages 函数
queryPages 是页面查询的核心入口,支持多维度过滤 资料来源:src/core/index.ts:40-52:
export function queryPages(idx: VaultIndex, f: PageFilter): IndexedPage[] {
return idx.pages.filter(p => {
if (f.wiki && wikiSet && !wikiSet.has(p.wiki)) return false;
if (f.type && p.type !== f.type) return false;
if (f.channel && p.channel !== f.channel) return false;
if (f.status && p.status !== f.status) return false;
if (f.layer && f.layer !== "all") {
const set = f.layer === "knowledge" ? KNOWLEDGE_TYPES : EXECUTION_TYPES;
if (!set.includes(p.type)) return false;
}
return true;
});
}
查询过滤器参数
| 参数 | 类型 | 说明 | |||
|---|---|---|---|---|---|
wiki | `string \ | undefined` | 按 Wiki 名称过滤 | ||
type | `string \ | undefined` | 按页面类型过滤 | ||
channel | `string \ | undefined` | 按协调频道过滤 | ||
status | `string \ | undefined` | 按状态过滤(draft/active/accepted 等) | ||
layer | `"knowledge" \ | "execution" \ | "all" \ | undefined` | 按知识层过滤 |
id | `string \ | undefined` | 按页面 ID 精确匹配 |
页面类型分层
系统将页面类型划分为两个知识层:
| 知识层 | 包含类型 | 说明 |
|---|---|---|
KNOWLEDGE_TYPES | concept, decision, spec, process, capability, domain, support | 持久化、可蒸馏的知识 |
EXECUTION_TYPES | guide, source, idea, question | 执行层面的文档 |
注意:guide、source、idea、question被排除在知识层之外,因为它们是程序性或外部引用性质,不符合"持久化、可蒸馏"知识的标准 资料来源:src/core/lint-checks/synthesis-debt.ts:26-34
索引更新机制
写穿透索引(Write-Through Index)
upsertPage 函数负责单页面的索引更新:
export function upsertPage(pagePath: string): void {
// 读取文件 → 解析 frontmatter → 更新 pages.json 和 tokens.json
// 注意:不重新生成 links.json, wikis.json, profiles.json
}
该函数执行以下操作:
- 读取页面文件内容
- 解析 frontmatter 元数据
- 向
_index/pages.json添加/替换条目 - 向
_index/tokens.json添加分词数据 - 不重新生成
_index/{links,wikis,profiles}.json(这些是聚合文件)
聚合索引文件的重新生成由 vault.reindex 工具单独处理 资料来源:src/core/index.ts:78-82
分词与停用词过滤
const UPSERT_STOP_WORDS = new Set([
"the","and","of","a","an","in","to","is","for","on","with","as","at","by","or","be",
"this","that","it","from","are","was","were","not","but","if"
]);
function upsertTokenize(text: string): string[] {
return text.toLowerCase()
.replace(/[^a-z0-9\s]/g, " ")
.split(/\s+/)
.filter(t => t.length > 1 && !UPSERT_STOP_WORDS.has(t))
.map(t => upsertStemmer.stem(t)); // 使用 Porter Stemmer
}
| 处理步骤 | 说明 |
|---|---|
| 转小写 | 统一大小写 |
| 去除非字母数字字符 | 保留单词边界 |
| 停用词过滤 | 移除高频无意义词 |
| Porter 词干提取 | 词形归一化 |
Claims 检索与排序
有效置信度计算
Claims 采用半衰期衰减模型计算有效置信度 资料来源:src/core/claim-render.ts:52-62:
function effectiveConfidence(
claim: { confidence: Confidence; last_validated?: string; status?: string },
today: Date,
config: ClaimsConfig,
): number {
const base = BASE_CONFIDENCE[claim.confidence ?? "medium"];
const ageMs = today.getTime() - new Date(claim.last_validated ?? today).getTime();
const halfLives = ageMs / MS_PER_DAY / config.half_life_days;
const decayed = base * Math.pow(0.5, halfLives);
const eff = Math.max(decayed, config.effective_floor);
// 被撤回的 Claims 有效置信度归零
if (claim.status === "retracted") return 0;
return eff;
}
置信度基础值
| 置信度级别 | 基础值 | 半衰期衰减后最小值 |
|---|---|---|
high | 0.9 | 由 effective_floor 决定 |
medium | 0.6 | 由 effective_floor 决定 |
low | 0.3 | 由 effective_floor 决定 |
Claims 排序策略
排序得分公式:
score(claim) = effective_confidence + (profile_match ? 0.1 : 0)
| 排序因素 | 说明 |
|---|---|
| 有效置信度 | 半衰期衰减后的当前置信度 |
| Profile 加成 | 当部署 Profile ID 在 claim 的 profile 数组中时加 0.1 |
综合文档检索
综合文档查询
syntheses.ts 提供综合文档的查询与陈旧度分析 资料来源:src/core/syntheses.ts:40-75:
// 过滤出 synthesis 类型的页面
const syntheses = allPages.filter(p => {
if (p.type !== "synthesis") return false;
if (opts.wiki && p.wiki !== opts.wiki) return false;
return true;
});
// 从文件 frontmatter 读取 last_compiled
if (synthPath && existsSync(synthPath)) {
const raw = readFileSync(synthPath, "utf8");
const { frontmatter } = parseFrontmatter(raw);
const rawLc = frontmatter.last_compiled;
// 计算距今天数
lagDays = Math.floor((now - compiledMs) / MS_PER_DAY);
}
综合文档陈旧度指标
| 指标 | 说明 |
|---|---|
last_compiled | 上次编译日期,来自 frontmatter |
lag_days | 距今天数 |
staleness | 可配置的陈旧度阈值(默认 30 天) |
频道摘要检索
channel.ts 提供协调频道的实时摘要 资料来源:src/core/channel.ts:24-45:
export function channelTail(vaultPath: string, opts: ChannelTailOptions): ChannelSummary[] {
// 查询所有 journal 类型页面
const pages = queryPages(idx, { type: "journal", wiki: opts.wiki });
// 按 wiki::channel 聚合
const byKey = new Map<string, ChannelSummary>();
for (const p of pages) {
const key = `${p.wiki}::${p.channel}`;
// 统计 24 小时内的条目数
if (p.created >= sinceIso) summary.count24h++;
// 记录最新条目
if (!summary.lastEntry || p.created > summary.lastEntry.ts) {
// 读取文件获取摘要和作者
excerpt = body.trim().slice(0, 240);
author = String(fm.author ?? "unknown");
}
}
}
频道摘要数据结构
| 字段 | 类型 | 说明 | |
|---|---|---|---|
name | string | 频道名称 | |
wiki | string | 所属 Wiki | |
count24h | number | 24 小时内条目数 | |
lastEntry | `ChannelEntry \ | null` | 最新条目详情 |
检索流程图
graph TD
A[用户查询请求] --> B{查询类型}
B -->|页面查询| C[queryPages]
B -->|Claims 查询| D[查询 + 置信度计算]
B -->|综合文档| E[过滤 synthesis 类型]
B -->|频道摘要| F[channelTail 聚合]
C --> G[应用过滤器]
D --> H[计算 effective_confidence]
E --> I[读取 last_compiled]
F --> J[统计 count24h]
G --> K[返回 IndexedPage[]]
H --> L[按 score 排序]
I --> M[计算 lag_days]
J --> N[返回 ChannelSummary[]]
L --> O[返回排序后 Claims]
M --> P[返回 SynthesisStaleness[]]架构设计要点
索引与文件系统同步
| 操作 | 索引更新范围 |
|---|---|
upsertPage | pages.json + tokens.json |
vault.reindex | 全部索引文件 |
| 文件删除 | 需手动触发重建 |
Wiki 解析器
export function queryWikis(idx: VaultIndex): IndexedWiki[] {
return idx.wikis;
}
过滤器组合
页面过滤器支持多维度组合过滤,各维度之间为 AND 关系:
graph LR
A[Wiki 过滤] -->|AND| Z[最终结果]
B[Type 过滤] -->|AND| Z
C[Channel 过滤] -->|AND| Z
D[Status 过滤] -->|AND| Z
E[Layer 过滤] -->|AND| Z配置参数
Claims 渲染配置
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
half_life_days | number | 30 | 置信度半衰期(天) |
effective_floor | number | 0.1 | 有效置信度下限 |
综合文档配置
| 参数 | 类型 | 默认值 | 说明 | |
|---|---|---|---|---|
min_lag_days | `number \ | null` | null | 最小陈旧天数阈值 |
stale_after_days | number | 30 | 标记为陈旧的天数 |
相关工具
| 工具名称 | 功能 |
|---|---|
vault.reindex | 重新生成全部索引文件 |
vault.synthesize | 编译或刷新综合页面 |
vault.channel-tail | 拉取协调频道的最新条目 |
vault.recall | 根据条件召回相关页面 |
来源:https://github.com/BrettNye/stoa / 项目说明书
Wiki管理
Wiki管理是Stoa系统的核心功能之一,负责管理知识库中的wiki空间、页面组织、链接解析以及内容综合。Stoa采用vault-root结构,所有wiki内容位于wikis/目录下,每个wiki是独立的内容空间,支持多wiki架构和跨wiki引用。
继续阅读本节完整说明和来源证据。
概述
Wiki管理是Stoa系统的核心功能之一,负责管理知识库中的wiki空间、页面组织、链接解析以及内容综合。Stoa采用vault-root结构,所有wiki内容位于wikis/目录下,每个wiki是独立的内容空间,支持多wiki架构和跨wiki引用。
Wiki管理的核心职责包括:
- 创建和配置新的wiki
- 管理wiki的活动状态和默认上下文
- 解析和验证wiki间的链接关系
- 驱动内容综合(synthesis)机制
- 维护wiki索引和元数据
资料来源:README.md
资料来源:[README.md]()
任务协作系统
任务协作系统是 Stoa 知识管理平台的核心子系统之一,负责管理任务(task)类型页面的生命周期、任务分发与认领、以及通过 Channel 机制实现跨智能体(agent)的任务协调。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
任务协作系统是 Stoa 知识管理平台的核心子系统之一,负责管理任务(task)类型页面的生命周期、任务分发与认领、以及通过 Channel 机制实现跨智能体(agent)的任务协调。
系统的设计目标包括:
- 结构化任务管理:通过标准化的 frontmatter schema 定义任务元数据,确保任务状态、优先级和归属的完整性
- 智能体协调:支持通过 Channel 进行任务公告和认领,实现多智能体环境下的工作分配
- 状态追踪:提供任务状态流转的完整生命周期管理,从草稿(draft)到归档(archived)
- 索引与查询:基于 VaultIndex 的全文检索能力,支持按类型、wiki、状态等维度查询任务
资料来源:src/core/frontmatter.ts:1-50
核心数据模型
页面类型体系
Stoa 采用统一的页面类型系统,任务(task)是其中一种核心类型。系统定义了以下类型常量用于过滤和分类:
// 知识类型(硬知识,可合成)
const KNOWLEDGE_TYPES = ["concept", "decision", "spec", "source"];
// 执行类型(过程性知识)
const EXECUTION_TYPES = ["guide", "idea", "question", "task", "move"];
页面状态枚举
任务页面使用统一的 PageStatus 枚举定义状态:
| 状态值 | 含义 | 使用场景 |
|---|---|---|
draft | 草稿 | 任务刚创建,尚未激活 |
active | 活跃 | 任务正在执行中 |
accepted | 已接受 | 任务已被认领并确认 |
superseded | 已替代 | 任务已被新任务替代 |
archived | 已归档 | 任务完成或放弃后归档 |
资料来源:src/core/frontmatter.ts:15-17
Inbox 项结构
Inbox(收件箱)是任务分发的基础机制。系统通过解析 frontmatter 中的特定字段将页面路由到相应的 Inbox:
export interface InboxEntry {
id: string;
wiki: string;
path: string;
title: string;
type: NoteType;
updated: string;
created: string;
}
Channel 协作机制
Channel 是 Stoa 中实现任务公告和实时协作的核心组件。它本质上是一个命名频道,用于:
- 任务公告:将新任务发布到特定频道
- 认领机制:智能体通过 Channel 认领分配给它的任务
- 活动聚合:按频道聚合 24 小时内的活动摘要
Channel 摘要结构
export interface ChannelSummary {
name: string; // 频道名称(kebab-case)
wiki: string; // 所属 wiki
lastEntry: EntryInfo | null; // 最新条目
count24h: number; // 24小时内条目数
}
Channel 聚合逻辑
系统通过以下流程聚合 Channel 摘要:
graph TD
A[查询所有 journal 类型页面] --> B[按 channel 分组]
B --> C{是否超过 24 小时?}
C -->|是| D[跳过计数]
C -->|否| E[count24h++]
E --> F[更新 lastEntry]
D --> G[返回排序后的 ChannelSummary 列表]
E --> G处理逻辑的核心代码:
for (const p of pages) {
const channel = p.channel;
if (typeof channel !== "string" || !channel) continue;
const key = `${p.wiki}::${channel}`;
if (p.created >= sinceIso) summary.count24h++;
if (!summary.lastEntry || p.created > summary.lastEntry.ts) {
// 读取文件获取 author 和 body excerpt
summary.lastEntry = {
id: p.id,
channel,
wiki: p.wiki,
author: String(fm.author ?? "unknown"),
ts: p.created,
excerpt,
pageId: p.id,
};
}
}
资料来源:src/core/channel.ts:30-60
任务生命周期管理
任务创建
任务通过 writePage 函数创建,系统自动处理:
- 生成规范的文件路径:
tasks/<slug>.md - 解析并验证 frontmatter
- 写入文件系统并更新索引
export interface WritePageInput {
id: string;
type: NoteType;
wiki: string;
frontmatter: Record<string, any>;
body: string;
expectedUpdated?: string;
}
任务路径映射
系统使用 pathForPage 函数将页面 ID 映射到文件系统路径:
// 任务类型路径格式
path = join(vaultPath, "wikis", wiki, "tasks", `${id}.md`);
智能体协作工作流
任务分发流程
graph LR
A[任务创建] --> B[写入 tasks 目录]
B --> C[更新 VaultIndex]
C --> D[Channel 公告]
D --> E[智能体感知]
E --> F[任务认领]
F --> G[状态更新为 accepted]硬知识类型判定
在协作系统中,系统需要区分"硬知识"(可合成的知识资产)和"执行型"知识。任务属于 EXECUTION_TYPES:
const HARD_KNOWLEDGE_TYPES = new Set(["concept", "decision", "spec", "source"]);
// 任务不属于硬知识,不参与合成债务检测
const type = String(page.type);
if (HARD_KNOWLEDGE_TYPES.has(type)) {
// 参与合成债务检测
}
资料来源:src/core/lint-checks/synthesis-debt.ts:40-60
Channel 名称规范
Channel 名称必须符合 kebab-case 格式,lint 检查会验证格式:
| 规则 | 正则表达式 | 示例 |
|---|---|---|
| 有效格式 | ^[a-z0-9]+(-[a-z0-9]+)*$ | feature-x, bug-fix |
| 无效格式 | 包含大写或特殊字符 | myChannel, feature_x |
// Lint 检查代码
if (p.channel && !/^[a-z0-9]+(-[a-z0-9]+)*$/.test(p.channel)) {
diagnostics.push({
severity: "warning",
code: "BAD_CHANNEL_FORMAT",
message: `channel "${p.channel}" must be lowercase kebab-case`
});
}
配置与验证
Frontmatter Schema 验证
系统使用 Zod 进行运行时验证,确保任务元数据的完整性:
const draftSchema = z.object({
id: z.string().regex(/^[a-z0-9-]+$/),
title: z.string().min(1),
type: NoteType,
created: z.string().regex(ISO_DATE),
channel: z.string().regex(KEBAB).optional(),
});
验证规则:
id:仅允许小写字母、数字和连字符created:必须是 ISO 日期格式YYYY-MM-DDchannel:必须是 kebab-case 格式
资料来源:src/core/frontmatter.ts:50-70
索引查询能力
VaultIndex 提供强大的查询能力,支持按多个维度过滤任务:
export function queryPages(
idx: VaultIndex,
filters: {
wiki?: string;
type?: string;
status?: string;
layer?: "knowledge" | "execution" | "all";
}
): IndexedPage[]
支持的过滤维度:
wiki:限定 wiki 范围type:匹配页面类型status:匹配页面状态layer:按知识层过滤(knowledge 或 execution)
系统集成
与 Lint 系统集成
任务协作系统与全局 lint 检查集成,确保数据质量:
| 检查项 | 严重级别 | 说明 |
|---|---|---|
BAD_CHANNEL_FORMAT | warning | Channel 名称格式不符合 kebab-case |
FILENAME_ID_MISMATCH | warning | 文件名与 ID 不匹配 |
SNIPPET_NO_IMPLEMENTATION | warning | 带有 snippet 标签的页面缺少 implementation 字段 |
// 示例:遍历所有页面检查 channel 格式
for (const p of idx.pages) {
if (input.wiki && p.wiki !== input.wiki) continue;
if (p.channel && !/^[a-z0-9]+(-[a-z0-9]+)*$/.test(p.channel)) {
diagnostics.push({ /* ... */ });
}
}
与 Synthesis 系统集成
虽然任务本身不参与合成债务检测,但任务可以引用合成的知识资产:
// 合成页面可以引用任务
资料来源:inputIds.map(i => `[[wikis/${wiki}/${typeFolderForId(i)}/${i}]]`)
资料来源:src/core/synthesize.ts:40-50
总结
任务协作系统是 Stoa 平台中连接知识管理与智能体执行的关键桥梁。它通过:
- 标准化数据模型:基于 Zod schema 的类型安全定义
- Channel 机制:实现跨智能体的任务公告和认领
- 状态流转管理:完整的任务生命周期支持
- 索引与查询:高效的 VaultIndex 查询能力
- 质量保障:集成 lint 检查确保数据完整性
该系统设计遵循单一职责原则,将任务提取、状态管理、Channel 协作等功能模块化,便于维护和扩展。
资料来源:[src/core/frontmatter.ts:1-50]()
Claims与Evolution系统
Claims与Evolution系统是stoa项目的核心智能体能力框架,负责管理知识主张的验证、置信度计算以及智能体画像的动态演进。该系统通过半衰期衰减机制、证据链追踪和多维度评分算法,实现了知识可信度评估与能力成长的闭环管理。
继续阅读本节完整说明和来源证据。
系统概述
Claims与Evolution系统是stoa项目的核心智能体能力框架,负责管理知识主张的验证、置信度计算以及智能体画像的动态演进。该系统通过半衰期衰减机制、证据链追踪和多维度评分算法,实现了知识可信度评估与能力成长的闭环管理。
Claims(知识主张)作为系统的基本单元,承载了智能体对特定知识点的断言及其元数据。Evolution(进化)系统则利用Claims集合,通过聚类分析和移动推荐算法,驱动智能体画像的能力升级与专业化发展。
核心设计目标:
- 为知识断言提供可量化的置信度评估
- 通过时间衰减机制保持知识库的新鲜度
- 基于证据质量自动调整主张可信度
- 支持多智能体协作场景下的知识共享与验证
资料来源:[src/core/evolution.ts:1-30]()
CLI命令参考
本文档全面介绍 stoa CLI 的命令结构、用法模式及核心命令详解。stoa 是一个基于 MCP(Model Context Protocol)的知识库管理系统,通过命令行接口提供笔记检索、内容捕获、任务协作等功能。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
stoa CLI 是 vault-mcp 服务器的命令行封装,提供与 MCP 工具等效的操作能力。所有命令均支持通过 --vault 参数指定 vault 路径,或通过环境变量 STOA_VAULT_PATH 设置默认路径。资料来源:README.md:1-50
stoa --vault=/path/to/vault recall <topic>
stoa --vault=/path/to/vault inbox "thought to capture"
stoa --vault=/path/to/vault list-wikis
环境变量 STOA_VAULT_PATH 可替代每次调用时的 --vault= 参数,提升使用效率。资料来源:README.md:45-50
命令架构
stoa CLI 采用Commander框架进行命令解析,支持多层级子命令结构。命令注册遵循统一模式,每个命令模块负责注册自身的参数解析和行为逻辑。资料来源:src/cli/commands/new-wiki.ts:1-15
graph TD
A[stoa CLI] --> B[--vault 路径选项]
A --> C[命令主体]
C --> D[recall]
C --> E[inbox]
C --> F[synthesize]
C --> G[channel-post]
C --> H[task-create]
C --> I[bootstrap-repo]
C --> J[new-wiki]
C --> K[list-wikis]核心命令详解
recall — 主题检索
recall 命令根据关键词检索 vault 中的相关页面,返回匹配的页面列表及相关性评分。
stoa --vault=/path/to/vault recall <topic>
功能说明: 该命令通过全文索引和分词机制匹配包含指定主题的笔记内容,返回最多25条相关结果。资料来源:src/core/index.ts:1-30
检索结果包含页面ID、标题、wiki归属及更新时间等元数据,支持通过 --limit 参数调整返回数量。
inbox — 快速捕获
inbox 命令用于即时捕获思绪或临时笔记,将其写入当前激活 wiki 的 inbox 目录。
stoa --vault=/path/to/vault inbox "thought to capture"
功能说明: 捕获的内容会自动添加时间戳并生成唯一ID,适合记录快速闪现的想法而不打乱现有工作流。资料来源:src/cli/commands/inbox.ts:1-20
synthesize — 合成页面生成
synthesize 命令从多个源页面编译生成综合报告,适用于知识整合与摘要生成场景。
stoa --vault=/path/to/vault synthesize --topic "主题名称"
功能说明: 系统根据主题相关性从 vault 中选取相关页面,自动生成包含引用来源的综合文档。生成结果保存为 synthesis-*.md 格式的草稿页面。资料来源:src/core/synthesize.ts:1-50
channel-post — 频道消息发布
channel-post 用于向协调频道发布消息,支持跨实例通信与任务协调。
stoa --vault=/path/to/vault channel-post --channel <channel-name> --message <content>
功能说明: 频道消息遵循 YAML 格式规范,支持结构化数据传递。消息发布后可供其他 MCP 客户端或订阅者消费。资料来源:src/cli/commands/channel-post.ts:1-25
task-create — 任务创建
task-create 命令用于在 vault 中创建新任务,支持原子性任务声明与竞态处理。
stoa --vault=/path/to/vault task-create --title <title> --description <desc>
功能说明: 任务创建采用乐观锁机制防止并发冲突,后到的声明请求会收到 AlreadyClaimedError 错误。资料来源:README.md:30-35
bootstrap-repo — 仓库引导
bootstrap-repo 命令为消费仓库初始化 MCP 配置和 CLAUDE.md 片段,建立与 vault 的连接。
stoa --vault=/path/to/vault bootstrap-repo --target <repo-path>
功能说明: 该命令在目标仓库中写入 .mcp.json 配置文件和 CLAUDE.md 引导文件,完成自动化集成设置。资料来源:src/cli/commands/bootstrap-repo.ts:1-20
new-wiki — 新建 Wiki
new-wiki 命令脚手架化一个新的 wiki 空间,包括必要的文件夹结构和初始化文件。
stoa new-wiki <name> --mode <mode> --scope <scope>
参数说明:
| 参数 | 必填 | 说明 |
|---|---|---|
<name> | 是 | Wiki 名称 |
--mode | 是 | 创建模式:idea-map、project-doc、learning、mixed |
--scope | 是 | Wiki 作用域定义 |
功能说明: 新建的 wiki 包含 map.md、index.md、wiki 本地的 CLAUDE.md 等标准文件。资料来源:src/cli/commands/new-wiki.ts:1-18
环境变量
| 变量名 | 说明 | 优先级 |
|---|---|---|
STOA_VAULT_PATH | 设置默认 vault 路径 | 高于 .active-wiki 文件 |
STOA_DEFAULT_WIKI | 设置默认 wiki 名称 | 高于配置文件 |
STOA_DEFAULT_FAMILY | 设置默认家族名称 | 高于配置文件 |
环境变量设置后可省略 --vault 参数,直接使用命令主体。资料来源:README.md:45-50
Wiki 参数解析顺序
当命令涉及 wiki 作用域时,系统按以下优先级解析 wiki 标识:
- 显式
wiki:参数 --default-wiki=<name>服务器启动参数- vault 根目录的
.active-wiki文件 - 无匹配时抛出错误
资料来源:README.md:40-45
命令执行流程
sequenceDiagram
participant CLI as 命令行
participant CMD as 命令处理器
participant CORE as 核心模块
participant FS as 文件系统
CLI->>CMD: 解析参数与选项
CMD->>CMD: 加载上下文配置
CMD->>CORE: 调用核心业务逻辑
CORE->>FS: 读写 vault 数据
FS-->>CORE: 返回操作结果
CORE-->>CMD: 格式化输出
CMD-->>CLI: 显示结果输出格式
CLI 命令的输出遵循统一格式,包含操作状态和结果数据:
- 成功操作: 返回 JSON 格式的结构化结果
- 错误情况: 返回错误码和描述信息
- 列表查询: 返回数组格式的多项结果
相关命令索引
| 分类 | 命令 | 功能 |
|---|---|---|
| 读取 | recall | 主题检索 |
| 写入 | inbox | 快速捕获 |
| 写入 | synthesize | 合成页面 |
| 协作 | channel-post | 频道消息 |
| 协作 | task-create | 任务创建 |
| 系统 | bootstrap-repo | 仓库引导 |
| 系统 | new-wiki | 新建 wiki |
资料来源:[README.md:40-45]()
失败模式与踩坑日记
保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。
安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。
假设不成立时,用户拿不到承诺的能力。
新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
下游已经要求复核,不能在页面中弱化。
Pitfall Log / 踩坑日志
项目:BrettNye/stoa
摘要:发现 7 个潜在踩坑项,其中 0 个为 high/blocking;最高优先级:配置坑 - 可能修改宿主 AI 配置。
1. 配置坑 · 可能修改宿主 AI 配置
- 严重度:medium
- 证据强度:source_linked
- 发现:项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主,或安装命令涉及用户配置目录。
- 对用户的影响:安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。
- 建议检查:列出会写入的配置文件、目录和卸载/回滚步骤。
- 防护动作:涉及宿主配置目录时必须给回滚路径,不能只给安装命令。
- 证据:capability.host_targets | github_repo:1229401738 | https://github.com/BrettNye/stoa | host_targets=mcp_host, claude, claude_code
2. 能力坑 · 能力判断依赖假设
- 严重度:medium
- 证据强度:source_linked
- 发现:README/documentation is current enough for a first validation pass.
- 对用户的影响:假设不成立时,用户拿不到承诺的能力。
- 建议检查:将假设转成下游验证清单。
- 防护动作:假设必须转成验证项;没有验证结果前不能写成事实。
- 证据:capability.assumptions | github_repo:1229401738 | https://github.com/BrettNye/stoa | README/documentation is current enough for a first validation pass.
3. 维护坑 · 维护活跃度未知
- 严重度:medium
- 证据强度:source_linked
- 发现:未记录 last_activity_observed。
- 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
- 建议检查:补 GitHub 最近 commit、release、issue/PR 响应信号。
- 防护动作:维护活跃度未知时,推荐强度不能标为高信任。
- 证据:evidence.maintainer_signals | github_repo:1229401738 | https://github.com/BrettNye/stoa | last_activity_observed missing
4. 安全/权限坑 · 下游验证发现风险项
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 对用户的影响:下游已经要求复核,不能在页面中弱化。
- 建议检查:进入安全/权限治理复核队列。
- 防护动作:下游风险存在时必须保持 review/recommendation 降级。
- 证据:downstream_validation.risk_items | github_repo:1229401738 | https://github.com/BrettNye/stoa | no_demo; severity=medium
5. 安全/权限坑 · 存在评分风险
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 对用户的影响:风险会影响是否适合普通用户安装。
- 建议检查:把风险写入边界卡,并确认是否需要人工复核。
- 防护动作:评分风险必须进入边界卡,不能只作为内部分数。
- 证据:risks.scoring_risks | github_repo:1229401738 | https://github.com/BrettNye/stoa | no_demo; severity=medium
6. 维护坑 · issue/PR 响应质量未知
- 严重度:low
- 证据强度:source_linked
- 发现:issue_or_pr_quality=unknown。
- 对用户的影响:用户无法判断遇到问题后是否有人维护。
- 建议检查:抽样最近 issue/PR,判断是否长期无人处理。
- 防护动作:issue/PR 响应未知时,必须提示维护风险。
- 证据:evidence.maintainer_signals | github_repo:1229401738 | https://github.com/BrettNye/stoa | issue_or_pr_quality=unknown
7. 维护坑 · 发布节奏不明确
- 严重度:low
- 证据强度:source_linked
- 发现:release_recency=unknown。
- 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
- 建议检查:确认最近 release/tag 和 README 安装命令是否一致。
- 防护动作:发布节奏未知或过期时,安装说明必须标注可能漂移。
- 证据:evidence.maintainer_signals | github_repo:1229401738 | https://github.com/BrettNye/stoa | release_recency=unknown
来源:Doramagic 发现、验证与编译记录