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, 云资产清单, 代码理解, 代码重构, 大语言模型, 日志审计, 逆向工程