GitHub

deterministic · zero-LLM gate · open source

人审模型,agent 写码。

Humans review the model. Agents write the code.

codeontic 在代码之上建一层逻辑建模——像汇编之上建高级语言一样。流程、循环、模块交接点、测试覆盖,全部建成结构化模型,锚定到真实代码符号上。建模才是真相源,代码只是投影,随时可以重写。

codeontic builds a logic model above your code — like high-level languages above assembly. It models system behavior with a fixed ontology (loops, flows, junctions, scenarios, debts), anchored to real code symbols, verified on every PR. You don't read every line; you still know what the system does.

codeontic——模型是系统的骨架,代码是投影:代码随便改,骨架不失真。

Background

这个项目从一次质疑开始

This project started with a challenge

我们团队很早就用 AI agent 写日常代码。有一次跟运维同学沟通项目细节,发现自己答不上来——agent 写的东西太多了,很多逻辑我们自己也说不清。运维同学直接说:"最终还是要人控制 AI,不能让 AI 控制了咱。"

Our team adopted AI agents for day-to-day coding early on. One day, discussing project details with the ops team, we realized we couldn't answer their questions — agents had written so much code that we'd lost track of the details. Their response was blunt: "Humans need to stay in control of the AI, not the other way around."

他说得对。但回头让人手写代码,效率不允许——这条路走不回去。问题不是要不要用 AI,而是用了之后,怎么不丢掉对系统的掌控。

They were right. But going back to writing everything by hand wasn't an option either. The question wasn't whether to use AI — it was how to keep your grip on the system after you do.

codeontic 就是为了回答这个问题。不是限制 agent,是在代码之上建一层人能审、机器能核对的逻辑模型——你不需要读每一行代码,但你仍然知道系统在做什么。

codeontic was built to answer that question. Not by restricting agents, but by building a logic model above the code — one that humans review and machines verify. You don't read every line, but you still know what the system does.

The problem

代码量在涨,人的理解力没有跟上

Code grows; your understanding doesn't keep up

单仓越来越大

Repos keep growing

几十万行代码,agent 一次读不完,人也不可能从头看一遍。

Hundreds of thousands of lines — too much for an agent's context, and nobody reads it end to end.

行为散落各处

Behavior is scattered

队列消费、定时器、重试链、状态机——系统真正的行为藏在代码各个角落,没有一个地方完整写着"它应该怎么运转"。

Queue consumers, timers, retry chains, state machines — real behavior hides in corners, and nothing states end to end how the system is supposed to run.

agent 写的码没人审

Nobody reviews agent code

agent 产出快,人不再逐行读。脑子里那张系统图很快就旧了——但你还得靠它做技术决策。

Agents produce fast; nobody reads line by line. Your mental picture of the system goes stale — but you still need it to make technical decisions.

The approach

像汇编之上建高级语言一样,在代码之上建一层逻辑模型

Build an abstraction layer above code, like a high-level language above assembly

codeontic 用五种节点——loop(循环)、flow(链路)、junction(交接点)、scenario(场景)、debt(旧账)——给系统行为建模。每个节点锚定到真实的代码符号上,每条场景指向真实的测试。模型就是真相源:代码只是它的投影,可以随时重写。

codeontic models system behavior with five node kinds — loop, flow, junction, scenario, debt — each anchored to real code symbols, each scenario pointing at a real test. The model is the source of truth; code is its projection and can be rewritten at will.

模型与代码之间的三个方向:conformance 从模型到代码打分,reconcile 从代码找回漏登记的信号,coverage 是模型自查。方向从不反转。

01

高频重构,低压力

Refactor often, stress-free

代码怎么改都行——改完跑 conformance,它逐条告诉你结构还在不在。重构的压力从"怕出事"变成"跑一遍就知道"。

Rewrite anything — conformance tells you piece by piece whether the structure survived. Refactoring goes from "afraid to break things" to "run and see."

02

给人做技术决策参考

Inform human decisions

系统里有什么循环在跑、逻辑怎么流转、哪里没有测试守着——一张图摆在面前,做架构决策有据可依。

What loops are running, how logic flows, where nothing guards — a map on the table so architectural decisions have evidence behind them.

03

给 agent 快速查逻辑

Fast logic lookup for agents

agent 不用从头读几十万行代码——查模型就知道这个系统的结构、哪些行为已建模、哪些还有缺口。

Agents don't need to read hundreds of thousands of lines — query the model to know the system's structure, what's modeled, and where the gaps are.

04

PR 阶段校验对齐

PR-stage alignment checks

每次 PR 自动核对代码和模型的对齐度。门禁确定性运行,亚秒出结果,不调 LLM,不跑你的代码。

