{"id":49759011,"url":"https://github.com/brycewang-stanford/stata-code","last_synced_at":"2026-07-28T17:00:23.941Z","repository":{"id":356401849,"uuid":"1225026146","full_name":"brycewang-stanford/stata-code","owner":"brycewang-stanford","description":"Agent-native Stata bridge for empirical research — run DiD/IV/RDD and publication-ready tables from Claude Code, Jupyter, or VS Code on one token-economy result schema, with StatsPAI cross-validation. | 面向实证研究的智能体 Stata 桥接器——在 Claude Code、Jupyter、VS Code 中用一套省 token 的结果格式跑 DiD/IV/RDD 与出版级表格，并支持 StatsPAI 跨栈交叉验证。","archived":false,"fork":false,"pushed_at":"2026-07-20T17:46:40.000Z","size":5233,"stargazers_count":18,"open_issues_count":0,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-20T19:22:26.335Z","etag":null,"topics":["ai-agents","anthropic","claude","data-analysis","data-science","econometrics","jupyter","llm","mcp","mcp-server","model-context-protocol","notebook","python","regression","reproducible-research","stata","stata-mcp","statistical-computing","statistics","vscode-extension"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brycewang-stanford.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-29T21:49:07.000Z","updated_at":"2026-07-20T17:46:57.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/brycewang-stanford/stata-code","commit_stats":null,"previous_names":["brycewang-stanford/stata-code"],"tags_count":33,"template":false,"template_full_name":null,"purl":"pkg:github/brycewang-stanford/stata-code","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brycewang-stanford%2Fstata-code","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brycewang-stanford%2Fstata-code/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brycewang-stanford%2Fstata-code/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brycewang-stanford%2Fstata-code/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brycewang-stanford","download_url":"https://codeload.github.com/brycewang-stanford/stata-code/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brycewang-stanford%2Fstata-code/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":36001047,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-28T02:00:06.341Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","anthropic","claude","data-analysis","data-science","econometrics","jupyter","llm","mcp","mcp-server","model-context-protocol","notebook","python","regression","reproducible-research","stata","stata-mcp","statistical-computing","statistics","vscode-extension"],"created_at":"2026-05-11T02:02:05.635Z","updated_at":"2026-07-28T17:00:23.932Z","avatar_url":"https://github.com/brycewang-stanford.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"branding/logo/horizontal@1024.png\" alt=\"stata-code logo\" width=\"520\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"README.en.md\"\u003eEnglish\u003c/a\u003e | \u003ca href=\"README.md\"\u003e\u003cstrong\u003e中文\u003c/strong\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n# stata-code\n\n[![PyPI](https://img.shields.io/pypi/v/stata-code.svg)](https://pypi.org/project/stata-code/)\n[![Python](https://img.shields.io/pypi/pyversions/stata-code.svg)](https://pypi.org/project/stata-code/)\n[![License](https://img.shields.io/pypi/l/stata-code.svg)](https://github.com/brycewang-stanford/stata-code/blob/main/LICENSE)\n[![CI](https://img.shields.io/github/actions/workflow/status/brycewang-stanford/stata-code/test.yml?branch=main\u0026label=tests)](https://github.com/brycewang-stanford/stata-code/actions/workflows/test.yml)\n[![Downloads](https://static.pepy.tech/badge/stata-code/month)](https://pepy.tech/project/stata-code)\n[![VS Code](https://img.shields.io/visual-studio-marketplace/v/brycewang-stanford.stata-code-vscode.svg?label=vscode)](https://marketplace.visualstudio.com/items?itemName=brycewang-stanford.stata-code-vscode)\n[![VS Code Installs](https://img.shields.io/visual-studio-marketplace/i/brycewang-stanford.stata-code-vscode.svg)](https://marketplace.visualstudio.com/items?itemName=brycewang-stanford.stata-code-vscode)\n[![VS Code Downloads](https://img.shields.io/visual-studio-marketplace/d/brycewang-stanford.stata-code-vscode.svg?label=vscode%20downloads)](https://marketplace.visualstudio.com/items?itemName=brycewang-stanford.stata-code-vscode)\n[![Rating](https://img.shields.io/visual-studio-marketplace/r/brycewang-stanford.stata-code-vscode.svg)](https://marketplace.visualstudio.com/items?itemName=brycewang-stanford.stata-code-vscode)\n[![GitHub release](https://img.shields.io/github/v/release/brycewang-stanford/stata-code)](https://github.com/brycewang-stanford/stata-code/releases)\n[![GitHub stars](https://img.shields.io/github/stars/brycewang-stanford/stata-code?style=social)](https://github.com/brycewang-stanford/stata-code)\n\n\u003cdiv align=\"center\"\u003e\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003ca href=\"https://copaper.ai\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/brycewang-stanford/stata-code/main/branding/partners/copaper-logo.png\" alt=\"CoPaper.AI\" width=\"200\" /\u003e\u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd width=\"48\"\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003ca href=\"https://sccei.fsi.stanford.edu/reap\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/brycewang-stanford/stata-code/main/branding/partners/stanford-reap-logo.png\" alt=\"Stanford REAP — 斯坦福中国经济与制度研究中心\" width=\"280\" /\u003e\u003c/a\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003csub\u003e\u003cstrong\u003eStanford REAP × CoPaper.AI\u003c/strong\u003e · 面向实证研究的产学研 AI 工具箱\u003c/sub\u003e\n\n\u003c/div\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"branding/github-instructions.png\" alt=\"stata-code: agent-native Stata bridge — one Python core, multiple frontends (Jupyter kernel, MCP server, VS Code extension)\" width=\"720\" /\u003e\n\u003c/p\u003e\n\n\u003e 面向 LLM 智能体的 Stata 桥接工具 —— **一个 Python 核心，多种前端入口**。\n\n`stata-code` 让你可以从现代开发环境中驱动 Stata：LLM 智能体（Claude Code、Cursor、Claude Desktop）、Jupyter notebook，或 VS Code 编辑器。它们共享同一个 Python 核心，并返回稳定、结构化、**适合智能体读取**的结果格式。\n\n**面向实证经济学家。** 用自然语言驱动 Stata：**一次对话里跑完 DiD、IV、RDD 和出版级 `esttab` 表**——再把每个估计在 Stata 与 Python 两套实现上交叉核对，只采信结果一致的那一个（Cunningham 跨包稳健性检验）。\n\n**60 秒上手**（配合 [Claude Code](https://github.com/anthropics/claude-code)，无需全局安装）：\n\n```bash\nclaude mcp add stata-code --scope user -- uvx --from \"stata-code[mcp]\" stata-code-mcp\n```\n\n然后直接问：\n\n\u003e *“用 `data/cfps_panel.dta` 跑一个工人月工资对处理变量的双向固定效应回归（控制变量 `age age2 edu industry`），再用 Callaway-Sant'Anna 检验异质处理效应，最后输出 `esttab` 表。”*\n\n`stata-code` 会自动写 do 文件、运行、把表格回传并解读结果——还能用 [StatsPAI](https://github.com/brycewang-stanford/StatsPAI) 把同一个 ATT 再估一遍，确认两套结果一致。这些工作流以一键 MCP prompts（`did_event_study`、`iv_2sls`、`rdd`、`publication_table`、`cross_validate_did`）的形式提供，背后是一个按需调用的 [recipe 库](skills/stata-code/references/recipes/)。\n\n**为什么选 `stata-code`：** MIT 许可证 · 同时提供 MCP server、内置 agent skill、Jupyter kernel、VS Code 扩展 **和** 终端命令行（`stata-code run`）· 统一的结构化、省 token 的结果格式（typed errors、原生 `r()` / `e()`）· **支持 Stata 17+（pystata）或 Stata 13+（无需 pystata 的 console 后端）** · 零 Python 独立二进制 · 面向无人值守 agent 的默认命令安全护栏 · 配合 StatsPAI 做跨栈交叉验证（Cunningham 检验）。\n\n```text\n                    ┌────────────────────────────────────────┐\n                    │     stata-code core (Python)           │\n                    │                                        │\n                    │   • pystata 17+ / console 13+ backends │\n                    │   • v1.0 统一结果 schema               │\n                    │   • 默认节省 token                     │\n                    │   • 通过 Stata frames 支持多 session   │\n                    │   • 结构化 typed errors + 建议         │\n                    └────────────────────────────────────────┘\n                       ↑              ↑              ↑\n              ┌────────┴────┐  ┌──────┴─────┐  ┌────┴────────────┐\n              │  Jupyter    │  │  MCP       │  │  VS Code        │\n              │  kernel     │  │  server    │  │  extension      │\n              └─────────────┘  └────────────┘  └─────────────────┘\n```\n\n此外还有第四个前端——**终端命令行**（`stata-code run` / `lint` / `setup`），让任何能调用 shell 的 agent（或纯终端）拿到同一套带类型的 `RunResult`；core 支持两种后端：**pystata**（Stata 17+，内存会话）或 **console 后端**（Stata 13+ 批处理，无需 pystata），两者返回完全相同的 schema。\n\n**当前状态：v0.12（2026 年 7 月）** —— core、MCP server、Jupyter kernel、VS Code 扩展和命令行都已经在 Stata 18 MP 上端到端跑通；console 后端把覆盖范围扩展到无需 pystata 的 Stata 13+。v0.12 新增常驻会话 daemon，让连续多次 CLI 调用共享内存中的数据；在此之前 v0.11 是一个「agent 使用体验」版本：返回体可裁剪、长任务可后台执行、do 文件内报错可定位、失败运行的 log 句柄自动关闭、生成文件自动上报 —— 详见 [changelog](CHANGELOG.md)。测试套件覆盖 schema、runner、console 解析器、MCP、kernel、notebook、run-index、subprocess pool、命令安全、linter 和 VS Code 等模块；CI 也检查 lint、类型、schema 生成、包元数据和 VSIX 打包。许可证：**MIT**。快速上手见 [docs/quickstart.zh.md](docs/quickstart.zh.md)。\n\n当前代码树明确支持的三类用户 / agent 工作流：\n\n- **在 Jupyter notebook 里跑 Stata 代码。** `pip install \"stata-code[kernel]\"` + `stata-code-kernel install --user` 会注册一个名为 **Stata** 的 kernel，Jupyter Notebook、JupyterLab、以及 VS Code 的 Jupyter 扩展都能在 kernel 选择器里看到它。Cell 里直接写 Stata 命令，日志、图形和警告会内联渲染（自 v0.5 起 kernel logo 已一起打包进 PyPI wheel，VS Code 的 Jupyter kernel picker 也能正常显示）。详见下文 [作为 Jupyter kernel](#作为-jupyter-kernel)。\n- **可选的 agent「修复并重跑」循环。** `stata_run` 在每次失败时都会返回结构化的 `error.kind/line/context` 和 `suggestions`。默认情况下 Claude Code 只把它当作诊断信息上报；但如果你明确说「帮我修到跑通」「修复并反复运行直到成功」，agent 就会用同一组字段去改 `.do` 文件、再调 `stata_run`，直到代码通过。这个修复循环是 **opt-in** 的：默认失败 = 诊断，不是自动改写授权。详见下文 [Agent 工作流里的报错恢复](#agent-工作流里的报错恢复)。\n- **经济学实证工作流指南。** 随包 skill 和 cookbook 覆盖现代 DiD、IV/弱工具变量、RDD、表格导出、data-MCP 到 Stata 的交接、以及跨包/跨栈 parity audit。`stata-code` 负责运行和审计 Stata 这一侧；R、Python、官方数据 MCP 仍是独立工具，通过显式 handoff 文件和 source metadata 衔接。详见 [`skills/stata-code/references/`](skills/stata-code/references/) 和 [`examples/`](examples/)。\n\n---\n\n## 为什么做这个项目\n\nStata 的 AI / agent 工具生态现在比较分散，详见 [References-tools.md](References-tools.md)：\n\n- 现有 MCP server（[SepineTam/stata-mcp](https://github.com/sepinetam/stata-mcp)、[tmonk/mcp-stata](https://github.com/tmonk/mcp-stata)）使用 **AGPL-3.0**，不适合闭源或商业集成。\n- 常用的 VS Code AI 插件（[hanlulong/stata-mcp](https://github.com/hanlulong/stata-mcp)）是 MIT，但 MCP server 被打包在插件内部，不方便单独复用。\n- 每个工具都用自己的方式封装 `pystata`，返回结构不统一，智能体需要为不同工具写特殊处理。\n- 很多工具一开始是为人类交互设计的，再接到 MCP 上；它们经常把 200 行日志和 base64 图片直接塞进回复，默认就大量消耗 token。\n\n`stata-code` 要填补的就是这个空位：\n\n1. **MIT 许可证**，没有 copyleft 传染问题。\n2. 所有前端共享同一个结果格式：[SCHEMA.md](SCHEMA.md)。\n3. 默认面向智能体：typed errors、结构化 `r()` / `e()`、log refs、graph refs、suggestion seeds。\n4. 一个 core，多个入口：Jupyter kernel、MCP server、VS Code 扩展。\n\n如果你关心 AGPL/GPL Stata 项目的 clean-room 边界，请看 [LICENSE-POLICY.md](LICENSE-POLICY.md)。\n\n---\n\n## 安装\n\n要求：**Python 3.10+**，外加以下任一种 Stata —— **Stata 17+**（用其自带的 `pystata`，\n支持内存内会话），或 **Stata 13+**（走 console 后端，不需要 `pystata`，无状态）。\n\n```bash\n# 从 PyPI 安装\npip install stata-code\n\n# 同时安装 MCP server 和 Jupyter kernel 的额外依赖\npip install \"stata-code[mcp,kernel]\"\n\n# 或者从源码安装（开发用 editable install）\ngit clone https://github.com/brycewang-stanford/stata-code.git\ncd stata-code\npip install -e \".[mcp,kernel]\"\n```\n\n\u003e **命名说明。** PyPI 上的发行包名是 `stata-code`（带连字符），\n\u003e 但 Python 导入名是 `stata_code`（下划线 —— Python 标识符不能包含连字符）。\n\u003e 和 `scikit-learn` → `import sklearn` 是同样的约定。\n\u003e 所以：`pip install stata-code`，`from stata_code import run`。\n\n注意：`pystata` **不在 PyPI 上**，它随 Stata 一起安装。`stata-code` 会自动在 macOS 的 `/Applications/Stata/utilities/pystata` 以及 Linux / Windows 的对应位置寻找它。如果你的 Stata 安装在其他位置，请在导入前把 `pystata` 加到 `PYTHONPATH`。\n\n安装后可以用只读 doctor 检查本机环境：\n\n```bash\nstata-code doctor\nstata-code doctor --json          # 机器可读输出\nstata-code doctor --no-stata-probe # 跳过实时 Stata 初始化\nstata-code doctor --workspace /path/to/project --no-user-config-scan\n```\n\ndoctor 会报告 package/Python 版本、MCP 和 Jupyter extras、`pystata` 发现结果、\n`PATH` 上的 console scripts、常见项目级/用户级 MCP client 配置文件、\nclient/VS Code 配置提示，以及 best-effort 的 Stata 版本/edition 探测。它不会\n改 shell、Stata、Claude、Cursor 或 VS Code 配置。\n\n---\n\n## 快速开始\n\n完整 cookbook 在 [`examples/`](examples/)：基础回归、DiD、图形、多 session、大矩阵。\n\n### 作为 Python library\n\n包级 `run()` / `execute()` API 使用和 MCP server 相同的 subprocess-backed\nrunner，因此长任务会遵守 `timeout_ms`，`pystata` 对 stdout 的重定向也会被隔离在 worker 进程中，不会污染调用方进程。\n\n```python\nfrom stata_code import run\n\nr = run(\"sysuse auto, clear\")\nr = run(\"regress mpg weight\")\n\nif r.ok:\n    print(r.results.e.scalars[\"r2\"])           # 0.6515 (native float)\n    print(r.results.e.macros[\"cmd\"])           # \"regress\"\n    b = r.results.e.matrices[\"b\"]\n    print(dict(zip(b.cols, b.values[0])))      # {\"weight\": -0.006, \"_cons\": 39.44}\nelse:\n    print(r.error.kind, r.error.message)       # ErrorKind.VARNAME_NOT_FOUND, \"...\"\n    for s in r.error.suggestions:\n        print(\"hint:\", s.action)               # \"Did you mean `mpg`?\"\n```\n\n### 从命令行使用（Bash）\n\n任何能 shell out 的 agent 或脚本都能用上同一套结构化引擎 —— **不需要 MCP**。\n`stata-code run` 可以执行 `.do` 文件、一个或多个 `-e` 片段，或从 stdin 读入的代码，\n并打印 `RunResult`：\n\n```bash\nstata-code run analysis.do                  # 跑 do 文件，输出文本摘要\nstata-code run -e \"sysuse auto\" -e \"regress mpg weight\"\nstata-code run analysis.do --json           # 完整 RunResult JSON（给 agent 用）\necho \"summarize price\" | stata-code run -    # 从 stdin 读代码\nstata-code run model.do --graphs out/        # 同时把图形导出到 out/\nstata-code run job.do --session modelA --timeout-ms 120000\n```\n\n成功退出码是 `0`，Stata / adapter 出错时是 `1`，因此可以直接接进 CI 和\"改了再跑\"的\n脚本循环。`stata-code lint analysis.do` 则在完全不启动 Stata 的前提下做静态检查\n（大括号不配对、缺 `end`、悬空的 `///`）。\n\n**后端 —— Stata 13+ 且没有 pystata。** `--backend` 决定代码怎么跑：`pystata`\n（Stata 17+，内存内会话）、`console`（Stata 13+ 批处理，不需要 pystata，无状态），\n或 `auto`（默认：有 pystata 就用，否则退到 console）。console 后端驱动 Stata 的命令行\n可执行文件，并把日志解析成同样的带类型 `RunResult` —— 带类型的 `r()`/`e()`、估计表、\n以及错误分类 —— 所以老版本 Stata 和无 pystata 的环境同样是一等公民：\n\n```bash\nstata-code run analysis.do --backend console\nexport STATA_CODE_STATA_CLI=/usr/local/stata18/stata-mp   # 自动找不到时手动指定\n```\n\n**零 Python 二进制。** 独立的 `stata-code` 可执行文件（由\n[`scripts/build_standalone.py`](scripts/build_standalone.py) 构建，现成的 CI workflow\n模板见 [`packaging/standalone.github-workflow.yml`](packaging/standalone.github-workflow.yml)）\n把运行时一起打包，不需要安装 Python。配合 `--backend console`，这就是一条完全不依赖\nPython、又能拿到带类型 Stata 结果的路径。\n\n### 会话 daemon（跨调用保持数据）\n\n`stata-code run` 默认每次调用都起一个新进程，进程一退，内存里的数据就没了。\n`daemon` 子命令把 subprocess pool 挪进一个常驻进程，通过 Unix socket 对外服务，\n于是连续两次 `run --daemon` 会落在**同一个 Stata 会话**上：\n\n```bash\nstata-code run --daemon -e 'sysuse auto, clear' -e 'gen z = price/1000'\nstata-code run --daemon -e 'summarize z'      # 新进程，但 z 还在\nstata-code run --daemon -e 'regress price mpg'\nstata-code run --daemon -e 'display e(r2)'    # 上一个进程留下的 e() 也还在\n```\n\n第一次 `run --daemon` 会自动把 daemon 拉起来，不需要手动 start。也可以显式管理：\n\n```bash\nstata-code daemon start                    # 后台启动（--foreground 留在当前终端）\nstata-code daemon status                   # pid、uptime、活跃 session 列表\nstata-code daemon status --json\nstata-code daemon stop\nstata-code daemon restart\nstata-code daemon start --idle-timeout 0   # 0 = 永不因空闲退出\n```\n\n几个要点：\n\n- **会话隔离照旧。** `--session other` 在 daemon 里仍然是独立的 Stata frame / worker，\n  彼此看不到对方的数据。\n- **默认空闲 30 分钟自动退出**，免得忘了关的 daemon 一直占着 Stata license。\n  用 `--idle-timeout` 调整，`0` 表示禁用。\n- **只监听 Unix socket，不开 TCP。** daemon 会执行任意 Stata 代码，所以刻意只暴露在\n  mode-0700 目录下的 mode-0600 socket 上。[命令安全](#命令安全)护栏依然生效。\n- **需要 pystata 后端。** `--backend console` 本身就是无状态批处理，套 daemon 没有意义，\n  因此会直接报错而不是静默失效。\n- **socket 路径过长时自动降级。** `sun_path` 上限约 104 字节；home 目录很深或\n  `XDG_RUNTIME_DIR` 很长时，会自动改用 `/tmp` 下一个由原路径哈希得出的短路径。\n  所有入口都用同一套推导，因此仍能找到同一个 daemon。\n\n`stata-code run`（不加 `--daemon`）、`run --daemon` 和 MCP server 三条路走的是同一个\n引擎、返回同一份 `RunResult` schema，区别只在于 Stata 会话活多久。\n\n### 一条命令配置客户端\n\n`stata-code setup` 把 MCP server 条目写进客户端配置 —— 它是只读的 `doctor` 那个\n「会改文件」的对应物。它会保留配置里其他的 server，并在覆盖任何文件之前先做备份：\n\n```bash\nstata-code setup --all                 # Claude Code、Cursor、VS Code（project scope）\nstata-code setup --claude --dry-run    # 只预览，不写入\nstata-code setup --vscode --python .venv/bin/python   # 指定解释器\nstata-code setup --codex               # 打印可复制粘贴的 TOML 片段\n```\n\n### 命令安全\n\n默认情况下，runner 会在命令抵达 Stata **之前**拦截 OS 逃逸和文件删除类命令\n（`shell`、`winexec`、`erase`、`rm`、`rmdir`，以及 `!` shell 转义），因此一个自主运行的\nagent 循环没办法删文件或执行任意 shell 命令。被拦截时返回 `policy_blocked` 结果\n（`rc=-4`），而不是真的去执行。这是护栏，不是沙箱；可以用环境变量调整：\n\n```bash\nSTATA_CODE_COMMAND_POLICY=off      # 完全关闭护栏\nSTATA_CODE_POLICY_ALLOW=shell      # 放行特定命令（逗号分隔）\nSTATA_CODE_POLICY_BLOCK=python     # 额外拦截某些命令\n```\n\n### 作为 MCP server\n\n`pip install \"stata-code[mcp]\"` 之后，`stata-code-mcp` 会出现在你的 `PATH` 中。可以接到 Claude Code、Cursor、Claude Desktop 等任何兼容 MCP 的客户端里。\n\n#### 用 `claude mcp add` 接入 Claude Code（推荐）\n\n如果你还没有安装 Claude Code，请先看 [anthropics/claude-code](https://github.com/anthropics/claude-code)。\n\n最快的方式是 `claude mcp add` 命令。根据想要的可见范围选 scope：\n\n```bash\n# user scope —— 一次安装，本机所有 Claude Code workspace 全局可用\nclaude mcp add stata-code --scope user -- stata-code-mcp\n\n# local scope —— 仅当前 workspace（本地 Claude 配置，不会提交到仓库）\nclaude mcp add stata-code --scope local -- stata-code-mcp\n\n# project scope —— 写入仓库内的 ./.mcp.json，和协作者共享\nclaude mcp add stata-code --scope project -- stata-code-mcp\n```\n\n接着运行 `claude`，输入 `/mcp` 确认 `stata-code` 出现并带有 21 个工具（`stata_run`, `stata_run_status`, `list_background_runs`, `stata_info`, `get_log`, `search_log`, `get_graph`, `get_matrix`, `inspect_data`, `lint_do`, `install_package`, `list_sessions`, `cancel_session`, `reset_session`, `notebook_outline`, `notebook_get_cell`, `notebook_locate`, `notebook_edit_cell`, `notebook_insert_cell`, `notebook_delete_cell`, `list_runs`）。\n\n#### Agent 工作流里的报错恢复\n\n`stata_run` 不会自行改写源 `.do` 文件或替你改代码。它执行提交的 Stata 代码，所以代码本身仍可能照常生成日志、图形、表格或其他输出。Stata 报错时，`stata_run` 返回结构化诊断（`error.kind`, `error.message`, `error.line`, `error.context`）和尽力生成的 `suggestions`。这支持两种不同的 Claude Code 工作流：\n\n- 如果你说的是「运行这个 do-file」或「验证这段代码」，Claude 可以只报告失败原因和建议的下一步，不修改源文件。\n- 如果你明确说「帮我修到跑通」或「修复并反复运行直到成功」，Claude 可以基于同一组结构化错误字段修改 `.do` 文件，再调用 `stata_run` 继续迭代。\n\n如果需要自动修复循环，请明确说出来。否则，失败的运行应先被视为诊断结果，而不是自动改写代码的授权。\n\n#### 用 `uvx`（不必全局 pip install）\n\n如果不想全局 `pip install stata-code`，可以用 [`uv`](https://github.com/astral-sh/uv) 临时运行：\n\n```bash\nclaude mcp add stata-code --scope user -- uvx --from \"stata-code[mcp]\" stata-code-mcp\n```\n\n`uvx` 会在首次启动时下载并缓存 `stata-code`。注意：`pystata` **不在 PyPI 上**，仍需要在宿主机上能找到。runner 会自动把标准 Stata 安装路径（macOS 上的 `/Applications/Stata/utilities/pystata` 等）加到 `sys.path`；如果你的 Stata 在别处，请用 env 设置 `PYTHONPATH`。\n\n#### 通过 plugin marketplace 接入 Claude Code\n\n本仓库还带有 Claude Code 插件清单（`.claude-plugin/`）。把 marketplace 加入你的 Claude Code 配置后，两条命令即可同时接好 MCP server 和教会 Claude v1.0 结果 schema 的 agent skill：\n\n```bash\nclaude plugin marketplace add brycewang-stanford/stata-code\nclaude plugin install stata-code\n```\n\n插件会注册 `stata-code` MCP server，并安装 [`stata-code` skill](skills/stata-code/SKILL.md)，让 Claude 学会按 `error.kind` 分支、惰性调用 `get_log(ref)`、并直接使用 notebook 编辑工具，无需每个会话重新解释。\n\n#### 其它 MCP client（Cursor / Claude Desktop / Cline / Continue / Windsurf / Antigravity）\n\n大多数非 Claude Code 的 MCP client 都接受同一段 JSON 配置。把它放进对应 client 的 MCP 配置文件即可：\n\n| Client | 配置文件 |\n| --- | --- |\n| Claude Desktop | macOS：`~/Library/Application Support/Claude/claude_desktop_config.json`；Windows：`%APPDATA%\\Claude\\claude_desktop_config.json` |\n| Cursor | `~/.cursor/mcp.json`（用户级）或 `\u003cworkspace\u003e/.cursor/mcp.json`（项目级） |\n| Windsurf | `~/.codeium/windsurf/mcp_config.json` |\n| Cline（VS Code） | settings 中的 `cline.mcpServers` |\n| Continue | `~/.continue/config.json` 的 `experimental.modelContextProtocolServers` |\n| Antigravity / 通用 | `~/.claude/mcp.json` 或该 client 文档指定的位置 |\n\n#### 手动 JSON 配置（Cursor / Claude Desktop / 兜底方案）\n\n对于没有 `mcp add` CLI 的客户端，直接编辑配置文件即可（`~/.claude/mcp.json`、Cursor settings、Claude Desktop 的 `claude_desktop_config.json` 等）：\n\n```json\n{\n  \"mcpServers\": {\n    \"stata-code\": {\n      \"command\": \"stata-code-mcp\"\n    }\n  }\n}\n```\n\n如果 `stata-code-mcp` 不在 `PATH` 上，也可以以 module 方式运行：\n\n```bash\npython -m stata_code.mcp\n```\n\n如果 `stata-code-mcp` 安装在项目内 virtualenv（推荐用于可复现环境），建议在\nclient 配置里写绝对路径，例如 `/abs/path/to/.venv/bin/stata-code-mcp`。\n\n#### MCP 故障排查\n\n如果 `stata_run` 返回 `adapter_crash`，并出现 `worker emitted non-JSON: '\\n'`，\n请升级到 `stata-code\u003e=0.6.4`，然后重启 MCP client，让它启动新的 server 进程。\n同时确认 client 解析到的是预期的 `stata-code-mcp`；项目内 virtualenv 安装\n应使用 `.venv/bin/stata-code-mcp` 的绝对路径，不要依赖全局 `PATH`。\n\n如果 OpenAI 系客户端返回 `API Error: 400 Invalid schema for function\n'mcp__stata-code__notebook_insert_cell'`，并提到顶层 `oneOf`，请升级到\n`stata-code\u003e=0.6.5`，然后重启 MCP client。旧 server 进程在重启前仍会继续\n暴露旧 schema。\n\nMCP server 注册了 21 个工具：\n\n| 工具 | 用途 |\n| --- | --- |\n| `stata_run` | 执行 Stata code，返回 v1.0 RunResult JSON；支持 `include_results` / `include_estimation` 控制返回体大小，`timeout_ms` 硬超时，`run_in_background` 后台执行 |\n| `stata_run_status` | 轮询后台运行（`run_in_background=true`）的状态与结果，可用 `wait_ms` 阻塞等待 |\n| `list_background_runs` | 列出本 server 追踪的后台运行 |\n| `stata_info` | 返回 Stata edition、version 和 capabilities |\n| `get_log` | 通过 `log://` ref 获取完整日志 |\n| `search_log` | 在已存储的 `log://` payload 内搜索匹配行 |\n| `get_graph` | 通过 `graph://` ref 获取图形 bytes（`ImageContent`） |\n| `get_matrix` | 通过 `matrix://` ref 获取矩阵 `{rows, cols, values}` |\n| `inspect_data` | 运行 `describe` + `codebook`，返回紧凑的数据集元数据 |\n| `lint_do` | 在执行前静态检查 do 文件源代码（花括号不匹配、缺少 `end`、悬空 `///`） |\n| `install_package` | 安装 SSC 或显式 `net install` 包，并验证命令可解析 |\n| `list_sessions` | 列出 live sessions |\n| `cancel_session` | 取消某个 session；subprocess-backed 路径会终止运行中的 worker，也会短路尚未开始的运行 |\n| `reset_session` | 清空某个 session 的数据 |\n| `notebook_outline` | `.ipynb` 的 cell 索引（cell_id、类型、源代码预览） |\n| `notebook_get_cell` | 单个 cell 的完整源代码 + 节流版输出摘要 |\n| `notebook_locate` | 用 snippet / regex / 报错文本定位 cell |\n| `notebook_edit_cell` | 原子替换 cell 源代码（保留 id，清空 outputs） |\n| `notebook_insert_cell` | 插入新 cell，分配新的 nbformat 4.5+ UUID |\n| `notebook_delete_cell` | 按 id 删除 cell |\n| `list_runs` | 查询 run-bundle manifest（按 notebook / cell_id / session / since / ok 过滤，用 limit / offset 翻页） |\n\n对于新版 MCP 客户端，这些工具会返回 `structuredContent`，并在 tool\nmetadata 里声明 `outputSchema`；同时仍保留序列化 JSON text block，兼容旧客户端。\nserver 还暴露 MCP resources：\n\n| Resource | 用途 |\n| --- | --- |\n| `stata://schema/run-result` | `stata_run` 结构化输出的 JSON Schema |\n| `stata://server/capabilities` | server instructions、tools、resource templates |\n| `stata://sessions` | 当前 subprocess-backed Stata sessions |\n| `log://...` | 被截断运行结果背后的完整日志 |\n| `graph://...` | 捕获到的 graph image bytes |\n| `matrix://...` | 延迟获取的大矩阵 payload |\n\n同时提供 MCP prompts：`run_do_file_and_report`、`debug_stata_error`、\n`fix_and_rerun_until_passes`、`replication_audit`、\n`plan_cross_stack_parity_audit`、`data_mcp_to_stata_handoff`、\n`summarize_estimation_results`、`run_notebook_cell_and_report`、\n`fix_and_rerun_notebook_cell`、`did_event_study`、`iv_2sls`、`rdd`、\n`publication_table` 和 `cross_validate_did`，用于常见 agent 工作流。\n\n### 作为 Jupyter kernel\n\n`stata-code` 的 Jupyter 支持是以 **kernel** 形式打包在 Python 包里的 —— JupyterLab 插件市场里**没有**独立的 \"stata-code 插件\"。安装分两步：先 `pip install` 安装带 `kernel` extra 的包，再把 kernelspec 注册到 Jupyter。\n\n**前置条件**：本机已经安装 Stata 17+ 且持有合法许可证（kernel 通过 `pystata` 调用本地 Stata），同一个 Python 环境里已经装好 `jupyter`/`jupyterlab`，Python 版本 ≥ 3.10。\n\n```bash\n# 1. 安装带 kernel extra 的 stata-code（会同时装上 ipykernel）\npip install \"stata-code[kernel]\"\n\n# 2. 把 kernelspec 注册到当前用户的 Jupyter data dir\nstata-code-kernel install --user\n# 等价命令：\n# python -m stata_code.kernel install --user\n```\n\n检查 kernel 是否注册成功：\n\n```bash\njupyter kernelspec list\n# 输出里应该能看到名为 `stata` 的条目\n```\n\n然后打开 Jupyter Notebook / JupyterLab（或 VS Code 中的 `.ipynb`），在 kernel 选择器里挑 **Stata**，cell 里直接写 Stata 命令即可，日志、graphs 和 warnings 会以内联方式显示。\n\n\u003e JupyterLab 的 Extension Manager 只能安装前端 JS 扩展，**装不了 kernel**。所以上面的 `pip install` + `install --user` 是唯一支持的安装路径。\n\n### 作为 VS Code 扩展\n\n配套扩展已发布到 Marketplace：[`brycewang-stanford.stata-code-vscode`](https://marketplace.visualstudio.com/items?itemName=brycewang-stanford.stata-code-vscode)。它会以子进程方式启动 `stata-code-mcp`，并提供语法高亮、`**#` section 和 `program define` 的 Outline、`.do` 文件的 code-lens \"Run cell\" / \"Run section\"、**七视图侧边栏**（sessions / last result / **data 变量浏览器** / run history / logs / graphs / **outputs**）——其中包含一个 agent-native 版的 Stata **变量窗口**，以及一个把每次运行写到磁盘的 `esttab` 表格和 `export` 文件呈现出来的 **Outputs** 面板——状态栏指示器、补全、帮助跳转、保守变量重命名，以及来自 v1.0 typed errors 的内联诊断。\n\n```bash\n# 从 VS Code 命令行\ncode --install-extension brycewang-stanford.stata-code-vscode\n```\n\n或者打开 VS Code 的 **Extensions** 侧栏，搜索 `stata-code`。扩展同时发布在 [Open VSX](https://open-vsx.org/)，因此 Cursor、Windsurf 等 VS Code 兼容编辑器不必经过微软 Marketplace 也能安装。\n\n首次激活时，扩展会在 `PATH`（以及 workspace 下的 `.venv` / `venv`）里探测 `stata-code-mcp`。如果找不到，会弹出一次性的安装提示，附上准确的 `pip install \"stata-code[mcp]\"` 命令——选择 **Don't show again** 可对当前扩展版本永久静默。\n\n扩展仍然依赖系统 Python 上安装了 MCP extra（`pip install \"stata-code[mcp]\"`），从而保证 `stata-code-mcp` 在 `PATH` 上可用，并且能导入 MCP SDK。和其它前端一样，需要 Stata 17+ 和有效的 Stata 许可证。\n\n#### Cell 与 section 约定\n\n扩展识别 `.do` 文件里两类互补的结构标记。二者可以混用在同一个文件里，互不冲突：\n\n| 标记 | 用途 | 示例 |\n| --- | --- | --- |\n| `* %% [标题]` | Cell 边界。每个标记有一个 **▶ Run Cell** code-lens；\"Run Cell\" 提交该标记到下一个标记之间的内容。与 `kylebutts/vscode-stata` 的 Jupyter 风格 cell 约定兼容。 | `* %% 02 model fit` |\n| `**# 标题` … `**###### 标题` | Section 标题，1–6 级。每个标题有一个 **▶ Run Section** code-lens，并进入 Outline 视图。\"Run Section\" 提交该标题到下一个同级或更高级标题之间的内容，与 `ZihaoVistonWang.stata-all-in-one` 的层级执行模型一致。 | `**## DiD specification` |\n\n`program define … end` 代码块也会出现在 Outline 里，嵌套在所属 section 之下。\n\n如果扩展或 MCP client 找不到 server，请在同一个 Python 环境里运行\n`stata-code doctor --no-stata-probe`。它会报告 `stata-code-mcp` 是否在\n`PATH` 上，并提示 GUI client 常见的绝对路径或 `python -m stata_code.mcp`\n兜底配置。它也会读取当前 workspace 和用户目录里常见的 MCP 配置文件，告诉你\nclient 是否已经指向 `stata-code`。\n\n---\n\n## 默认节省 token\n\n典型的 `stata_run` 响应比现有 MCP server 直接返回日志和图片的方式小约 **10 倍**。核心设计有四点：\n\n1. **日志默认只返回 `head` + `tail` + `ref`**。完整日志可以按需用 `get_log(ref)` 获取，也可以用 `search_log(ref, pattern)` 直接在 ref 里检索。Stata 回归日志可能有约 6,000 tokens，`stata-code` 默认约 600 tokens。\n2. **图形默认返回 refs，不内联 base64**。一个 30 KB PNG 转成 base64 约 50,000 tokens；返回 ref 可以让智能体只在真正需要渲染时再取 bytes。确实需要内联时，图形会以真正的 MCP image content block 返回 —— 视觉模型能直接看到，而不是塞在 JSON 字符串里、既烧 token 又看不见的 base64。\n3. **一次估计只描述一次**。默认（`include_results: \"scalars\"`）保留 `r()` / `e()` 的 scalars 和 macros，而把每个矩阵降级成只带形状的 `matrix://` stub。否则同一批数字会被编码四遍 —— `e(b)`、`e(V)` 的行列标签、`e(beta)`、`r(table)` —— 而 `results.estimation` 里其实已经有带类型的系数表了。一个 123 项的回归返回体从约 57 KB 降到约 28 KB。原始数值仍然只差一次 `get_matrix(ref)`；`include_results: \"full\"` 可恢复旧行为。\n4. **错误是结构化 typed errors**。智能体可以判断 `err.kind == \"varname_not_found\"`，而不是正则解析英文日志。\n\n固定效应很多的场景还有两个开关：`include_estimation: \"summary\"` 保留模型层面的信息但丢掉逐项系数，`max_coefficients` 则给系数表设上限。两种情况下 `estimation.n_coefficients` 都仍然报告模型真实的项数，`coefficients_truncated` 会标记被截断 —— 所以裁剪过的表不会被误当成一个更小的模型。\n\n例如，变量名写错时返回的是结构化错误：\n\n```json\n{\n  \"ok\": false,\n  \"rc\": 111,\n  \"error\": {\n    \"kind\": \"varname_not_found\",\n    \"varname\": \"mpgg\",\n    \"line\": 3,\n    \"source_file\": null,\n    \"context\": {\n      \"before\": [\"use auto\"],\n      \"failing\": \"summarize mpgg\",\n      \"after\": []\n    },\n    \"suggestions\": [\n      {\"action\": \"Did you mean `mpg`?\", \"command\": \"describe\"}\n    ],\n    \"recovery\": {\n      \"category\": \"user_code\",\n      \"retriable\": false,\n      \"needs_code_change\": true,\n      \"needs_user_input\": false\n    }\n  }\n}\n```\n\n当出错的命令位于你调用的脚本里（`do \"analysis.do\"`）时，`line` 和 `context` 指向的是**那个脚本内部**的行，`source_file` 给出文件路径 —— 智能体不需要再把文件重新读一遍去找出错行。\n\n完整 schema 见 [SCHEMA.md](SCHEMA.md)。\n\n---\n\n## 架构\n\n```text\nstata_code/\n├── core/\n│   ├── _runtime.py    # process-singleton pystata wrapper\n│   ├── _refs.py       # LRU ref store for log/graph/matrix payloads\n│   ├── schema.py      # Pydantic v2 models for the v1.0 result schema\n│   ├── errors.py      # rc → ErrorKind mapping + suggestion seeds\n│   ├── runner.py      # in-process execute(); collects everything via sfi\n│   └── _pool.py       # subprocess workers for public API / MCP hard timeouts\n├── mcp/\n│   └── server.py      # MCP server (21 tools)\n└── kernel/\n    └── kernel.py      # Jupyter kernel\n```\n\n`runner.py` 是唯一直接接触 `pystata` 的地方。包级 Python API 和 MCP server 会先走 `_pool.py`，由隔离的 worker subprocess 调用 `runner.execute()`；Jupyter kernel 为了 notebook 交互性仍使用 in-process runner。\n\n---\n\n## 对比\n\n| | stata-code | SepineTam/stata-mcp | hanlulong/stata-mcp | nbstata |\n| --- | --- | --- | --- | --- |\n| 许可证 | **MIT** | AGPL-3.0 | MIT | GPL-3.0 |\n| 独立 MCP | ✓ | ✓ | 与 VS Code 捆绑 | — |\n| Jupyter kernel | ✓ | — | — | ✓ |\n| 统一结果格式 | ✓ ([SCHEMA.md](SCHEMA.md)) | per-tool | per-tool | per-tool |\n| 默认节省 token | ✓ (log refs, graph refs) | — | — | — |\n| 结构化错误和建议 | ✓ (34 kinds) | — | — | — |\n| 多 session | ✓ (Stata frames) | partial | — | — |\n| 生态成熟度 | early | ✓ (statamcp.com, cookbook) | ✓ (11k installs) | ✓ |\n\n`stata-code` 是这个问题空间里更年轻的、MIT 许可证的、agent-native 的替代方案。AGPL 方案里，SepineTam 的 `stata-mcp` 目前更成熟；`stata-code` 的目标是服务那些不能接受 copyleft 传染、又需要结构化智能体接口的场景。\n\n### 和直接调用 Stata 命令行比\n\n先把话说明白：**你完全可以不装任何工具，直接从 shell 调 Stata。** 大多数 Stata\n安装都自带一个命令行可执行文件，一次性执行的场景下它挺好用，没必要为此引入依赖：\n\n```bash\n/Applications/Stata/StataMP.app/Contents/MacOS/stata-mp -b do analysis.do\nprintf 'sysuse auto, clear\\nsummarize mpg\\nexit, clear\\n' | stata-mp -q\n```\n\n值得知道的是这条路会在哪里失效。下面两列跑的是**同一个 Stata 二进制、同一份日志**\n（`stata-code` 用的是 `--backend console`），差别只在于外面那层包装：\n\n| | 裸 `stata-mp -b` | `stata-code run` |\n| --- | --- | --- |\n| 出错时的退出码 | **`0`** —— 静默失败 | `1` |\n| 怎么知道出了错 | 自己 grep 日志里的 `r(111);` | `ok=False`、`rc=111` |\n| 错误分类 | 无 | `[varname_not_found]`（共 34 类） |\n| 修复建议 | 无 | \"Run `describe` to list available variables\" |\n| 取回归系数 | 从对齐的 ASCII 表里抠 | `e.scalars[\"r2\"] → 0.6515312529087511`（float） |\n| 跨调用保持数据 | 不能 | `run --daemon`（见下节） |\n\n第一行是最容易吃亏的地方：Stata 批处理模式**即使代码报错也返回退出码 0**。\n在自动化循环里，agent 看到 `exit 0` 就会继续往下走，把失败的结果当成有效结果用。\n\n选择建议：\n\n- **一次性执行**（\"跑一下这个 do 文件给我看结果\"）—— 裸命令行就够了，别过度设计。\n- **脚本 / CI**（需要靠退出码判断成败）—— 用 `stata-code run`，最小代价换到可靠信号。\n- **迭代式分析**（多轮改设定、读中间结果、基于 `e()` 决定下一步）—— 用\n  `run --daemon` 或走 MCP，否则无状态和文本解析这两个问题会在多轮里叠加放大。\n\n\u003e 不加 `--daemon` 时，`stata-code run` **每次调用都起一个新进程**：同一次调用里的\n\u003e 多个 `-e` 共享 session，但进程退出后内存里的数据就没了。加上 `--daemon` 之后\n\u003e 数据会留在常驻进程里，详见 [会话 daemon](#会话-daemon跨调用保持数据)。\n\n---\n\n## 路线图\n\n### 已完成（当前代码树）\n\n- v1.0 result schema ([SCHEMA.md](SCHEMA.md))\n- 基于 `pystata` 的 runner，原生类型化的 `r()`、`e()` 和矩阵\n- 通过 Stata frames 支持多 session（`session_id` 接受 `[A-Za-z0-9_-]+`；例如 `model-a` 这类 id 会在内部映射到合法的私有 frame 名，但返回结果仍回显公开 id）\n- 常驻会话 daemon（`stata-code daemon`、`run --daemon`）：多次 CLI 调用共享同一个活的 Stata 会话，走 mode-0600 Unix socket，支持空闲自动退出\n- 行级错误归属：line number、context、commands_executed\n- 图形捕获：`png` / `svg` / `pdf` + ref store，并记录来源命令归属\n- 日志截断 + ref store\n- 警告抽取：5 类 + 通用 notes\n- 34 类错误分类法 + 标准化建议，以及机器可读的 `recovery` 判定（可重试 / 需改代码 / 需人工介入）\n- MCP server：21 个工具，覆盖执行、notebook 导航 / 检索 / 原子化编辑、运行索引（`list_runs`）、日志检索（`search_log`）、数据集检查（`inspect_data`）、静态检查（`lint_do`）和包安装（`install_package`）\n- 命令安全护栏：`shell`、`winexec`、`erase`、`rm`、`rmdir`、`!` 等 OS 逃逸 / 删除文件命令在执行前被拦截；可通过 `STATA_CODE_COMMAND_POLICY` / `STATA_CODE_POLICY_ALLOW` / `STATA_CODE_POLICY_BLOCK` 配置\n- Bash / 终端入口：`stata-code run`（`.do` 文件、`-e` 片段或 stdin）打印同一套结构化 `RunResult`，任何能调用 shell 的 agent 都可消费；`stata-code lint` 运行静态检查；`stata-code setup` 写入 MCP 客户端配置\n- Console（批处理）后端（`core/console.py`、`--backend console`、`run_console()`）：驱动 Stata 命令行、把日志解析成同一套带类型的 `RunResult`，支持 **Stata 13+ 且无需 pystata**\n- 零 Python 独立二进制（`scripts/build_standalone.py` + CI 工作流模板 `packaging/standalone.github-workflow.yml`）；配合 `--backend console` 是完全不依赖 Python 的一条龙\n- VS Code 一键上手：扩展可自动在工作区创建 `.venv` 并安装 server（命令面板：“Stata: Set Up MCP Server”）\n- 中文快速上手指南：[docs/quickstart.zh.md](docs/quickstart.zh.md)\n- Jupyter kernel：接入 v1.0 pipeline，kernel logo 已随 wheel 一起打包\n- 返回体预算：`include_results`（默认把矩阵降级为 `matrix://` stub）、`include_estimation`、`max_coefficients`，需要原始数值时用 `get_matrix(ref)` 按需拉取\n- 公共 Python API 和 MCP server 的 subprocess-backed 硬超时与取消：`timeout_ms`（现已成为 `stata_run` 的正式入参，并且把排队时间也计入预算 —— 同一 session 冲突时返回 `rc=-5` / `session_busy`，不再无限阻塞）、`cancel(session_id)`、MCP `cancel_session`\n- 长任务后台执行：`run_in_background` 立即返回 job id，用 `stata_run_status`（可 `wait_ms` 有界阻塞）和 `list_background_runs` 轮询\n- `do` / `run` 脚本内部的报错定位：`error.line` 和 `error.context` 落在被调用文件内，`error.source_file` 给出文件路径；失败的运行同样带有完整可检索的 log\n- log 句柄卫生：失败运行泄漏的 log 句柄会被自动关闭（`auto_close_logs`），中途 abort 的脚本不会让该 session 后续每次运行都以 r(604) 失败\n- 生成文件上报：`result.outputs` 列出每次运行写出的表格、导出文件和数据集，与 run bundle 选项无关\n- `.ipynb` 单 cell 修复闭环：`notebook_outline` / `notebook_get_cell` / `notebook_edit_cell`，并通过 `expected_source` 做乐观并发控制；`stata_run` 回显 `origin_cell_id`\n- 持久化 run bundle + `list_runs`：按 cell / origin / session / since / ok 查询 `manifest.json`，并用 limit / offset 翻页\n- 只读 `stata-code doctor` / `verify` 诊断：检查 package 版本、extras、\n  `pystata` 发现、console scripts、client 配置提示，以及可选的实时 Stata\n  版本探测\n- 经济学实证工作流层：现代 DiD、IV/弱工具变量、RDD、表格导出、data-MCP handoff、跨包/跨栈 parity audit 的 skill references 和 cookbook examples\n- 从 `schema.py` 自动生成 JSON Schema 工件：[`schema/run_result.schema.json`](schema/run_result.schema.json)\n- VS Code 扩展已发布到 Marketplace [`brycewang-stanford.stata-code-vscode`](https://marketplace.visualstudio.com/items?itemName=brycewang-stanford.stata-code-vscode)：语法高亮、section outline/navigation、code-lens cell/section runner、七视图侧边栏（sessions / last result / data 变量浏览器 / run history / logs / graphs / outputs）、状态栏、补全、保守变量重命名、诊断、MCP 子进程\n- Clean-room 许可证策略 ([LICENSE-POLICY.md](LICENSE-POLICY.md))\n\n### 下一步\n\n- 长任务的流式 / 增量进度（`log.complete:false`、部分日志行）。v0.11 的 `run_in_background` 已经让 20 分钟的 `boottest` / `csdid` 不再阻塞调用方，但运行中的任务在结束前仍然不汇报任何中间结果\n- Stata 11–16 的 console fallback，按 v1.0 schema 重新实现\n- 决定 Jupyter kernel 是否也迁到 subprocess pool，或者继续清楚记录当前为了交互性保留 in-process runner 的取舍\n- VS Code 体验打磨：Extension Host 端到端测试、首次启动诊断、命令面板 UX\n- **v1.0** —— 稳定 schema，覆盖更广的 Stata edition\n\n明确不做的范围见 [SCHEMA.md §7](SCHEMA.md)。\n\n---\n\n## 测试\n\n```bash\npip install -e \".[dev,mcp,kernel]\"\npytest                              # 完整测试集；本机有 Stata 时包含真实 Stata 集成测试\npytest -m \"not stata_required\"      # CI 子集，不需要 Stata\npytest -m \"stata_required\" -v       # 仅 Stata 集成测试\n```\n\n`stata_required` marker 标记真实 Stata 集成测试。CI 使用 `pytest -m \"not stata_required\"`，因此不会收集这些测试。本地没有 Stata 时，这些测试也会用 `\"pystata / Stata 17+ not available\"` 信息 cleanly skip。\n\n---\n\n## 贡献\n\n- 提 PR 前请先读 [LICENSE-POLICY.md](LICENSE-POLICY.md)。\n- 第一个 PR description 里请加一行 acknowledgement，模板在 policy 文件里。\n- 新增 schema field 或 runner 行为时必须补测试。\n\n---\n\n## 许可证\n\n代码使用 [MIT](./LICENSE)。[LICENSE-POLICY.md](LICENSE-POLICY.md) 说明本项目如何处理和其他 Stata 项目的关系。\n\n## 商标声明\n\nStata 是 StataCorp LLC 的注册商标。本项目是独立项目，不隶属于 StataCorp，也未获得 StataCorp 背书。\n\n## 致谢\n\n本项目参考和学习的 Stata 工具生态整理在 [References-tools.md](References-tools.md)。其中列出的项目保留各自的许可证和作者归属；复用前请查看对应仓库。\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003ca href=\"https://copaper.ai\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/brycewang-stanford/stata-code/main/branding/partners/copaper-logo.png\" alt=\"CoPaper.AI\" width=\"200\" /\u003e\u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd width=\"40\"\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003ca href=\"https://sccei.fsi.stanford.edu/reap\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/brycewang-stanford/stata-code/main/branding/partners/stanford-reap-logo.png\" alt=\"Stanford REAP\" width=\"280\" /\u003e\u003c/a\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003ca href=\"https://copaper.ai\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/brycewang-stanford/stata-code/main/branding/partners/copaper-qrcode.png\" alt=\"访问 copaper.ai\" width=\"160\" /\u003e\u003c/a\u003e\u003cbr/\u003e\n      \u003cstrong\u003e访问 \u003ca href=\"https://copaper.ai\"\u003ecopaper.ai\u003c/a\u003e\u003c/strong\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg src=\"https://raw.githubusercontent.com/brycewang-stanford/stata-code/main/branding/partners/copaper-wechat.jpg\" alt=\"CoPaper.AI 微信\" width=\"160\" /\u003e\u003cbr/\u003e\n      \u003cstrong\u003e微信公众号：CoPaper.AI\u003c/strong\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003csub\u003e由 \u003ca href=\"https://copaper.ai\"\u003e\u003cstrong\u003eCoPaper.AI\u003c/strong\u003e\u003c/a\u003e 维护，孵化于 \u003ca href=\"https://sccei.fsi.stanford.edu/reap\"\u003e\u003cstrong\u003eStanford REAP / SCCEI\u003c/strong\u003e\u003c/a\u003e · 实证研究 AI 助手\u003c/sub\u003e\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrycewang-stanford%2Fstata-code","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrycewang-stanford%2Fstata-code","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrycewang-stanford%2Fstata-code/lists"}