npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

codeontic

v0.14.0

Published

受本体论启发的行为建模引擎:把「系统应该怎么运转」写成机器可校验的模型并绑定到真实代码,每次 PR 零 LLM 对账,防止实现与认知漂移。

Readme


起点是一个我们答不上来的问题

一次上线评审,运维指着一个大部分由 agent 写出来的服务问:"这些代码你们还控制得住吗?"

老实说:控制不住——至少不是他说的那种控制。没人逐行读过,以后也不会有人去读。

但往回走不是答案。手写更慢,而且差距还在拉大;agent 写码这件事是单向门,这个项目直接把它当成既定前提,不再论证。所以"控制"只能换个意思:不是有人全读过,而是系统应该怎么运转,被写在了一个机器能拿来对账的地方。

多读代码解决不了这个问题

一个真实的仓库是几百个文件、几十万行。人读不完,agent 也读不准——塞不进上下文,检索回来的是片段,而片段足够让它给出一个听起来对、其实错的答案。"先把代码通读一遍"对人对 agent 都不成立。

而且真正要紧的问题也不是某个文件写得对不对,是:这套系统里有哪些会自己往前走的机器?一个请求怎么从 A 走到 B?哪里根本没人守着? 这些答案不在任何一个文件里——所以谁也查不到,所以每个人脑子里那张系统图都在悄悄过期。

办法:在代码之上再加一层

没人靠读机器码去控制一个现代系统。我们在它上面加了一层语言,然后让编译器负责让两边保持一致。这件事再做一次,往上一层:在源码之上放一层行为模型,写清系统应该怎么运转,再让一个确定性的检查器逼着代码对齐它。

这一层不是文档。文档没有办法"当场出错";模型是结构化的,绑在真实代码符号上,每次 PR 都被核对一遍。

建什么模

五种固定节点,写成 YAML,一个节点一个文件:

| | | | --- | --- | | loop(循环) | 会自己往前走的机器:状态机、轮询、重试链、渲染循环 | | flow(链路) | 一段端到端的旅程——要么由若干 loop 按执行先后串成,要么直接绑在代码上(CLI 路径、一次性管线) | | junction(交接点) | 两个东西交棒的位置,最容易出问题,所以单独记录、单独打分 | | scenario(场景) | 用业务的话写下的一条行为:给定 / 当 / 则,并指向一个真实测试 | | debt(旧账) | 看着像行为、但查下来不是的东西:死状态机、声明了却没兑现的能力 |

# .codeontic/model/loops/*.yaml —— 一个后台控制循环(示例是虚构的)
- id: L1
  kind: loop
  title: Order 状态机
  boundary: "pending → processing → shipped/cancelled;cancelled 是终态"
  owner: packages/orders
  anchors: ["packages/orders/src/order-service.ts#OrderService"]  # 绑定到真实代码符号
  consumes_queues: ["order:process"]                              # 按名字对账生产和消费
  scenarios: [GWT-A1-001]                                         # GWT 场景,verified_by 指向真实测试

完全没有后台循环的仓库——CLI、构建工具、一次性管线——直接给旅程建模:

# .codeontic/model/flows/*.yaml —— 自己带代码绑定的旅程
- id: C1
  kind: flow
  shape: anchored                            # 直接绑定到代码(composed 则由其他节点组成)
  title: 安装一个 skill
  anchors: ["src/install.ts#install"]        # 跟 loop 一样的绑定方式
  scenarios: [GWT-C1-001]

想法从哪来。 这套设计受本体论启发:用一套固定的概念和关系,把一个领域里"有什么、彼此怎么关联"写成机器能处理的结构。上面五种节点就是一个专门描述"系统行为"的小本体,只是方向反了过来——传统本体从现实里归纳,现实永远是对的;这里的模型是规范:先写下系统应该怎么运转,再让代码来对齐。归纳出来的图只能描述现状,立成规范的模型才能审判现状。

模型才是真相源,代码只是投影

这是整件事真正颠倒的地方:模型说了算,代码只是它当前的一次投影。 而投影是可以重写、可以重新生成、可以扔掉的——只要它投出来的骨架没变。在一个由 agent 写码的仓库里,这恰好是你最想要的性质。

所以两边对不上的时候,结论不是"模型过期了",而是代码欠模型一笔账——就像编译器对它吐出的汇编有裁判权,方向从不反转。

从代码里算出来的 code graph 做不到这件事:它是代码的函数,所以代码永远"没错",它只能告诉你代码长什么样。codeontic 保留一份独立的真相源,从三个方向核对:

  • conformance——模型 → 代码:给每个建模行为打分 met / partial / gap,缺什么点名什么。
  • reconcile——代码 → 模型:找代码里有、模型没登记的信号(队列、定时器、轮询)。
  • coverage——模型自查:多少节点真的绑到了代码上。

模型怎么保证自己没说谎