Every PR automatically checks code-to-model alignment. The gate is deterministic, sub-second, and never calls an LLM or runs your code.

Showcase

实测:670 个文件的仓库,整仓建模

Real test: a 670-file repo, modeled whole

earendil-works/pi,一个公开的 agent 工具仓库。5 次并行 agent 会话建模,一次人工合并裁决。

earendil-works/pi, a public agent-harness monorepo. 5 parallel agent sessions, then one human pass to merge and adjudicate.

60
nodes modeled
51
GWT scenarios
52
files anchored
43 / 7 / 2
met / partial / gap
pi 的系统地图:整仓全景按代码包分区,每个方块是一个建模过的 loop 或入口链路,颜色是落实程度。

Quick start

npx codeontic init          # model skeleton + agent kit + /codeontic skill front door
npx codeontic check . --repo-root . --strict-anchors   # deterministic gate (sub-second, zero-LLM)
npx codeontic conformance . --repo-root .              # met / partial / gap report card
npx codeontic overview . --repo-root .                 # the interactive system map

init 在你的仓库里写出模型骨架和一套 agent 指令。agent 照着它扫代码、识别行为、起草模型节点。你审核之后才落库——机器发现,人来裁决。

init writes a .codeontic/ skeleton and an agent kit: instructions a coding agent in your repo follows to discover behavior and draft the model. You review the drafts; nothing lands unverified.

项目还在早期,欢迎试用

Early stage — come try it

目前已支持 TypeScript / JavaScript 项目,npm 可装,门禁已接通 CI。后续会持续完善多语言支持和建模工具链。

TypeScript / JavaScript projects are fully supported today. Published on npm, CI-ready. Multi-language support and tooling improvements are on the roadmap.

Concept

一套描述系统行为的结构语言

A structural language for system behavior

loop(循环)、flow(链路)、junction(交接点)、scenario(场景)、debt(旧账)——五种节点构成一套封闭的词汇表,专门描述系统应该怎么运转。每一条都锚定到真实的代码符号上:写下来就能核对,核对了就能强制执行。

A closed vocabulary (loops, flows, junctions, scenarios, debts) writes down how the system is supposed to run, anchored to real code symbols so the claims can be evidenced and enforced.

模型不是文档,它绑定在三个地方

Bound to reality in three places

1

行为绑定到代码符号上:anchors: path#symbol

