edouard-claude/codetospec
GitHub: edouard-claude/codetospec
将遗留代码库通过 LLM map/reduce 与确定性验证器转化为可版本化、可验证的业务规则知识图谱。
Stars: 2 | Forks: 0
# codetospec
将遗留代码库转化为一个可版本化、可验证的
业务规则知识图谱。
```
codetospec old-legacy-app → ./spec-graph deepseek-chat · 4 workers
✓ extract 24 fichiers · 69 facts (import 14 · module 6 · route 5 · symbol 41 · table 3)
extracteur php: ok · 57 facts
● chunk 38 chunks
● map ███████████████████████████████░░░░░░░░░░░░░ 68% 26/38 · 53 règles candidates
⣾ app/legacy/report.php:1-250
○ reduce en attente
╭────────────────────────────────────────────────────────────────────────────────────────╮
│ parse failed, falling back to line chunks path=assets/style.css │
│ chunk failed chunk=9f31c02a path=app/divers2.php err=rejected after 2 corrections │
╰────────────────────────────────────────────────────────────────────────────────────────╯
tokens map 112k+16k · reduce 0+0 · total 112k+16k 4m32s [q] quitter
```
`codetospec` 读取源代码仓库并生成一个 Markdown 图谱:domain、
entity、endpoint 和 rule 节点(以 EARS 格式编写的需求),
通过 YAML frontmatter 中的类型化边连接。其输出旨在供
人类阅读(GitLab、Obsidian)**并**供 agent(`graph.json`、
`llms.txt`)使用——通常作为系统重写的
规范基准。
```
---
id: rule.billing.prorata-activation
type: rule
status: generated
sources:
- path: app/Services/Billing/ProrataCalculator.php
lines: "42-118"
edges:
- {type: belongs_to, to: domain.billing}
- {type: touches, to: entity.invoices}
ears: event
acceptance: 3
---
# 激活时按比例计费
**Requirement (EARS)**: WHEN a subscriber activates mid-month, the system
shall bill prorated to the remaining days.
...
```
## 实现方式
LLM 擅长阅读代码,但不擅长被信任。`codetospec` 将
LLM 限制在一个它无法控制的循环中:
- **程序驱动;LLM 仅执行认知工作。** Chunking、
merging、graph building 和 cross-domain edges 均通过确定性方式计算。
LLM 绝不发明结构。
- **每个 LLM 的输出在进入图谱前都会进行机械验证**:
JSON schema、EARS 模式、必须能够解析到真实文件和
行范围的引用,以及必须存在的参照。无效输出将被退回要求
更正(最多两次),随后该单元被标记为失败,运行继续
——一个糟糕的 chunk 绝不会导致整个运行崩溃。
- **机械提取的事实是核心锚点。** 符号、路由、表
和导入由解析器提取,而非由模型提取。LLM 只消费
事实,绝不生产事实。
- **一切皆为引用。** 每条规则都精确指向源码中的 `path:lines`。
`codetospec verify` 可随时根据代码树重新检查图谱。
## 天然的跨语言架构
核心程序对任何特定语言都一无所知。语言知识
存在于三个层面:
1. **tree-sitter**(通用结构):用于 chunking 和
符号提取的容错 AST,无论代码处于何种状态。语法由声明式的
`.scm` 查询文件驱动——添加一门语言只需添加一个语法和
一个查询文件,无需修改核心代码。PHP、Go、JavaScript、TypeScript/TSX 和
Rust 开箱即用;未知文件将回退到行窗口 chunk。
2. **外部原生提取器**(生态系统语义):独立的
可执行程序,通过微型的 JSON 协议通信,可自由使用目标
生态系统自身的工具链。PHP 提取器作为首个示例随软件发布
(路由、schema 表、可选的运行时自省)。添加一个
生态系统只需编写一个可执行程序,无需更改二进制文件。
3. **The LLM**:直接读取 chunk,原生支持多语言。
任何 OpenAI 兼容的 endpoint 均可工作:自托管的 vLLM、DeepSeek,或
任何其他 `/chat/completions` 提供商——通过三个环境
变量即可选择您想要的模型。
## Pipeline
```
extract (layers 1+2) ──▶ chunk (AST) ──▶ map (LLM, parallel, per chunk)
──▶ reduce (LLM, per domain) ──▶ build + verify + render (pure Go)
```
- **map**:每个 chunk 进行一次调用,提取带有引用的候选规则。
- **reduce**:每个 domain 进行一次调用,对候选规则进行去重和整合;
引用必须存在于候选列表的字面文本中——模型无法
捏造或篡改它们。
- **build/verify/render**:节点被组装并交叉检查(唯一的
id、可解析的 edge 和引用、frontmatter 往返验证)。除非验证通过,
否则不会写入任何内容。
运行是**可恢复的**(支持 Ctrl-C 安全中断:状态在每个单元处理后保存,重新运行时会跳过已缓存的
单元)且**确定性的**(两次热缓存运行产生字节完全相同的
输出)。Token 使用量按阶段进行
跟踪并实时显示。
## 快速开始
环境要求:Go ≥ 1.26,一个 C 工具链(用于 tree-sitter 的 CGo),
一个 OpenAI 兼容的 endpoint。
```
make build
export LLM_BASE_URL=https://api.deepseek.com/v1 # or your vLLM, or any provider
export LLM_API_KEY=sk-... # empty accepted (local vLLM)
export LLM_MODEL=deepseek-chat
bin/codetospec run --src /path/to/legacy-repo --out /path/to/spec-graph
```
在交互式终端中,`run` 会显示一个全屏控制面板(已解析的文件、
事实、map/reduce 进度、失败情况、实时 Token 计数;按 `q` 可
干净地停止,稍后运行将继续恢复)。使用 `--no-tui` 可输出普通日志(适用于 CI)。
其他命令:
```
bin/codetospec verify --src --out # re-check citations, exit 1 on violation
bin/codetospec stats --out # phase counters and token costs
```
实用标志:`--workers N`(map 并行度)、`--max-tokens N`(如果
大型 domain 的 reduce 输出被截断,请提高此值)、`--lang fr|en`(需求
语言)、`--exclude 'vendor,node_modules,*.md,*.csv'`(目录名和
文件 glob)、`--facts extra.facts.json`(从任意位置注入事实)。
## 输出
```
/
├── llms.txt # navigation guide for agents
├── README.md # summary, coverage report, Mermaid domain graph
├── graph.json # whole graph, machine format
└── nodes/
├── domains/.md
├── entities/.md
├── endpoints/.md
└── rules/..md
```
Domain 的 `depends_on` 边是根据跨越 domain
边界的导入事实计算出来的——绝不是由 LLM 生成的。输出的 README 会报告覆盖率:至少被一条规则引用的 endpoint、触及的 entity、失败的 chunk/domain,
以及没有对应语法的文件。
## 提取器协议(facts v1)
提取器是在 `codetospec.yaml` 中配置的任何
可执行程序,它会将以下内容写入 stdout:
```
{"schema": "codetospec/facts/v1", "facts": [
{"kind": "route", "id": "route.post./api/activate",
"attrs": {"method": "POST", "path": "/api/activate", "controller": "..."},
"source": {"path": "routes/web.php", "lines": "5-5"},
"origin": "php", "certainty": "static"}
]}
```
```
# codetospec.yaml(位于被分析的 repo 根目录)
extractors:
- name: php
cmd: php
args: [extractors/php/extract.php, --root, "{src}"]
timeout: 300s
```
`kind`:`symbol`、`route`、`table`、`module`、`import`。`certainty`:
`static` 或 `proved`(运行时验证过)。Facts 根据 id 合并,优先级为
`proved` > 提取器 > tree-sitter,因此运行时验证的路由将覆盖
静态猜测的路由。提取器发生故障只是一个警告,并非致命错误。
## 限制(v0.1)
- 保证引用在所引用的 chunk 和文件内是可解析的——但
不保证指向确切的语句。
- 去重是在每个 domain 内进行的;在两个不同 domain 中体现的相同行为
会产生两条规则。
- 尚无 agentic reduce、无 SQLite、无 MCP server、无 CI drift-check——请参阅
规范中的路线图。
## 许可证
MIT
标签:DLL 劫持, EVTX分析, Map/Reduce, Tree-sitter, 云资产清单, 代码理解, 代码重构, 大语言模型, 日志审计, 逆向工程