惠斯通MCP
磨刀石是一种用来磨刀的扁平石头。刀刃可以切割,但没有石头,它就会变钝。磨刀者的技能是知道正确的角度和压力——这种判断不能自动化,只能练习。
Whetstone MCP将这一比喻应用于人工智能辅助开发。AI是刀刃。你的判断是石头。每次你拒绝AI输出并解释原因时,你都在磨砺优势。Whetstone捕捉到这些时刻,并将其转化为持久、可查询的约束——因此刀片在对话、项目和团队中保持锋利。
特性
- 捕获拒绝 --以结构化数据的形式记录代理对话中的错误及其原因
- 编码约束 --将重复的拒绝提炼为具有严重性和域的持久、可查询的规则
- 主动式应用程序 --代理在生成输出之前获取约束,因此您不会两次拒绝同一件事
- 模式检测 --尚未编码的类似排斥物的表面簇
- Web仪表板 --约束健康、领域差距、毕业候选人和趋势的实时概述
- 按项目存储 --每个项目都有自己的SQLite数据库,致力于git,因此约束会随代码一起传递
- Git集成 --预推钩导出人类可读的约束快照,使口味变化在差异中可见
- 代理不可知 --与任何MCP兼容的代理(Claude Code、Cursor、Codex、Kiro或其他任何代理)配合使用
- CLI+MCP --每个工具都可以作为代理的MCP工具和人类的CLI子命令使用
运作原理
- 在对话中拒绝AI输出并解释原因
- Whetstone将拒绝作为结构化数据捕获
- 您(或您的代理)将拒绝提炼为约束——编码规则
- 在生成未来输出之前,主动应用约束
- 随着时间的推移,你的品味会变得更加敏锐,并与你的代码一起进行跟踪和版本控制
快速开始
1.安装惠斯通
npm install -g @frontier-collective/whetstone-mcp要更新:再次运行相同的命令。要卸载,请执行以下操作: npm uninstall -g @frontier-collective/whetstone-mcp
开发安装
对于贡献或从源代码运行:
git clone git@github.com:frontier-collective/whetstone-mcp.git ~/tools/whetstone
cd ~/tools/whetstone
make setup要更新,请执行以下操作: git pull && make build --符号链接会自动获取新版本。
2.初始化项目
在任何要使用Whetstone的项目中:
cd ~/projects/my-app
whetstone init这将创建:
my-app/
.whetstone/
whetstone.db # SQLite database for this project's constraints
exports/ # human-readable snapshots (generated on git push)承诺 .whetstone/ 目录到您的仓库,以便约束随代码一起传递。
然后安装预推git挂钩:
whetstone hook这将安装 .git/hooks/pre-push-whetstone (导出脚本)和a .git/hooks/pre-push 调用它的调度程序。如果您已经有一个预推挂钩,在覆盖之前您会收到提示。
3.配置您的AI代理
Whetstone作为MCP服务器运行时,它会在代理启动时自动启动。将其添加到项目的代理配置中:
克劳德代码
创建 .claude/settings.json 在您的项目中:
{
"mcpServers": {
"whetstone": {
"command": "whetstone-mcp",
"env": {
"WHETSTONE_DB": ".whetstone/whetstone.db"
}
}
}
}如果你不跑 npm link,直接引用构建:
{
"mcpServers": {
"whetstone": {
"command": "node",
"args": ["/absolute/path/to/whetstone/dist/index.js"],
"env": {
"WHETSTONE_DB": ".whetstone/whetstone.db"
}
}
}
}光标
在 .cursor/mcp.json:
{
"mcpServers": {
"whetstone": {
"command": "whetstone-mcp",
"env": {
"WHETSTONE_DB": ".whetstone/whetstone.db"
}
}
}
}其他MCP兼容代理
任何支持MCP的代理都可以连接--指向 whetstone (或 node /path/to/dist/index.js)与 WHETSTONE_DB 环境变量集。服务器使用stdio传输。
4.使用它
现在,您的代理对话中提供了以下工具:
| 工具 | 它做什么 |
|---|---|
reject | 记录拒绝——记录错误原因 |
constrain | 从拒绝(接受)中创建持久约束 rejection_ids 链接它们) |
get_constraints | 在生成输出之前获取活动约束 |
search | 跨约束和拒绝的自由文本搜索 |
applied | 将约束标记为已应用(使用情况跟踪) |
link | 将现有的拒绝与约束联系起来——事后关闭飞轮 |
update_constraint | 优化、取代或弃用约束 |
export | 将约束导出为markdown或JSON |
patterns | 表面反复出现的拒绝主题尚未编码 |
list | 浏览按域和编码/未编码状态过滤的拒绝 |
stats | 获取拒绝和约束统计信息 |
db_path | 返回解析的数据库文件路径(诊断) |
不需要特殊的语法——您的代理将这些视为可用的工具,可以在对话中自然地使用它们。
约束生命周期
Rejection (raw event — "this is wrong because...")
→ Constraint (encoded rule, status: active)
→ Graduated (exported to CLAUDE.md, cursor rules, etc.)
→ Deprecated in Whetstone (avoid duplication)废品是原材料。约束是精炼的产品。当约束被证明是持久的时,将其导出到项目的永久文档中,并在Whetstone中弃用。
仪表盘
Whetstone包括一个web仪表板,用于直观地显示项目的约束健康状况。
whetstone dashboard # launch on localhost:1337
whetstone dashboard --port 3000 # use a different port仪表板每5秒自动刷新一次,旨在与您的代理一起运行——在您工作时在浏览器中打开它。
你会看到什么
总结卡 --总拒绝数、约束以及编码到约束中的拒绝百分比。每张卡都包含一个每周增量,显示过去7天的趋势。
未编码图案 --尚未编码为约束的类似拒绝集群。这些都是“你一直说同样的不”的信号。每个集群都显示了一个建议的编码动作,关闭飞轮。
领域差距 --按编码覆盖率排名的域(最低优先)。一个有很多拒绝但限制很少的领域是你编码品味中的一个缺口。
毕业候选人 --已应用8次或更多次的约束,表明它们足够持久,可以升级到项目的永久文档(CLAUDE.md、游标规则等)。
逐渐减弱的约束 --曾经使用过但超过30天未应用的主动约束。这些可能需要刷新、改进或弃用。
近期活动 --最新的拒绝和限制,包括域徽章、时间戳和状态指示器。
仪表板从与MCP服务器相同的SQLite数据库读取数据,因此所有内容都保持同步。运行后 clear-db,仪表板检测到文件更改并自动重新连接。
试试看:完整的演练
本演练使用 make 目标是从命令行练习每个工具。每 make tool-* 命令向MCP服务器发送JSON-RPC调用,这与AI代理使用的协议相同。到最后,你会经历完全拒绝约束飞轮的过程。
先决条件: 跑 make setup 一次安装、构建和链接。
第一步:记录一些拒绝
废品是原材料。每一个都捕捉到了AI输出不够好的时刻。首先在 frontend 域名:
make tool-reject DOMAIN=frontend DESC="Used useEffect to compute derived state"
make tool-reject DOMAIN=frontend DESC="Computed derived values inside useEffect instead of inline"
make tool-reject DOMAIN=frontend DESC="Put a simple string concatenation in a useEffect hook"每个响应都包括拒绝ID和将其编码为约束的建议。请注意,这三个拒绝都是关于同一个根本问题的——对派生状态的useEffect误用。
现在,在不同的域中记录一对夫妇:
make tool-reject DOMAIN=backend DESC="Leaked raw Prisma error message to API response"
make tool-reject DOMAIN=backend DESC="Exposed internal database error in REST endpoint"还有一个无关的前端拒绝:
make tool-reject DOMAIN=frontend DESC="Used a modal dialog for a simple yes/no confirmation"第二步:检测模式
这 patterns 该工具根据每个域内的文本相似性对类似的拒绝进行聚类。这是“你一直说同样的不”探测器:
make tool-patterns您将看到两个集群——三个useEffect拒绝与一个共享主题组合在一起,如 "derived, useeffect, state",两个数据库错误拒绝按主题分组,如 "database, error".模态对话拒绝是独立的(没有集群),因为它是关于另一个问题的。
这是一个信号,表明这些拒绝应该成为约束。
步骤3:对约束进行编码
从集群中选择一个,并阐明一个约束——一个用命令式语气表达的持久规则。这是编码步骤,模糊的“我不喜欢这个”变成了精确的指令:
make tool-constrain \
DOMAIN=frontend \
TITLE="No useEffect for derived state" \
RULE="Compute derived values inline. Never use useEffect or useMemo for values that can be calculated directly from props or state."响应包括约束ID(例如。, 01ABC123).复制它以进行下一步。
步骤4:将拒绝链接到约束
现在关闭飞轮——通过将这些拒绝链接到约束,将其标记为“编码”。使用步骤1中的拒绝ID(记录每次拒绝时打印):
make tool-link ID= RID=
make tool-link ID= RID=
make tool-link ID= RID=你也可以通过 rejection_ids 在步骤3中创建约束时,直接将它们链接到一个镜头中—— constrain 工具接受可选 rejection_ids 参数。
步骤5:检查仪表板
make tool-stats您将看到总拒绝数、仍有多少拒绝未编码(您链接的拒绝已不再未编码)、按域划分的拒绝数以及大多数应用的约束。再次运行模式:
make tool-patternsuseEffect集群消失了——这些拒绝现在被编码了。只剩下未链接的后端集群,告诉你还有一个模式等待编码。
步骤6:在生成输出之前获取约束
这是价值最高的工具。一位代理人打来电话 get_constraints 在生成代码以预先应用您的口味之前:
make tool-get-constraints DOMAIN=frontend返回前端域的活动约束,按使用情况排序——应用最多的约束首先出现。代理会读取这些内容并主动应用它们,这样你就不必两次拒绝同一件事。
步骤7:跟踪实际使用的约束
当代理在生成过程中应用约束时,它会调用 applied 记录如下:
make tool-applied ID=
make tool-applied ID=
make tool-applied ID=跑 make tool-stats 同样,约束现在显示在“应用最多的约束”中,计数为3。随着时间的推移,这些数据揭示了哪些约束实际上是有价值的,哪些约束从未被使用(过时)。
第8步:搜索所有内容
按关键字查找限制和拒绝:
make tool-search QUERY=useEffect
make tool-search QUERY=error在标题、规则、描述、推理和标签之间进行搜索。
第九步:出口毕业
当约束被证明是持久的时,将其导出到项目的永久文档中:
make tool-export FORMAT=markdown
make tool-export FORMAT=json
make tool-export DOMAIN=frontend FORMAT=markdown将标记粘贴到CLAUDE.md、光标规则或Codex指令中。然后弃用Whetstone中的约束以避免重复:
make tool-update-constraint ID= TITLE="No useEffect for derived state"刚刚发生了什么
您体验了完整的飞轮:
Reject ("this is wrong") x 3
-> Patterns detected ("you keep saying the same no")
-> Constraint encoded ("here's the rule")
-> Rejections linked (flywheel closed)
-> Constraint applied (proactive taste)
-> Usage tracked (what's actually valuable)
-> Exported (graduated to project docs)在实践中,你的AI代理会在对话中完成所有这些工作。您可以自然地拒绝输出,代理会记录它,显示模式,并帮助您对约束进行编码。Makefile目标只是直接查看机器的一种方式。
Git集成
预推钩由以下人员安装 whetstone hook 自动:
- 将所有活动约束导出到临时文件
- 与最新导出进行比较——如果没有变化,则跳过
- 如果更改,则保存到
.whetstone/exports/.md并承诺 - 中止推送,以便包含快照提交——再次推送,它立即完成
这意味着约束更改始终在差异中与其所管理的代码一起可见。带时间戳的文件创建了项目品味演变的历史。
版本控制
Whetstone使用semver自动发布git流:
make version # show current version
make release patch # 0.1.0 → 0.1.1
make release minor # 0.1.0 → 0.2.0
make release major # 0.1.0 → 1.0.0你一定在 develop 一棵干净的工作树的树枝。这 release target自动处理整个git流:
- 构建并运行测试(失败时中止)
- 凸起
package.json和更新CHANGELOG.md - 创建
release/带有标记提交的分支 - 合并到
master然后回到develop - 清理发布分支
完成后,推送并创建GitHub版本:
git push origin master develop --tags
make gh-releaseGitHub 发布
make gh-release 创建一个GitHub Release,其中包含从中提取的注释 CHANGELOG.md。它只显示尚未发布GitHub Release的标签——如果所有内容都已发布,它就会干净地退出。
make gh-release # pick from unreleased tags
make gh-release TAG=v0.0.3 # skip the prompt, release a specific tag完整的发布工作流程:
make release patch # bump, changelog, git-flow merge, tag
git push origin master develop --tags
make gh-release # create GitHub Release with changelog notes
make npm-publish # publish to npm registry命令行命令
两者 whetstone 和 whetstone-mcp 与CLI命令一样工作——它们是相同的。每个MCP工具都可以作为CLI子命令使用。
设置
whetstone init # set up .whetstone/ directory and database
whetstone hook # install pre-push git hook (dispatcher pattern)
whetstone dashboard # launch web dashboard on localhost:1337
whetstone dashboard --port 3000 # use a different port
whetstone --help # show all commands and options捕捉
# Log a rejection
whetstone reject --domain frontend --desc "Used useEffect for derived state" \
--reasoning "Derived values should be computed inline"
# Encode a constraint (link rejections by ID)
whetstone constrain --domain frontend --category pattern \
--title "No useEffect for derived state" \
--rule "Compute derived values inline, never in useEffect" \
--severity critical --rejection-ids "01ABC123,01DEF456"查询
# Fetch constraints before generating code
whetstone get-constraints --domain frontend
whetstone get-constraints --severity critical
# Search across everything
whetstone search --query useEffect
whetstone search --query error --type constraints
# Surface unencoded rejection patterns
whetstone patterns
whetstone patterns --domain backend
# Browse rejections
whetstone list --domain frontend
whetstone list --status unencoded --limit 20
# View statistics
whetstone stats
# Export for graduation to project docs
whetstone export --format markdown
whetstone export --domain backend --format json --output constraints.json管理
# Track constraint usage
whetstone applied --id 01ABC123
# Link rejections to a constraint
whetstone link --id 01ABC123 --rejection-ids 01DEF456,01GHI789
# Evolve a constraint
whetstone update-constraint --id 01ABC123 --severity critical
whetstone update-constraint --id 01ABC123 --status deprecated诊断
# Show which database file is being used
whetstone db-path
# Wipe all data and recreate empty database (prompts for confirmation)
whetstone clear-db
whetstone clear-db --force # skip confirmation (for scripting)所有命令接受 --db 以覆盖数据库位置。
发展
使用 make 所有常见操作的目标。跑 make help 查看完整列表。
make setup # install, build, and link globally (first time)
make install # install npm dependencies
make build # compile TypeScript
make dev # watch mode
make test # run tests
make clean # remove dist/ and test database
make init # set up .whetstone/ directory and database
make help # show all targets including MCP tool runnersMCP工具也可以通过Make直接从命令行进行操作:
make tool-reject DOMAIN=backend DESC="Leaked internal error to client"
make tool-constrain DOMAIN=backend TITLE="No raw errors" RULE="Wrap all API errors"
make tool-get-constraints DOMAIN=backend
make tool-search QUERY=error
make tool-stats技术栈
| 技术 | 目的 |
|---|---|
| TypeScript | 服务器语言——最广泛的MCP SDK支持 |
| better-sqlite3 | 原生SQLite绑定——快速、原子写入、WAL模式 |
| @modelcontextprotocol/sdk | 标准MCP服务器实现 |
| ulid | 可排序的唯一标识符 |