A behavior is pinned to a real code symbol (anchors: path#symbol).

2

行为写成 GWT 场景:given / when / then,用业务的话写。

It is written down as a GWT scenario (given / when / then, in business language).

3

场景指向真实测试:verified_by

The scenario points at a real test (verified_by).

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

A deterministic gate checks all three on every pull request, and conformance grades every modeled behavior met / partial / gap, naming the exact missing piece. The engine verifies that these things exist and point where they claim — it does not judge whether a test truly asserts its scenario. That limit is deliberate: proving it would mean running your code, and the gate never does.

打分成绩单:每个建模行为标 met / partial / gap,缺什么点名什么,顶部有汇总条。

Where the idea comes from

为什么叫 codeontic

Borrowed from ontology, with the direction reversed

名字来自 code + ontic。本体论是个老办法:用一套固定的概念和关系,把一个领域的结构写成机器能处理的形式。codeontic 的五种节点就是一个专为系统行为设计的小本体——不多不少,刚好够写下"这个系统里有什么机制在运转"。

The design borrows from ontology — the old practice of describing a domain as a fixed set of concepts and relations a machine can work with. codeontic's five node kinds are a small ontology purpose-built for system behavior.

关键的区别:传统本体从现实归纳,现实永远对。codeontic 的模型是规范性的——先写下系统应该怎么跑,再让代码来对齐。归纳出来的图只能描述现状;规范性的模型才能审判现状。这也是它能说出"代码错了"的原因。

A classical ontology is induced from reality, and reality is always right. This model is normative: write down how the system is supposed to run, then hold the code to it. An induced graph can only describe the present; a normative model can judge it.

一小段行为图:loop 和 junction 节点按打分上色,其中一个 loop 用虚线连到真实代码符号。

The model

模型长什么样

What the model looks like

.codeontic/model/loops/*.yaml
- id: L1
  kind: loop
  title: Order state machine
  boundary: "pending → processing → shipped/cancelled"
  owner: packages/orders
  anchors: ["packages/orders/src/order-service.ts#OrderService"]
  consumes_queues: ["order:process"]
  scenarios: [GWT-A1-001]
.codeontic/model/flows/*.yaml
- id: C1
  kind: flow
  shape: anchored
  title: Install a skill
  anchors: ["src/install.ts#install"]
  scenarios: [GWT-C1-001]

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

A repo with no background loops at all — a CLI, a build tool, a one-shot pipeline — models its journeys directly instead.

Showcase · earendil-works/pi

整仓建模:60 个节点,191 条锚点

pi, modeled whole: 60 nodes, 191 anchors

pi 是一个公开的 agent 工具仓库:10 个 package,约 670 个 TypeScript 源文件。5 个并行 agent 会话建模,一次人工合并裁决。

pi is a public agent-harness monorepo: 10 packages, ~670 TypeScript source files. The map was built by 5 parallel agent sessions, then one human pass to merge and adjudicate.

model30 loops · 19 flows · 7 junctions · 4 debts · 51 scenarios
built by5 parallel agent sessions, then one human pass to merge and adjudicate
gatecheck --strict-anchors → exit 0, zero warnings
coverage52 code files anchored; 13 of the last 26 commits touched one of them (50%)
conformance43 met · 7 partial · 2 gap
pi 的系统地图:整仓全景按代码包分区,每个方块是一个建模过的 loop 或入口链路,颜色是落实程度。

开页就是整仓全景:按代码包分区,圆角胶囊是入口链路,方块是 loop,颜色是落实程度,虚线是跨包的交接点。往下是 19 条端到端链路、建模细节和旧账清单。

The map opens on the whole-repo panorama: partitioned by package, rounded capsules are entry journeys, boxes are loops, color is conformance status, dashed lines are cross-package junctions. Below it: 19 end-to-end journeys, the modeling detail, and the outstanding ledger.

打开交互地图 ↗Open the full interactive map ↗ 每条链路、每个 loop 都能点开,代码链接指向 pi 在 666d897 的真实文件。单个自包含 HTML,下载后离线可开。 Every flow and loop opens into a drawer, and code links point at pi's real files at 666d897. One self-contained HTML file — it works offline after a download.

它查出了什么

What the map put where a person could see it

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

pi is healthy and actively developed — every large codebase carries a ledger like this one.

3

三处功能代码写完了,但生产路径上没有任何人在用。

Three implementations that are complete but not wired up — finished machinery with no production consumer yet.

4

一个包里有四份互相不知道的"查过期就刷新"代码。单看每份都对,放在一起就是一个要不要合并的问题。

Four independent "check staleness → refresh" implementations that share no code, in one package. Individually reasonable; as a set, a consolidation decision.

1

同一种写法——setTimeout 回调里再挂 setTimeout——在三个不相干的包里各出现一次:渲染节流、SQLite 租约心跳、WebSocket 保活。只搜 setInterval,一个都搜不到。

One loop shape — "a recursive setTimeout that re-arms itself" — living in three unrelated packages: render throttling, a SQLite writer's lease heartbeat, and a WebSocket session pool's keepalive. Grep for setInterval and you miss the entire class.

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

The last one is the argument for modeling the whole repo rather than one subsystem: cross-cutting patterns only exist at full scale.

Docs

命令、工作流与边界

Commands, workflow, and limits

命令

Commands

commandwhat it doesfails a PR?
checkDeterministic gate: schema, reference integrity, acyclic graph, anchor existence, canonical-writer (AST) invariants — plus cross-node consistency as warnings. --diff for incremental runs.yes
conformanceModel → code report card: per-node met / partial / gap + the missing pieceadvisory
reconcileCode → model: extracted signals no model node registeredadvisory
coverageModel self-coverage: how much of the model is anchoredadvisory
backtestCommit-side backtest: of the last N .ts/.tsx-touching commits, how many touched a model-anchored fileadvisory
overviewInteractive system map — panorama, journeys, modeling detail, outstanding ledger
graphSelf-contained, conformance-colored HTML of the whole model
topologyComponent/dependency diagram from declared components + extracted facts
snapshotNightly full scan + drift reportnever a gate
impact <id>What a change here would touch
mcpstdio MCP server, so an agent can query model slices instead of reading the whole spec

Agent workflow

agent 怎么用它

How a coding agent drives it

不用额外配置。init 已经把指令放进了你的仓库,agent 自己会找到。

No training needed — init puts the manual inside your repo.

.claude/skills/codeontic/SKILL.md

Claude Code 自动识别成 /codeontic,按意图分路:发现建模(小仓单 agent;大仓走 loop-discovery-parallel.md 分域并行)、跑门禁、查缺口、出图、查模型。Cursor、Codex 这类能读文件的 agent,读同一份文件照做。

Claude Code picks it up as /codeontic and routes by intent: discovery (single-agent for small repos; loop-discovery-parallel.md partitions large ones), the gate, gaps, maps, model queries. Cursor, Codex, or any agent that can read a file follows the same instructions.

.codeontic/agent/

发现建模的四遍扫描法、给 PR 模板加声明栏、按你仓库的惯例配 CI。

The four-pass discovery method, PR-template setup, CI setup in your repo's own conventions.

codeontic mcp

起一个 MCP server,agent 按需查模型切片(影响面、场景、证据),不用通读整个模型。

An MCP server agents query for model slices (impact, scenarios, evidence) instead of reading the whole model.

分工很清楚:识别行为是 LLM 的事,守住模型的诚实是引擎的事。门禁本身不调 LLM、不联网、不执行你的代码。

Finding the behavior worth modeling is an LLM's job; keeping the model honest is the engine's. The gate itself never calls an LLM, touches the network, or runs your code.

What it costs

代价,先说清楚

Said up front, because this is a filter

建模消耗 token

Discovery burns tokens

建模由 coding agent 在你的仓库里完成。一个子系统约一次 agent 会话;670 文件的 pi 仓库用了 5 次并行会话加一次人工合并。

The modeling is done by a coding agent inside your repo. One subsystem (8–15 nodes) is roughly one agent session; ~670 files took 5 parallel sessions plus one human merge pass.

模型要进 git

The model is committed to your repo

.codeontic/model/ 是一堆 YAML,一个节点一个文件,提交、review,跟代码同等对待。生成的报告在 .codeontic/ws/,用完即弃,gitignore 掉。

.codeontic/model/ is file-per-node YAML and an asset — it belongs in git, reviewed like code. .codeontic/ws/ holds generated reports and is disposable (gitignored).

门禁不花钱

The gate costs zero tokens

checkconformance 是纯确定性的,亚秒出结果。日常成本只有一项:代码变了,agent 起草模型增量,你确认。

check and conformance are deterministic and sub-second. The only ongoing cost is keeping the model current: an agent drafts the delta during a PR, a maintainer verifies it.

FAQ

支持哪些语言?

Which languages does it support?

TS/JS 是一等公民:符号级锚点验证、AST 不变量检查都只认 TS/JS 源码。其他语言照样建模,结构检查(schema、引用完整性、无环性、场景)和锚点文件存在性都照常工作;符号级检查会回答"判断不了"——不误报,但也等于没验。

TypeScript / JavaScript repos are the first-class case. Other languages get the model but not the enforcement: schema, reference integrity, acyclicity, GWT scenarios, the debt baseline and anchor file existence are language-neutral, while symbol-level checks return "cannot tell" — never a false alarm, but never a verification either.

前提条件?

Any hard prerequisite?

得是 git 仓库。factsbacktestsnapshot 都要调 git。

A git checkout. facts, backtest, and snapshot all shell out to git.

--strict-anchors 严在哪?

What exactly does --strict-anchors promote?

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

Exactly the two checks that can be wrong with certainty — a malformed anchor, and an anchored file that no longer exists. A file that exists but no longer mentions the symbol stays a warning at any strictness, but conformance consumes it, so a node whose anchors went stale stops scoring met. The gate stays lenient; the report card stays honest.

哪些场景适用?

When should you not use it?

codeontic 在"行为看不清、错不起"的地方才值得投入。纯函数库(代码本身就是行为说明)、没有跨组件交接的薄 CRUD、以及即将整体重写的代码,都不值得建模。判断标准很简单:新人光读代码,会不会理解错?不会,就不用建。

Modeling costs real effort and does not pay off everywhere. It is a poor trade for pure function libraries, thin CRUD or glue with no cross-component handoff, and code you are about to delete or rewrite wholesale. The honest test: would a newcomer get this wrong by reading the code? If no, don't model it.

adapter 是什么?需要自己写吗?

What's an adapter — do I write one?

包里不内置。你在 .codeontic/adapter/ 放一个小抽取器,负责从你的技术栈里提取实现信号(队列名、定时器、轮询等)。加 --strict-adapter 可以让缺失 adapter 直接挡 CI,而不是静默跳过。

No adapter ships inside the package. Your repo owns a small, synchronous extractor at .codeontic/adapter/ that reads your stack's implementation signals (queue names, timers, pollers). Pass --strict-adapter to make a missing adapter a hard CI failure instead of a silent skip.

设计原则

Design guarantees

门禁不调 LLM、不碰网络、不运行代码——快、便宜、可复现。缓存不影响正确性(冷跑热跑逐字节一致)。快照和漂移报告永远不是 PR 门禁。发现与防腐严格分开:LLM 只出草稿,维护者审核后才入库。

The gate is zero-LLM, zero-network, zero-code-execution. The cache has zero correctness dependence (a cold run and a warm run are byte-for-byte identical). Snapshot / drift reports are never a PR gate. Discovery and anti-corrosion stay separated: the LLM only drafts, a maintainer verifies, and nothing lands without passing anchor verification.