模型里的每一条声明,在三个地方跟真实世界扣住,每次 PR 由确定性门禁核对:

  1. 行为绑定到代码符号:anchors: path#symbol;
  2. 行为写成 GWT 场景:给定 / 当 / 则,用业务的话写;
  3. 场景指向真实测试:verified_by。测试标题是带空格的句子?写 {file, text} 就行。

这也是它顺带把测试完善度摆出来的方式,而且是结构层面的审计:每一个建模行为——包括每一个交接点,也就是两个组件交棒的位置——要么有场景指向一个真实存在的测试,要么就被点名成缺口。真实仓库上跑一遍,浮出来的是"这些行为根本没人写过场景"和"这些场景绑的测试文件已经没了"——这两样,覆盖率百分比看不见。

机器核对的是这些东西存不存在、指的地方对不对。它不判断"这个测试是否真的测到了场景说的事"——要判断那个就得跑你的代码,而门禁永远不跑。这条线是故意画的,凡是报数字的地方都写着这句话。

拿它来做什么

  • 高频、低压力地重构。 代码只是投影,怎么改都行,改完跑一遍 conformance,它告诉你骨架还在不在。骨架稳定,代码流动,甚至可以是一次性的。
  • 给人做技术决策的依据。 同一件事有四份互不知道的实现、一整套写完了但生产上没人用的机制、同一种循环写法散在三个不相干的包里——这些都是待拍板的决策,而它们只有在整个系统摆到一页上时才看得见。
  • 让 agent 查逻辑,而不是猜。 codeontic mcp 按需提供模型切片(影响面、场景、证据),agent 回答问题靠的是模型,不是检索器碰巧捞到的那几段。
  • PR 阶段校验对齐。 门禁亚秒出结果、不调任何模型,所以每次改动都跑得起——漂移在制造它的那个 PR 里就被抓住,而不是两个季度以后。

一个真实的例子

earendil-works/pi 是个公开的 agent 工具仓库:10 个 package,约 670 个 TypeScript 源文件。整个仓库建完是这样:

| | | | --- | --- | | 模型 | 30 loop · 19 flow · 7 junction · 4 debt · 51 scenario | | 怎么建的 | 5 个并行 agent 会话,加一次人工合并裁决 | | 门禁 | check --strict-anchors → exit 0,零 warning | | 覆盖 | 绑定 52 个代码文件;最近 26 次提交里 13 次改到它们(50%) | | 打分 | 43 met · 7 partial · 2 gap |

直接打开完整交互地图——开页就是一张全景图:所有建模节点按代码包分区,然后才是链路、建模细节,欠账放在最后。每个节点都能点开,代码链接指向 pi 在 666d897 的真实文件。它是一个自包含的 HTML 单文件,也在仓库里(docs/examples/pi-overview.html),下载后离线可开。

pi 是个健康、活跃的仓库。这样的账每个大仓都有,区别只是有没有一张图把它摆出来:

  • 有三处功能,代码写完了,但生产路径上没有任何人在用。
  • 一个包里有四份互相不知道的"查过期就刷新"代码。单看每份都对,放在一起就是一个要不要合并的问题。
  • 同一种写法——setTimeout 的回调里再挂一个 setTimeout——在三个不相干的包里各出现一次:渲染节流、SQLite 租约心跳、WebSocket 保活。只搜 setInterval,一个都搜不到。

最后这条解释了为什么值得建全仓:跨包的模式,只建一个子系统永远看不见。方法和全部证据:Proposal 016。

快速开始

npx codeontic init          # 生成 model 骨架 + agent 指令 + /codeontic 前门
npx codeontic check . --repo-root . --strict-anchors   # 确定性门禁,亚秒出结果
npx codeontic conformance . --repo-root .              # met / partial / gap 成绩单
npx codeontic overview . --repo-root .                 # 上面那张交互式系统地图

init 写出 .codeontic/ 骨架和一套 agent 指令:你仓库里的 coding agent 照着它扫代码、起草模型。草稿由你审,没核实的不落库。

命令

| 命令 | 做什么 | 挡不挡 PR | | --- | --- | --- | | check | 确定性门禁:schema、引用完整、图无环、锚点存在、AST 不变量。另有两项一致性检查只报 warning:两个节点绑定同一个符号、正文引用了不存在的 id。--diff 只查增量 | 挡——唯一会挡的 | | conformance | 给每个建模行为打分:met / partial / gap,缺什么点名什么 | 只提醒 | | reconcile | 找代码里有、模型没登记的信号 | 只提醒 | | coverage | 模型自查:多少节点真的绑到了代码 | 只提醒 | | backtest | 最近 N 个改过 .ts/.tsx 的提交里,多少落在模型绑定的文件上 | 只提醒 | | overview | 交互式系统地图:全景图 → 链路 → 建模细节 → 欠账 | — | | graph | 整张模型的 HTML,按打分上色 | — | | topology | 按声明的 component + 抽取到的事实画组件依赖图 | — | | snapshot | 每晚全量扫一遍,出漂移报告 | 永不挡 | | impact <id> | 改这里会牵动什么 | — | | mcp | 起一个 MCP server,agent 按需查模型切片,不用通读 spec | — |

