stata-code Skill
stata-code is an agent-native Stata bridge. This skill briefs Claude on how to drive Stata efficiently through it. Do not regress to log-grepping; the schema is the contract.
1. When this skill applies
Activate this skill whenever the user mentions Stata in a way that implies execution, inspection, repair, or authoring, e.g.:
- "Run this regression in Stata."
- "Why does
summarize mpgg fail?"
- "Fix this do-file and rerun it until it passes."
- "Open
analysis.ipynb cell 3 and replace it with a robust SE specification."
- "Pull
e(b) and the residual variance after my last regress."
- "Write a staggered DiD / event-study in Stata."
It also applies on context carry-over: if earlier turns were about Stata, keep the skill active even when a later message doesn't say "Stata".
Confirm the MCP server is wired up with stata_info() once per session — this also selects your execution mode (§2).
2. Execution mode: live vs offline
Live (MCP) mode — default. stata_info() returns available: true. Execute code with stata_run, read the structured result, and repair using typed errors (§7–8). This is the normal path; everything below assumes it.
Offline (code-gen) mode. No stata-code server, or stata_info() returns available: false. You cannot execute Stata. Do not pretend to. Instead:
- Surface the install hint once (
pip install "stata-code[mcp]") if the user expected execution.
- Produce a complete, self-contained
.do file: start with version 18, load the data, set seed before any randomness, comment each block, and bake in defensive guards (see references/defensive-coding.md).
- Present the code plus expected outputs, clearly labeled as not-yet-run.
3. Reference library — read on demand
The skill ships a references/ library of dense Stata domain knowledge. Progressive disclosure: read at most 1–3 files relevant to the current task — never preload them all. The schema and tool sections below are always in effect regardless of which references you open.
| If the task is about… |
Read |
| Core syntax, macros, missing values, loops, factor/time-series operators |
references/syntax-core.md |
| Loading, cleaning, merging, reshaping, labeling data |
references/data-management.md |
| Regression, GLM, IV mechanics, fixed effects, postestimation, margins |
references/econometrics.md |
| Causal designs — DiD, event study, RDD, matching/weighting, synthetic control |
references/causal-inference.md |
Panel data / time series — xtset, tsset, xtreg, dynamic panels, arima |
references/panel-timeseries.md |
| Plots and visualization |
references/graphics.md |
| Regression/summary tables, LaTeX/Word/Excel/Markdown export |
references/tables-export.md |
| Choosing public data sources or documenting source provenance |
references/data-sources.md |
| Data fetched by external MCPs should become Stata inputs |
references/data-mcp-handoff.md |
| Cross-package or cross-language robustness / parity checks |
references/parity-audit.md |
| Turnkey empirical recipes — DiD/event study, IV/2SLS, RDD, publication tables, cross-validation |
references/recipes/<recipe>.md |
Interpreting results.estimation (coefficient table, diagnostics), error.recovery, reproducible-do / submission bundles, verify_dataset |
references/structured-results.md |
Diagnosing a failed run, Stata rc codes, the self-repair loop |
references/error-codes.md |
| Writing correct, reproducible Stata that fails loudly (not silently) |
references/defensive-coding.md |
| A specific community package |
references/packages/<pkg>.md — reghdfe, csdid, drdid, did_imputation, eventstudyinteract, did_multiplegt_dyn, rdrobust, ivreg2, ivreghdfe, boottest, estout, outreg2, coefplot, gtools |
Routing examples: "panel regression with clustered SEs" → econometrics.md (+ panel-timeseries.md); "my merge gives wrong N" → defensive-coding.md; "command not found: reghdfe" → error-codes.md + packages/reghdfe.md; "make a publication table" → tables-export.md + recipes/publication-tables.md; "compare Stata csdid against R did" → parity-audit.md + packages/csdid.md; "OECD MCP pulled a CSV; now analyze it in Stata" → data-mcp-handoff.md; "run the full DiD/event-study workflow" → recipes/did-event-study.md.
4. The 21 MCP tools (cheat sheet)
| Tool |
Use it when… |
stata_run(code, session_id?, …) |
The user wants Stata code executed. Default to session_id="main". See §4.1 for the payload/timeout knobs. |
stata_run_status(job_id, wait_ms?) |
Poll a run you submitted with run_in_background: true. wait_ms blocks up to 60 s — far cheaper than a tight poll loop. |
list_background_runs() |
See which background runs are still going. Summaries only; fetch a result with stata_run_status. |
stata_info() |
At session start (also picks live vs offline mode), or when capabilities / Stata edition matter. |
get_log(ref) |
A prior stata_run returned log.truncated: true and you need the full log. |
search_log(ref, pattern, is_regex?, ignore_case?, context?, max_matches?) |
You need only specific lines from a truncated log:// ref — grep it instead of pulling the whole log back with get_log. |
get_graph(ref, format?) |
The user wants graph bytes (export, display, embed). |
get_matrix(ref) |
A matrix in results.r.matrices / results.e.matrices came back with values: null. By default every matrix is a stub, so this is the normal way to get raw e(V) / e(b) numbers. |
inspect_data(varlist?, detail?, session_id?) |
"What's in this dataset?" Runs describe + codebook; returns the structured dataset block plus the codebook log. |
lint_do(code? / path?) |
Before running a long or generated do-file, statically check it (unbalanced braces, missing end, dangling ///). Cheap, Stata-free; catches structural mistakes without spending a run. Advisory — a clean result is not a guarantee. |
install_package(name, source?, url?, replace?, session_id?) |
A run failed with command_not_found (rc 199) for a community package, or the user asks to install one. Builds ssc/net install, then verifies with which. |
list_sessions() |
The user mentions multiple parallel Stata "tabs", or you need to find a session by id. |
cancel_session(session_id) |
A run is hung or the user said "stop". Subprocess workers terminate; in-flight code is killed. |
reset_session(session_id?) |
The user wants clear all-style fresh state for a session. |
notebook_outline(path) |
The user references a .ipynb and you need to know which cells exist. |
notebook_get_cell(path, cell_id) |
Read one cell's source plus a compact outputs summary. |
notebook_locate(path, snippet/regex/error_text) |
Find which cell contains a snippet or produced an error message. |
notebook_edit_cell(path, cell_id, new_source, expected_source?) |
Atomic cell replace. Pass expected_source for optimistic concurrency. |
notebook_insert_cell(path, source, after_cell_id?, before_cell_id?, at_start?, at_end?, cell_type?) |
Insert a new cell with a fresh nbformat 4.5 uuid. |
notebook_delete_cell(path, cell_id, expected_source?) |
Remove a cell. Pass expected_source when guarding against drift. |
list_runs(log_dir or origin_path, …) |
Search the on-disk run-bundle index — "show me my last failed run on this file". |
4.1 stata_run options worth knowing
Defaults are already tuned for you; reach for these only when the situation calls for it.
| Option |
Default |
Reach for it when… |
include_results |
"scalars" |
You genuinely need raw matrix numbers inline: "full". Under the default, scalars and macros are inline and every matrix is a matrix:// stub with its shape — because one estimation otherwise ships the same numbers four times (e(b), e(V), e(beta), r(table)) on top of results.estimation. "none" drops r()/e() entirely and still gives you estimation. |
include_estimation |
"full" |
The model is dominated by i.year i.firm nuisance terms and you only want the model-level block: "summary". |
max_coefficients |
unset |
You want the first N coefficient rows. estimation.n_coefficients still reports the true count and coefficients_truncated flags the cut, so you can always tell. |
timeout_ms |
600000 |
A run legitimately needs longer, or you want to fail fast. The budget covers queueing, so a call waiting on a busy session returns rc: -5 rather than hanging. |
run_in_background |
false |
Bootstraps, permutation tests, prodest loops — anything multi-minute. Returns a job_id immediately; poll stata_run_status. Give the job its own session_id if you want to keep working, since one Stata process serves one session. |
track_output_files |
true |
Leave it on: result.outputs tells you which esttab tables / exports / .dta files the run wrote, so you don't have to go hunting with shell tools. |
auto_close_logs |
true |
Leave it on. It closes log handles a failed run leaked; without it an aborted log using makes every later run in that session die with r(604). |
There are also MCP resources (stata://schema/run-result, log://..., graph://..., matrix://...) and prompts (run_do_file_and_report, debug_stata_error, fix_and_rerun_until_passes, replication_audit, summarize_estimation_results, run_notebook_cell_and_report, fix_and_rerun_notebook_cell, plan_cross_stack_parity_audit, data_mcp_to_stata_handoff, did_event_study, iv_2sls, rdd, publication_table, cross_validate_did).
5. The v1.0 RunResult schema (read this once)
Every stata_run reply has this shape (full spec: stata://schema/run-result or SCHEMA.md in the repo):
{
"ok": true, // ← branch on this first
"rc": 0, // Stata _rc; -1 adapter crash, -2 timeout, -3 cancelled,
// -4 policy blocked, -5 session busy
"session_id": "main",
"request_id": "01HX…",
"started_at": "2026-…Z",
"elapsed_ms": 234,
"stata_elapsed_ms": 198,
"stata": {"version": "18.0", "edition": "MP", "backend": "pystata"},
"log": {
"head": "...", // first 20 lines by default
"tail": "...", // last 20 lines (empty when not truncated)
"lines_total": 42,
"bytes_total": 2380,
"truncated": true,
"error_window": null, // ~10 lines around the failure on errors
"ref": "log://run-7f3a9b" // fetch full via get_log(ref) / grep via search_log(ref)
},
"results": {
"r": {"scalars": {…}, "macros": {…}, "matrices": {…}},
// By default every matrix is a STUB: no values, no labels, just shape + ref.
"e": {"scalars": {…}, "macros": {…},
"matrices": {"b": {"rows": [], "cols": [], "values": null,
"ref": "matrix://…", "n_rows": 1, "n_cols": 2}, …}},
"last_estimation_cmd": "regress",
// ← THE typed view. Read this instead of the raw matrices.
"estimation": {
"command": "regress", "command_family": "ols", "depvar": "price",
"n_obs": 74, "statistic_kind": "t", "source": "r_table",
"coefficients": [{"term": "mpg", "b": …, "se": …, "statistic": …,
"p_value": …, "ci_low": …, "ci_high": …}, …],
"n_coefficients": 2, // true term count, even if rows were trimmed
"coefficients_truncated": false,
"model_stats": {"N": 74, "r2": 0.219, …},
"diagnostics": {"weak_id_F": …, "hansen_p": …} // command-aware, never fabricated
}
},
"dataset": {"frame": "default", "n_obs": 74, "n_vars": 12, "changed": false, …},
"graphs": [{"ref": "graph://…", "format": "png", "source_command": "scatter …", "source_line": 5}],
"outputs": [{"path": "/w/tables/t1.tex", "bytes": 4552, "created": true}], // files the run wrote
"warnings": [{"kind": "convergence", "message": "…"}],
"error": null, // populated iff ok=false; see §7
"origin": null, // echoes origin_* request fields
"schema_version": "1.0",
"capabilities": ["log_truncation", "graph_ref", "matrix_ref", "multi_session",
"result_budget", "background_runs", "output_tracking", "log_hygiene", …]
}
Key invariants:
- Branch on
ok first; never grep log.head to decide success.
- Scalars are native numbers. Missing is JSON
null, not "." and never 8.988e+307. The same holds for every matrix cell.
results.estimation is the coefficient table to read. It is always derived from the complete values, so it carries real se / p_value / CI even when the matrices are stubs. Do not reconstruct inference from e(b) and e(V) yourself.
- Matrices arrive as
values: null + a matrix:// ref by default — call get_matrix only when you need the raw numbers.
result.outputs lists the files the run wrote. Read it instead of shelling out to find the esttab table you just produced.
- Graphs default to refs, not base64 bytes.
include_graphs: "inline" now returns real image content blocks (viewable), capped at 4 per response.
6. Token-economy defaults — keep responses small
stata-code is already aggressive about this; do not undo its work:
- Do not pass
include_full_log: true unless the user asked for the full log or the head/tail clearly miss the relevant content.
- Do not pass
include_graphs: "inline" unless the agent needs the bytes (rare; usually surface the ref).
- Do not read
get_log(ref) proactively; prefer search_log(ref, pattern) to pull just the lines you need, and only fall back to get_log for the full transcript.
- Do not pass
include_results: "full" reflexively. results.estimation already has the typed table with real standard errors; "full" roughly doubles the envelope for a wide model and hands you the same numbers three more times.
- Do reach for
include_estimation: "summary" or max_coefficients when a model has dozens of fixed-effect terms you are not going to report.
- Do quote specific numbers from
results.estimation / results.e.scalars rather than dumping JSON.
- Do send genuinely long jobs to
run_in_background on their own session_id instead of blocking a foreground call for minutes.
7. The typed-error taxonomy (34 kinds)
On failure, the error block looks like:
{
"kind": "varname_not_found", // ← branch on this, not on rc or message
"rc": 111,
"rc_label": "variable not found",
"message": "variable mpgg not found",
"command": "summarize mpgg",
"line": 3, // line within source_file, else within submitted code
"source_file": null, // set when the failure was inside a `do`/`run` script
"context": {"before": ["use auto"], "failing": "summarize mpgg", "after": []},
"commands_executed": 1,
"varname": "mpgg", // populated for varname_* / file_* / name_* kinds
"suggestions": [{"action": "Did you mean `mpg`?", "command": "describe"}],
"recovery": {"category": "user_code", "retriable": false,
"needs_code_change": true, "needs_user_input": false}
}
When you submit do "analysis.do" and it fails, line and context point inside
analysis.do and source_file names it — you do not need to re-read the script to
find the offending line. A failed run also still carries a full log, so
search_log(ref, …) works on failures.
Kinds you will see most often:
varname_not_found (rc 111) — varname is filled; check dataset.variables for the right name.
syntax (rc 100–103/121–127/130/132/197/198) — usually a typo; inspect context.failing.
command_not_found (rc 199) — often a community package: install_package(name=...).
file_not_found / file_exists / file_corrupt (rc 601/602/610/688) — path is filled.
not_sorted (rc 5) — prepend sort <var>.
name_conflict (rc 110) — use replace or pick a fresh name.
convergence / infeasible (rc 430/491) — model issue, not a typo; do not loop on it.
no_estimation_results (rc 301) — likely predict/margins before any regress.
log_state (rc 604/606) — a log handle is in the wrong state, almost always left by an earlier aborted run. Fix is capture log close _all, not a code change; recovery.retriable is true. auto_close_logs prevents most of these.
session_busy (−5) — that session's Stata process is still running an earlier request. Nothing ran; the code is fine. Wait, raise timeout_ms, use a different session_id, or send the long job to the background.
timeout (−2) / cancelled (−3) / adapter_crash (−1) — system-level; do not retry blindly.
The full rc → kind → fix table and the self-repair algorithm live in references/error-codes.md. Read it whenever you hit a non-trivial failure. Use error.suggestions as hints, not directives — apply a fix automatically only if the user asked you to repair and rerun.
8. The two big workflows
8.1 Diagnose-only (default)
1. stata_run(code)
2. If ok: report scalars/warnings. Done.
3. If not ok:
- State error.kind, error.line, error.context.failing.
- List error.suggestions verbatim.
- Ask the user how to proceed (do not edit source files).
8.2 Fix-and-rerun-until-passes (only when the user said so)
Drive the loop from error.kind (full version in references/error-codes.md):
loop (cap ~5 iterations):
result = stata_run(current_code)
if result.ok: break
switch result.error.kind:
command_not_found → if community pkg: install_package(name); else fix spelling
varname_not_found → closest match from error.varname / dataset.variables
syntax → fix the line at error.line
not_sorted → prepend `sort <var>`
name_conflict → add `replace` or drop the conflicting object first
file_not_found → fix error.path or generate the missing file
convergence/infeasible/estimation_failure → MODEL issue: respecify, do NOT loop
adapter_crash/timeout/cancelled → STOP and surface to the user
policy_blocked → the code used a blocked OS-escape command (shell/erase/rmdir/!);
do the task with a native Stata command instead, do NOT retry as-is
rewrite the .do file or notebook cell; re-run
if the same kind+line repeats unchanged twice → STOP with a summary
For notebook repair, use notebook_edit_cell(path, cell_id, new_source, expected_source=<old>) with optimistic concurrency so a user-side edit aborts your write rather than silently overwriting it.
9. Multi-session etiquette
- Default session is
"main". Long analyses with conflicting state belong in named sessions (session_id="model_a"). Valid ids match [A-Za-z0-9_-]+; ids that are not legal Stata frame names are mapped to private frames and still echo the public id.
- The VS Code extension calls sessions "tabs". A new session lazily spawns or maps to a Stata frame; data does not cross.
- After heavy state changes, prefer
reset_session(session_id) over rerunning with clear all — it is cheaper and clears refs.
10. Origin metadata (helpful for run-bundle audit)
When the user supplies a source file or notebook cell, pass:
origin_path: absolute path of the .do / .ipynb
origin_kind: "file", "selection", "line", "cell", "section", "code"
origin_label: "analysis/main.do:42" or similar
origin_cell_id: nbformat 4.5 cell uuid when it's a notebook cell
The runner echoes these into result.origin and writes them to the run-bundle manifest. list_runs then finds prior runs by cell or by file.
11. Things to NOT do
- Do not shell out to
stata / do-file editor / pystata directly. Use stata_run.
- Do not use OS-escape / file-deletion commands (
shell, winexec, erase, rm, rmdir, !) inside stata_run. They are blocked by the command-safety policy and return policy_blocked. Stay within native Stata data commands (save / use / copy); if a file genuinely must be deleted, ask the user to do it or to relax the policy.
- Do not parse English from
log.head to detect success — use ok / rc / error.kind.
- Do not retry a failing command unchanged. The taxonomy tells you why it failed; act on it or report it.
- Do not loop the fix-and-rerun routine on a model problem (
convergence, infeasible).
- Do not assume
e() is populated after a non-estimation command. Check results.last_estimation_cmd first.
- Do not rewrite a
.do file or .ipynb cell unless the user asked for repair. Diagnostics first.
- Do not paste graph base64 into chat unless the user explicitly asked for bytes; graphs go through
get_graph(ref).
- Do not preload the whole
references/ library — open only the 1–3 files the task needs.
12. Reference
- Domain knowledge: the
references/ library (routing table in §3).
- Full schema:
SCHEMA.md in the repo or the MCP resource stata://schema/run-result.
- Server capabilities + tool list: MCP resource
stata://server/capabilities.
- Examples (DiD, IV, graphs, multi-session, large matrices, parity audits, data-MCP handoff):
examples/ in the repo.
- License: MIT (
stata-code itself); Stata is a registered trademark of StataCorp LLC.
1---2name: stata-code3description: Use this skill whenever the user asks to run Stata code, debug a `.do` file, work with a Stata-backed Jupyter notebook, repair a Stata error, interpret `r()` / `e()` results, or write/plan a Stata analysis — and the `stata-code` MCP server is available (or, when it is not, to generate self-contained do-files). The skill teaches Claude the v1.0 RunResult schema, the 21 MCP tools, token-economy defaults, the typed-error repair loop, and a routing table into an on-demand Stata reference library (syntax, data management, econometrics, causal inference, panel/time series, graphics, tables, error codes, defensive coding, and key packages).4---56# stata-code Skill78`stata-code` is an agent-native Stata bridge. This skill briefs Claude on how to drive Stata efficiently through it. **Do not regress to log-grepping; the schema is the contract.**910## 1. When this skill applies1112Activate this skill whenever the user mentions Stata in a way that implies execution, inspection, repair, or authoring, e.g.:1314- "Run this regression in Stata."15- "Why does `summarize mpgg` fail?"16- "Fix this do-file and rerun it until it passes."17- "Open `analysis.ipynb` cell 3 and replace it with a robust SE specification."18- "Pull `e(b)` and the residual variance after my last `regress`."19- "Write a staggered DiD / event-study in Stata."2021It also applies on context carry-over: if earlier turns were about Stata, keep the skill active even when a later message doesn't say "Stata".2223Confirm the MCP server is wired up with `stata_info()` once per session — this also selects your execution mode (§2).2425## 2. Execution mode: live vs offline2627**Live (MCP) mode — default.** `stata_info()` returns `available: true`. Execute code with `stata_run`, read the structured result, and repair using typed errors (§7–8). This is the normal path; everything below assumes it.2829**Offline (code-gen) mode.** No stata-code server, or `stata_info()` returns `available: false`. You cannot execute Stata. Do **not** pretend to. Instead:3031- Surface the install hint once (`pip install "stata-code[mcp]"`) if the user expected execution.32- Produce a **complete, self-contained `.do` file**: start with `version 18`, load the data, `set seed` before any randomness, comment each block, and bake in defensive guards (see `references/defensive-coding.md`).33- Present the code plus *expected* outputs, clearly labeled as not-yet-run.3435## 3. Reference library — read on demand3637The skill ships a `references/` library of dense Stata domain knowledge. **Progressive disclosure: read at most 1–3 files relevant to the current task — never preload them all.** The schema and tool sections below are always in effect regardless of which references you open.3839| If the task is about… | Read |40|---|---|41| Core syntax, macros, missing values, loops, factor/time-series operators | `references/syntax-core.md` |42| Loading, cleaning, merging, reshaping, labeling data | `references/data-management.md` |43| Regression, GLM, IV mechanics, fixed effects, postestimation, margins | `references/econometrics.md` |44| Causal designs — DiD, event study, RDD, matching/weighting, synthetic control | `references/causal-inference.md` |45| Panel data / time series — `xtset`, `tsset`, `xtreg`, dynamic panels, `arima` | `references/panel-timeseries.md` |46| Plots and visualization | `references/graphics.md` |47| Regression/summary tables, LaTeX/Word/Excel/Markdown export | `references/tables-export.md` |48| Choosing public data sources or documenting source provenance | `references/data-sources.md` |49| Data fetched by external MCPs should become Stata inputs | `references/data-mcp-handoff.md` |50| Cross-package or cross-language robustness / parity checks | `references/parity-audit.md` |51| Turnkey empirical recipes — DiD/event study, IV/2SLS, RDD, publication tables, cross-validation | `references/recipes/<recipe>.md` |52| Interpreting `results.estimation` (coefficient table, diagnostics), `error.recovery`, reproducible-do / submission bundles, `verify_dataset` | `references/structured-results.md` |53| Diagnosing a failed run, Stata `rc` codes, the self-repair loop | `references/error-codes.md` |54| Writing correct, reproducible Stata that fails loudly (not silently) | `references/defensive-coding.md` |55| A specific community package | `references/packages/<pkg>.md` — `reghdfe`, `csdid`, `drdid`, `did_imputation`, `eventstudyinteract`, `did_multiplegt_dyn`, `rdrobust`, `ivreg2`, `ivreghdfe`, `boottest`, `estout`, `outreg2`, `coefplot`, `gtools` |5657Routing examples: "panel regression with clustered SEs" → `econometrics.md` (+ `panel-timeseries.md`); "my merge gives wrong N" → `defensive-coding.md`; "command not found: reghdfe" → `error-codes.md` + `packages/reghdfe.md`; "make a publication table" → `tables-export.md` + `recipes/publication-tables.md`; "compare Stata csdid against R did" → `parity-audit.md` + `packages/csdid.md`; "OECD MCP pulled a CSV; now analyze it in Stata" → `data-mcp-handoff.md`; "run the full DiD/event-study workflow" → `recipes/did-event-study.md`.5859## 4. The 21 MCP tools (cheat sheet)6061| Tool | Use it when… |62|---|---|63| `stata_run(code, session_id?, …)` | The user wants Stata code executed. Default to `session_id="main"`. See §4.1 for the payload/timeout knobs. |64| `stata_run_status(job_id, wait_ms?)` | Poll a run you submitted with `run_in_background: true`. `wait_ms` blocks up to 60 s — far cheaper than a tight poll loop. |65| `list_background_runs()` | See which background runs are still going. Summaries only; fetch a result with `stata_run_status`. |66| `stata_info()` | At session start (also picks live vs offline mode), or when capabilities / Stata edition matter. |67| `get_log(ref)` | A prior `stata_run` returned `log.truncated: true` and you need the full log. |68| `search_log(ref, pattern, is_regex?, ignore_case?, context?, max_matches?)` | You need only specific lines from a truncated `log://` ref — grep it instead of pulling the whole log back with `get_log`. |69| `get_graph(ref, format?)` | The user wants graph bytes (export, display, embed). |70| `get_matrix(ref)` | A matrix in `results.r.matrices` / `results.e.matrices` came back with `values: null`. By default *every* matrix is a stub, so this is the normal way to get raw `e(V)` / `e(b)` numbers. |71| `inspect_data(varlist?, detail?, session_id?)` | "What's in this dataset?" Runs `describe` + `codebook`; returns the structured `dataset` block plus the codebook log. |72| `lint_do(code? / path?)` | Before running a long or generated do-file, statically check it (unbalanced braces, missing `end`, dangling `///`). Cheap, Stata-free; catches structural mistakes without spending a run. Advisory — a clean result is not a guarantee. |73| `install_package(name, source?, url?, replace?, session_id?)` | A run failed with `command_not_found` (rc 199) for a community package, or the user asks to install one. Builds `ssc`/`net install`, then verifies with `which`. |74| `list_sessions()` | The user mentions multiple parallel Stata "tabs", or you need to find a session by id. |75| `cancel_session(session_id)` | A run is hung or the user said "stop". Subprocess workers terminate; in-flight code is killed. |76| `reset_session(session_id?)` | The user wants `clear all`-style fresh state for a session. |77| `notebook_outline(path)` | The user references a `.ipynb` and you need to know which cells exist. |78| `notebook_get_cell(path, cell_id)` | Read one cell's source plus a compact outputs summary. |79| `notebook_locate(path, snippet/regex/error_text)` | Find which cell contains a snippet or produced an error message. |80| `notebook_edit_cell(path, cell_id, new_source, expected_source?)` | Atomic cell replace. Pass `expected_source` for optimistic concurrency. |81| `notebook_insert_cell(path, source, after_cell_id?, before_cell_id?, at_start?, at_end?, cell_type?)` | Insert a new cell with a fresh nbformat 4.5 uuid. |82| `notebook_delete_cell(path, cell_id, expected_source?)` | Remove a cell. Pass `expected_source` when guarding against drift. |83| `list_runs(log_dir or origin_path, …)` | Search the on-disk run-bundle index — "show me my last failed run on this file". |8485### 4.1 `stata_run` options worth knowing8687Defaults are already tuned for you; reach for these only when the situation calls for it.8889| Option | Default | Reach for it when… |90|---|---|---|91| `include_results` | `"scalars"` | You genuinely need raw matrix numbers inline: `"full"`. Under the default, scalars and macros are inline and every matrix is a `matrix://` stub with its shape — because one estimation otherwise ships the same numbers four times (`e(b)`, `e(V)`, `e(beta)`, `r(table)`) on top of `results.estimation`. `"none"` drops `r()`/`e()` entirely and still gives you `estimation`. |92| `include_estimation` | `"full"` | The model is dominated by `i.year i.firm` nuisance terms and you only want the model-level block: `"summary"`. |93| `max_coefficients` | unset | You want the first N coefficient rows. `estimation.n_coefficients` still reports the true count and `coefficients_truncated` flags the cut, so you can always tell. |94| `timeout_ms` | `600000` | A run legitimately needs longer, or you want to fail fast. The budget covers **queueing**, so a call waiting on a busy session returns `rc: -5` rather than hanging. |95| `run_in_background` | `false` | Bootstraps, permutation tests, `prodest` loops — anything multi-minute. Returns a `job_id` immediately; poll `stata_run_status`. **Give the job its own `session_id`** if you want to keep working, since one Stata process serves one session. |96| `track_output_files` | `true` | Leave it on: `result.outputs` tells you which `esttab` tables / exports / `.dta` files the run wrote, so you don't have to go hunting with shell tools. |97| `auto_close_logs` | `true` | Leave it on. It closes log handles a *failed* run leaked; without it an aborted `log using` makes every later run in that session die with r(604). |9899There are also MCP resources (`stata://schema/run-result`, `log://...`, `graph://...`, `matrix://...`) and prompts (`run_do_file_and_report`, `debug_stata_error`, `fix_and_rerun_until_passes`, `replication_audit`, `summarize_estimation_results`, `run_notebook_cell_and_report`, `fix_and_rerun_notebook_cell`, `plan_cross_stack_parity_audit`, `data_mcp_to_stata_handoff`, `did_event_study`, `iv_2sls`, `rdd`, `publication_table`, `cross_validate_did`).100101## 5. The v1.0 RunResult schema (read this once)102103Every `stata_run` reply has this shape (full spec: `stata://schema/run-result` or `SCHEMA.md` in the repo):104105```jsonc106{107 "ok": true, // ← branch on this first108 "rc": 0, // Stata _rc; -1 adapter crash, -2 timeout, -3 cancelled,109 // -4 policy blocked, -5 session busy110 "session_id": "main",111 "request_id": "01HX…",112 "started_at": "2026-…Z",113 "elapsed_ms": 234,114 "stata_elapsed_ms": 198,115 "stata": {"version": "18.0", "edition": "MP", "backend": "pystata"},116117 "log": {118 "head": "...", // first 20 lines by default119 "tail": "...", // last 20 lines (empty when not truncated)120 "lines_total": 42,121 "bytes_total": 2380,122 "truncated": true,123 "error_window": null, // ~10 lines around the failure on errors124 "ref": "log://run-7f3a9b" // fetch full via get_log(ref) / grep via search_log(ref)125 },126127 "results": {128 "r": {"scalars": {…}, "macros": {…}, "matrices": {…}},129 // By default every matrix is a STUB: no values, no labels, just shape + ref.130 "e": {"scalars": {…}, "macros": {…},131 "matrices": {"b": {"rows": [], "cols": [], "values": null,132 "ref": "matrix://…", "n_rows": 1, "n_cols": 2}, …}},133 "last_estimation_cmd": "regress",134 // ← THE typed view. Read this instead of the raw matrices.135 "estimation": {136 "command": "regress", "command_family": "ols", "depvar": "price",137 "n_obs": 74, "statistic_kind": "t", "source": "r_table",138 "coefficients": [{"term": "mpg", "b": …, "se": …, "statistic": …,139 "p_value": …, "ci_low": …, "ci_high": …}, …],140 "n_coefficients": 2, // true term count, even if rows were trimmed141 "coefficients_truncated": false,142 "model_stats": {"N": 74, "r2": 0.219, …},143 "diagnostics": {"weak_id_F": …, "hansen_p": …} // command-aware, never fabricated144 }145 },146147 "dataset": {"frame": "default", "n_obs": 74, "n_vars": 12, "changed": false, …},148 "graphs": [{"ref": "graph://…", "format": "png", "source_command": "scatter …", "source_line": 5}],149 "outputs": [{"path": "/w/tables/t1.tex", "bytes": 4552, "created": true}], // files the run wrote150 "warnings": [{"kind": "convergence", "message": "…"}],151152 "error": null, // populated iff ok=false; see §7153 "origin": null, // echoes origin_* request fields154 "schema_version": "1.0",155 "capabilities": ["log_truncation", "graph_ref", "matrix_ref", "multi_session",156 "result_budget", "background_runs", "output_tracking", "log_hygiene", …]157}158```159160**Key invariants:**161- Branch on `ok` first; never grep `log.head` to decide success.162- Scalars are native numbers. Missing is JSON `null`, not `"."` and never `8.988e+307`. The same holds for every matrix cell.163- **`results.estimation` is the coefficient table to read.** It is always derived from the complete values, so it carries real `se` / `p_value` / CI even when the matrices are stubs. Do not reconstruct inference from `e(b)` and `e(V)` yourself.164- Matrices arrive as `values: null` + a `matrix://` ref by default — call `get_matrix` only when you need the raw numbers.165- `result.outputs` lists the files the run wrote. Read it instead of shelling out to find the `esttab` table you just produced.166- Graphs default to refs, not base64 bytes. `include_graphs: "inline"` now returns real image content blocks (viewable), capped at 4 per response.167168## 6. Token-economy defaults — keep responses small169170`stata-code` is already aggressive about this; do not undo its work:171172- **Do not** pass `include_full_log: true` unless the user asked for the full log or the head/tail clearly miss the relevant content.173- **Do not** pass `include_graphs: "inline"` unless the agent needs the bytes (rare; usually surface the `ref`).174- **Do not** read `get_log(ref)` proactively; prefer `search_log(ref, pattern)` to pull just the lines you need, and only fall back to `get_log` for the full transcript.175- **Do not** pass `include_results: "full"` reflexively. `results.estimation` already has the typed table with real standard errors; `"full"` roughly doubles the envelope for a wide model and hands you the same numbers three more times.176- **Do** reach for `include_estimation: "summary"` or `max_coefficients` when a model has dozens of fixed-effect terms you are not going to report.177- **Do** quote specific numbers from `results.estimation` / `results.e.scalars` rather than dumping JSON.178- **Do** send genuinely long jobs to `run_in_background` on their own `session_id` instead of blocking a foreground call for minutes.179180## 7. The typed-error taxonomy (34 kinds)181182On failure, the `error` block looks like:183184```jsonc185{186 "kind": "varname_not_found", // ← branch on this, not on rc or message187 "rc": 111,188 "rc_label": "variable not found",189 "message": "variable mpgg not found",190 "command": "summarize mpgg",191 "line": 3, // line within source_file, else within submitted code192 "source_file": null, // set when the failure was inside a `do`/`run` script193 "context": {"before": ["use auto"], "failing": "summarize mpgg", "after": []},194 "commands_executed": 1,195 "varname": "mpgg", // populated for varname_* / file_* / name_* kinds196 "suggestions": [{"action": "Did you mean `mpg`?", "command": "describe"}],197 "recovery": {"category": "user_code", "retriable": false,198 "needs_code_change": true, "needs_user_input": false}199}200```201202When you submit `do "analysis.do"` and it fails, `line` and `context` point **inside203`analysis.do`** and `source_file` names it — you do not need to re-read the script to204find the offending line. A failed run also still carries a full `log`, so205`search_log(ref, …)` works on failures.206207Kinds you will see most often:208209- `varname_not_found` (rc 111) — `varname` is filled; check `dataset.variables` for the right name.210- `syntax` (rc 100–103/121–127/130/132/197/198) — usually a typo; inspect `context.failing`.211- `command_not_found` (rc 199) — often a community package: `install_package(name=...)`.212- `file_not_found` / `file_exists` / `file_corrupt` (rc 601/602/610/688) — `path` is filled.213- `not_sorted` (rc 5) — prepend `sort <var>`.214- `name_conflict` (rc 110) — use `replace` or pick a fresh name.215- `convergence` / `infeasible` (rc 430/491) — model issue, not a typo; do not loop on it.216- `no_estimation_results` (rc 301) — likely `predict`/`margins` before any `regress`.217- `log_state` (rc 604/606) — a log handle is in the wrong state, almost always left by an earlier aborted run. Fix is `capture log close _all`, **not** a code change; `recovery.retriable` is true. `auto_close_logs` prevents most of these.218- `session_busy` (−5) — that session's Stata process is still running an earlier request. **Nothing ran**; the code is fine. Wait, raise `timeout_ms`, use a different `session_id`, or send the long job to the background.219- `timeout` (−2) / `cancelled` (−3) / `adapter_crash` (−1) — system-level; do not retry blindly.220221**The full rc → kind → fix table and the self-repair algorithm live in `references/error-codes.md`.** Read it whenever you hit a non-trivial failure. Use `error.suggestions` as hints, **not** directives — apply a fix automatically only if the user asked you to repair and rerun.222223## 8. The two big workflows224225### 8.1 Diagnose-only (default)226227```text2281. stata_run(code)2292. If ok: report scalars/warnings. Done.2303. If not ok:231 - State error.kind, error.line, error.context.failing.232 - List error.suggestions verbatim.233 - Ask the user how to proceed (do not edit source files).234```235236### 8.2 Fix-and-rerun-until-passes (only when the user said so)237238Drive the loop from `error.kind` (full version in `references/error-codes.md`):239240```text241loop (cap ~5 iterations):242 result = stata_run(current_code)243 if result.ok: break244 switch result.error.kind:245 command_not_found → if community pkg: install_package(name); else fix spelling246 varname_not_found → closest match from error.varname / dataset.variables247 syntax → fix the line at error.line248 not_sorted → prepend `sort <var>`249 name_conflict → add `replace` or drop the conflicting object first250 file_not_found → fix error.path or generate the missing file251 convergence/infeasible/estimation_failure → MODEL issue: respecify, do NOT loop252 adapter_crash/timeout/cancelled → STOP and surface to the user253 policy_blocked → the code used a blocked OS-escape command (shell/erase/rmdir/!);254 do the task with a native Stata command instead, do NOT retry as-is255 rewrite the .do file or notebook cell; re-run256 if the same kind+line repeats unchanged twice → STOP with a summary257```258259For notebook repair, use `notebook_edit_cell(path, cell_id, new_source, expected_source=<old>)` with optimistic concurrency so a user-side edit aborts your write rather than silently overwriting it.260261## 9. Multi-session etiquette262263- Default session is `"main"`. Long analyses with conflicting state belong in named sessions (`session_id="model_a"`). Valid ids match `[A-Za-z0-9_-]+`; ids that are not legal Stata frame names are mapped to private frames and still echo the public id.264- The VS Code extension calls sessions "tabs". A new session lazily spawns or maps to a Stata frame; data does not cross.265- After heavy state changes, prefer `reset_session(session_id)` over rerunning with `clear all` — it is cheaper and clears refs.266267## 10. Origin metadata (helpful for run-bundle audit)268269When the user supplies a source file or notebook cell, pass:270271- `origin_path`: absolute path of the `.do` / `.ipynb`272- `origin_kind`: `"file"`, `"selection"`, `"line"`, `"cell"`, `"section"`, `"code"`273- `origin_label`: `"analysis/main.do:42"` or similar274- `origin_cell_id`: nbformat 4.5 cell uuid when it's a notebook cell275276The runner echoes these into `result.origin` and writes them to the run-bundle manifest. `list_runs` then finds prior runs by cell or by file.277278## 11. Things to NOT do279280- Do not shell out to `stata` / `do-file editor` / `pystata` directly. Use `stata_run`.281- Do not use OS-escape / file-deletion commands (`shell`, `winexec`, `erase`, `rm`, `rmdir`, `!`) inside `stata_run`. They are blocked by the command-safety policy and return `policy_blocked`. Stay within native Stata data commands (`save` / `use` / `copy`); if a file genuinely must be deleted, ask the user to do it or to relax the policy.282- Do not parse English from `log.head` to detect success — use `ok` / `rc` / `error.kind`.283- Do not retry a failing command unchanged. The taxonomy tells you why it failed; act on it or report it.284- Do not loop the fix-and-rerun routine on a model problem (`convergence`, `infeasible`).285- Do not assume `e()` is populated after a non-estimation command. Check `results.last_estimation_cmd` first.286- Do not rewrite a `.do` file or `.ipynb` cell unless the user asked for repair. Diagnostics first.287- Do not paste graph base64 into chat unless the user explicitly asked for bytes; graphs go through `get_graph(ref)`.288- Do not preload the whole `references/` library — open only the 1–3 files the task needs.289290## 12. Reference291292- Domain knowledge: the `references/` library (routing table in §3).293- Full schema: `SCHEMA.md` in the repo or the MCP resource `stata://schema/run-result`.294- Server capabilities + tool list: MCP resource `stata://server/capabilities`.295- Examples (DiD, IV, graphs, multi-session, large matrices, parity audits, data-MCP handoff): `examples/` in the repo.296- License: MIT (`stata-code` itself); Stata is a registered trademark of StataCorp LLC.