--strict-anchors 只把两种"错就是错"的检查升成 error:锚点写法不合法、绑定的文件不存在。文件还在、只是里面找不到那个符号——这种永远只是 warning:它靠全文匹配,一次正常重构就可能误伤,老误报的门禁最后会被人关掉。但它没有被扔掉:conformance 会用它,锚点失效的节点拿不到 met。门禁宽,成绩单严。

coding agent 怎么用它

不用教。init 已经把说明书放进了你的仓库:

  • .claude/skills/codeontic/SKILL.md——Claude Code 自动识别成 /codeontic,按意图分路:发现建模(小仓单 agent;大仓走 .codeontic/agent/loop-discovery-parallel.md 分域并行)、跑门禁、查缺口、出图、查模型。Cursor、Codex 这类能读文件的 agent,读同一份文件照做。
  • .codeontic/agent/ 三份指令——发现建模的四遍扫描法、给 PR 模板加声明栏、按你仓库的惯例配 CI。
  • codeontic mcp——起一个 MCP server,agent 按需查模型切片(影响面、场景、证据),不用通读整个模型。

哪些行为值得建模,让 LLM 找;模型是不是还诚实,让引擎管。门禁本身不调 LLM、不联网、不执行你的代码。

要花什么

先把成本说清,这是筛选,不是劝退:

  • 建模烧 token。 一个子系统(8–15 个节点)大约一次 agent 会话;上面那个 670 文件的仓库,用了 5 个并行会话加一次人工合并。
  • 模型要进 git。 .codeontic/model/ 是一堆 YAML,一个节点一个文件。它是资产:提交、review,跟代码同等对待。生成的报告在 .codeontic/ws/,用完即弃,gitignore 掉。
  • 门禁不花钱。 check 和 conformance 亚秒出结果,不调用任何模型。日常唯一的成本:代码变了,让 agent 起草模型更新,你确认。

什么仓库能用

TS/JS 仓库是一等公民。 符号级核实认 .ts .tsx .mts .cts .js .jsx .mjs .cjs;AST 不变量扫 .ts;backtest 只统计动过 .ts/.tsx 的提交。

其他语言:模型照用,校验打折。 模型本身和门禁里的结构检查(schema、引用、无环、场景、旧账)不挑语言;锚点的文件存在性也不挑语言——这恰好是 --strict-anchors 会升级的那类。打折的部分,直说:

  • 符号级检查在 TS/JS 之外一律回答"判断不了"。不会误报,但也等于没查;conformance 靠它降级的那条链路,也就不会触发。crux 和 verified_by 文本锚同样受限。
  • backtest 会是空的:它只认 .ts/.tsx 提交。
  • reconcile 目前只认 TS。适配器接口是开放的,抽取器随你写,但喂给它的候选文件来自一句写死的 git grep -- "*.ts"——Python、Go 的抽取器拿不到文件。

硬前提:得是 git 仓库。 facts、backtest、snapshot 都要调 git。

有些代码不值得建模。 建模有成本,只在"看不清、错不起"的地方划算:后台机制、跨组件交接、多步旅程。纯函数库(日期工具、校验器)不值,代码自己就说清了;没有交接、没有多步推进的薄 CRUD 不值;马上要删掉重写的代码更不值。一句话判断:新人光读代码,会不会理解错? 不会,就别建。

设计红线

  • 门禁零 LLM、零网络、零代码执行——快、便宜、可复现。
  • 缓存不参与正确性:冷跑和热跑逐字节一致。
  • 快照和漂移报告永不挡 PR。
  • LLM 只出草稿;维护者核实之后才能落库。

适配器:开放接口

包里不带任何适配器。你的仓库自己带一个小抽取器,放在 .codeontic/adapter/,读你这套技术栈的实现信号(队列名、定时器、轮询)。加 --strict-adapter,缺了适配器就挡 CI,而不是悄悄跳过。让 init 生成的 CI 锁定 codeontic 版本,别用 @latest——新版本不该有机会在绿灯下悄悄改变门禁的含义。

项目现在到哪了

很早期。 引擎、门禁、地图都是真的,每天在真实仓库上跑——上面那张 pi 的图是生成出来的,不是效果图——但项目还年轻,接口还在动。

  • 目前一等公民是 TypeScript / JavaScript;其他语言拿得到模型和结构层门禁,打折的地方上面已经列清。
  • 先拿一个子系统试,别一上来建全仓:一次 agent 会话、8–15 个节点,一个小时之内你就知道这张图有没有告诉你新东西。
  • 欢迎提 issue,尤其是这两类:"模型表达不了 X"、"门禁把没问题的东西拦了"。这两种反馈直接决定下一步做什么。

想要到达的终态是:人审模型,agent 写码。

参与贡献

见 CONTRIBUTING.md:按 CI 顺序跑的本地门禁、stacked PR 的坑(squash 合并 base 会把子 PR 送错地方,而且哪里都不报错)、新增锚点字段时的扇出契约。

License

见 package.json。