Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

Version License GitHub

Stata projects increasingly run inside larger workflows — a Makefile that rebuilds results when inputs change, a CI service that reruns an analysis on every commit, a replication package that must run unattended on a stranger’s machine. Integration like this rests on two things Stata leaves implicit: whether a step succeeded, and what the project needs in order to run.

stacy makes both explicit. It is a task runner and package manager for Stata: stacy run executes a script, parses the log, and returns a proper exit code, while stacy add and stacy install maintain a manifest and lockfile for dependencies. Every command works from both the terminal and the Stata console. With these primitives, Stata projects can be automated, versioned, and reproduced.

If you know…stacy is like…Key similarity
RustCargoManifest + lockfile + build orchestration
Pythonuv or PoetryProject dependencies + reproducible environments
JavaScriptnpmpackage.json / package-lock.json workflow
RrenvProject-local library snapshots
Stata(nothing existed)This is what stacy provides

The Problem

The outcome is implicit. Stata’s batch mode (stata-mp -b do script.do) exits with code 0 even when scripts fail. Errors are buried in logs. Build systems, CI pipelines, and downstream scripts cannot detect failure — they proceed as if nothing went wrong.

The environment is implicit. User-written packages install to a global path — no manifest, no lockfile, no isolation between projects. There is no way to declare dependencies and install from that declaration. Each ssc install retrieves whatever version exists at that moment; a collaborator installing later gets a different version entirely.

The Solution

stacy makes both sides explicit:

# Execution: proper exit codes
stacy run analysis.do
echo $?  # 0 on success, 1-10 on various errors

# Environment: lockfile-based packages
stacy add estout reghdfe    # Adds to stacy.toml, creates stacy.lock
stacy install               # Installs exact versions from lockfile

A project that declares its dependencies can be installed identically elsewhere. A project that signals failure can be automated reliably:

  • Journals can verify that replication packages run
  • Cluster jobs fail fast instead of silently producing garbage
  • Collaborators work from the same locked environment rather than debugging “it worked on my machine”
results/output.dta: analysis.do data/input.dta
    stacy run analysis.do   # Stops on failure

One Tool, Two Interfaces

stacy is a single binary you can drive from the terminal or from inside Stata:

# Terminal
$ stacy run analysis.do --timeout 600
. stacy run analysis.do, timeout(600)

The Stata commands are thin wrappers around the same binary, generated from the same command schema as the command-line interface, so the two never drift apart. help stacy works as for any other Stata package. See Installation for setup.

What stacy Manages (and What It Doesn’t)

stacy makes two things explicit – execution outcomes and the package environment – and stays out of everything else:

stacy managesstacy does not manage
Whether a script succeeded (exit codes)Orchestrating large pipelines (use Make/Snakemake on top)
Which packages a project needs (manifest)The Stata version itself (use Docker for full-stack pinning)
Which exact versions are installed (lockfile + checksums)Data files or other languages’ environments
Where Stata looks for packages at runtime (S_ADO)Transitive dependencies (Stata packages don’t declare them reliably)

This makes stacy a small, composable piece of infrastructure rather than a framework: it slots under whatever build system, scheduler, or CI service you already use.

At a Glance

Without stacyWith stacy
stata -b do script.do returns 0 even on errorstacy run script.do returns 1-10 on error
Packages are global, unversionedstacy.lock pins exact versions with SHA256 checksums
Errors buried in log filesErrors displayed with documentation links
“It worked on my machine”Same versions everywhere via lockfile
Manual ssc install in scriptsstacy install from lockfile

Quick Example

# Run with error detection
stacy run analysis.do

# Initialize a project and add packages
stacy init
stacy add estout reghdfe

# Install all packages from lockfile (like npm install)
stacy install

# Check system configuration
stacy doctor

How to Use These Docs

Next Steps

Installation

stacy is a single static binary with no runtime dependencies.

Quick Install

macOS / Linux:

curl -fsSL https://stacy.janfasnacht.com/install.sh | bash

Windows (PowerShell):

irm https://raw.githubusercontent.com/janfasnacht/stacy/main/install.ps1 | iex

Both install to ~/.local/bin/ (or equivalent). Ensure this directory is in your PATH.

From within Stata

If you prefer not to leave Stata, you can install stacy directly from the Stata console:

net install stacy, from("https://stacy.janfasnacht.com/stata")
stacy setup

This downloads the Stata wrappers and installs the stacy binary to ~/.local/bin/. After setup, all stacy commands are available as native Stata commands (e.g., stacy run analysis.do, stacy add estout).

Other Methods

Homebrew:

brew install janfasnacht/stacy/stacy

Cargo (from source):

cargo install --git https://github.com/janfasnacht/stacy.git

Manual download: Get binaries from the releases page.

Verify Installation

stacy --version    # Check version
stacy doctor       # Check Stata detection and configuration

Stata Detection

stacy automatically finds Stata in common locations:

PlatformSearched paths
macOS/Applications/Stata*/, /Applications/StataNow/
Linux/usr/local/stata*, ~/stata*
WindowsC:\Program Files\Stata*\

If Stata is elsewhere, configure via (in precedence order):

  1. CLI flag: stacy run --engine /path/to/stata-mp script.do
  2. Environment: export STATA_BINARY=/path/to/stata-mp
  3. Config file: ~/.config/stacy/config.toml

Troubleshooting

Common installation issues:

ProblemSolution
stacy: command not foundAdd ~/.local/bin to PATH, restart terminal
macOS blocks binaryRun xattr -d com.apple.quarantine ~/.local/bin/stacy
Stata not foundSet STATA_BINARY env var or config file

See Troubleshooting for detailed solutions.

Updating

Re-run the install command, or:

brew upgrade stacy              # Homebrew
cargo install ... --force     # Cargo

Update Notifications

stacy checks for new releases on startup and prints a notification to stderr if one is available:

Update available: v1.1.0 → v1.2.0
Run `brew upgrade stacy` to update

The check uses a local cache refreshed every 24 hours in the background. It never slows down commands.

Update notifications are automatically suppressed in CI environments, non-interactive sessions, and piped output. To disable globally, set update_check = false in ~/.config/stacy/config.toml or set the STACY_NO_UPDATE_CHECK environment variable.

Uninstalling

rm ~/.local/bin/stacy           # Remove binary
rm -rf ~/.config/stacy          # Remove config (optional)
rm -rf ~/.cache/stacy           # Remove package cache (optional)

Next Steps

Quick Start

This page uses terminal commands. If you installed the Stata wrappers, every command also works from the Stata console – . stacy run analysis.do instead of $ stacy run analysis.do.

1. Verify Setup

stacy doctor

This checks that stacy can find Stata. If it fails, see Troubleshooting.

2. Run a Script

stacy run analysis.do

On success: exit code 0. On failure: non-zero exit code with error details.

❌ Failed: analysis.do (0.08s)

   Error: r(199) - unrecognized command
   See: https://www.stata.com/manuals/perror.pdf#r199

That’s it. Your existing scripts work unchanged.

3. Initialize a Project

stacy init

Creates stacy.toml (project configuration) and .gitignore.

4. Add Packages

stacy add estout reghdfe

This adds packages to stacy.toml, downloads them to the cache, and creates stacy.lock with exact versions.

To install from an existing lockfile:

stacy install

Your dependencies are now pinned. Anyone running stacy install gets the same versions.

5. Define Tasks

Add a [scripts] section to stacy.toml:

[scripts]
clean = "clean_data.do"
analysis = "run_analysis.do"
all = ["clean", "analysis"]

Run tasks by name:

stacy task clean       # Run one script
stacy task all         # Run sequence

This replaces master.do with explicit, named tasks that stop on error.

For complex pipelines with dependency tracking, see Build Integration.

Common Options

stacy run -v analysis.do       # Stream log output
stacy run -c 'display 2+2'     # Run inline code
stacy run --format json ...    # Machine-readable output

Next Steps

Project Config (stacy.toml)

The stacy.toml file configures project-level settings. Created by stacy init.

Location

my-project/
├── stacy.toml    # Project config (this file)
├── stacy.lock    # Package lockfile
└── ...

Full Reference

[project]
name = "my-analysis"
authors = ["Jane Doe <jane@university.edu>"]
description = "Economic analysis of market dynamics"
url = "https://github.com/user/my-analysis"

[run]
log_dir = "logs"
show_progress = true
progress_interval_seconds = 10
max_log_size_mb = 50

[paths]
ado = ["ado", "lib/custom"]

[packages.dependencies]
estout = "ssc"
reghdfe = "github:sergiocorreia/reghdfe"

[packages.dev]
assert = "ssc"

[scripts]
clean = "src/01_clean.do"
analyze = "src/02_analyze.do"
build = ["clean", "analyze"]

Sections

[project]

Project metadata. Optional but recommended for collaborative projects.

FieldTypeDefaultDescription
namestringdirectory nameProject name
authorsarray[]List of authors
descriptionstringnoneProject description
urlstringnoneProject URL

[run]

Settings for stacy run command.

FieldTypeDefaultDescription
log_dirstring"logs"Directory for kept log files, relative to the project root
show_progressbooltrueShow progress during execution
progress_interval_secondsint10Progress update interval
max_log_size_mbint50Log size warning threshold

Batch logs are internal: a script that succeeds leaves none behind. A script that fails keeps its log, and log_dir is where it goes — for stacy run as well as the scripts run by stacy task, stacy test and stacy bench. The directory is created when the first log needs it. stacy run --log <path> overrides log_dir for that run.

[paths]

Local ado directories to prepend to S_ADO. Paths are relative to the project root and resolved to absolute paths at runtime. This lets strict mode work with project-local .ado programs without needing adopath ++ boilerplate.

FieldTypeDefaultDescription
adoarray[]Local ado directories
[paths]
ado = ["ado", "lib/custom"]

Directories are prepended to S_ADO in declared order, before package cache paths. Non-existent paths produce a warning in stacy doctor but are not a hard error.

[packages.dependencies], [packages.dev], [packages.test]

Package dependencies by group. Format: package_name = "source".

[packages.dependencies]
estout = "ssc"                              # From SSC
reghdfe = "github:sergiocorreia/reghdfe"    # From GitHub

[packages.dev]
assert = "ssc"

[packages.test]
mytest = "ssc"

Sources:

  • "ssc" - Install from SSC
  • "github:user/repo" - Install from GitHub (default branch)
  • "github:user/repo@tag" - Install from GitHub at specific tag/branch

[scripts]

Task definitions for stacy task. Supports three formats:

[scripts]
# Simple: a task is a script path
clean = "src/01_clean.do"
analyze = "src/02_analyze.do"
tables = "src/03_tables.do"

# Sequential: an array runs tasks (or script paths) in order
build = ["clean", "analyze", "src/03_tables.do"]

# Parallel: run tasks (or script paths) concurrently
outputs = { parallel = ["analyze", "tables"] }

Array entries and parallel lists may name other tasks or point directly at script paths. The object form also supports script, args, and description keys:

analyze = { script = "src/02_analyze.do", description = "Main estimates" }

Important Notes

Unknown Keys Are Rejected

Task names under [scripts] are yours to pick. Every other key must be one stacy knows — including the keys inside a package table (source, version) and a task table (script, args, parallel, description). A key it does not know is an error, not a shrug:

$ stacy lock
Error: Failed to parse stacy.toml: TOML parse error at line 4, column 1
  |
4 | [dependencies]
  | ^^^^^^^^^^^^^^
unknown field `dependencies`, expected one of `project`, `run`, `paths`, `packages`, `scripts`
hint: declare these under [packages.dependencies]

Dependencies declared under the wrong key used to be dropped without a word, and stacy lock then reported success on zero packages. The same went for a typo inside a package table: { source = "ssc", verison = "1.0.0" } parsed, lost the version pin, and resolved the latest release instead.

Stata Binary

stacy auto-detects Stata in common locations. If detection fails, configure manually:

# Environment variable (recommended)
export STATA_BINARY=/path/to/stata-mp

# Or per-command
stacy run --engine /path/to/stata-mp script.do

# Or user config file (see User Config docs)
stata_binary = "/path/to/stata-mp"

Run stacy doctor to verify detection.

All Fields are Optional

An empty stacy.toml is valid:

# This file can be empty - all fields have defaults

Paths are Relative

Paths in stacy.toml are relative to the project root (e.g., script paths in [scripts]).

Global Package Cache

Packages are installed to a global cache at ~/.cache/stacy/packages/ and shared across all projects. Use stacy cache packages list to view cached packages.

Examples

Minimal

[project]
name = "analysis"

With Packages

[project]
name = "analysis"

[packages.dependencies]
estout = "ssc"
reghdfe = "github:sergiocorreia/reghdfe"

With Local Ado Paths

[project]
name = "analysis"

[paths]
ado = ["ado"]

[packages.dependencies]
estout = "ssc"

With Tasks

[project]
name = "analysis"

[packages.dependencies]
estout = "ssc"

[scripts]
clean = "src/01_clean.do"
build = "src/02_build.do"
report = "src/03_report.do"
all = ["clean", "build", "report"]

CI-Friendly

[project]
name = "analysis"

[run]
show_progress = false  # Cleaner CI logs

Validation

stacy validates the config on load. Invalid TOML causes an error:

Error: Failed to parse stacy.toml: expected `=` at position 15-16

Use stacy env to verify your configuration is loaded correctly.

See Also

User Config (~/.config/stacy/config.toml)

Machine-specific settings that should not be committed to version control.

This is separate from project config (stacy.toml), which lives in the project directory and is shared with collaborators.

Location

PlatformPath
macOS / Linux~/.config/stacy/config.toml
Windows%APPDATA%\stacy\config.toml

Created automatically by stacy init if it doesn’t exist, or create it manually.

Full Reference

# Stata binary path (overrides auto-detection)
stata_binary = "/Applications/StataNow/StataMP.app/Contents/MacOS/stata-mp"

# Check for updates on startup (default: true)
# update_check = false

Fields

stata_binary

Override Stata auto-detection with an explicit path.

# macOS
stata_binary = "/Applications/StataNow/StataMP.app/Contents/MacOS/stata-mp"

# Linux
stata_binary = "/usr/local/stata18/stata-mp"

# Windows
stata_binary = "C:\\Program Files\\Stata18\\StataMP-64.exe"

stacy validates the path on load. If the file doesn’t exist, you’ll get an error with a hint to fix it.

Precedence for Stata binary resolution (highest first):

  1. --engine CLI flag
  2. STATA_BINARY environment variable
  3. stata_binary in user config
  4. Auto-detection from common install paths

update_check

Controls whether stacy checks for new releases on startup. Enabled by default.

# Disable update notifications
update_check = false

When enabled, stacy:

  1. Reads a local cache (~/.cache/stacy/version-check.json) on startup
  2. Prints a notification to stderr if a newer version is available
  3. Refreshes the cache in the background (every 24 hours)

The check never blocks or slows down commands. The background refresh uses the GitHub Releases API with a 3-second timeout.

Environment Variables

These environment variables affect stacy behavior independently of the config file:

VariableEffect
STATA_BINARYStata binary path (overrides config file)
STACY_NO_UPDATE_CHECKSuppress update notifications (set to any value)
CISuppresses update notifications automatically
GITHUB_ACTIONSSuppresses update notifications automatically

Update Notification Suppression

Update notifications are automatically suppressed when:

  • update_check = false in user config
  • STACY_NO_UPDATE_CHECK environment variable is set
  • CI or GITHUB_ACTIONS environment variable is set
  • stderr is not a terminal (piped output, cron jobs, etc.)

The notification looks like:

Update available: v1.1.0 → v1.2.0
Run `brew upgrade stacy` to update

The upgrade instruction adapts to your install method (Homebrew, Cargo, or manual download).

Cache Directory

stacy stores cached data at:

PlatformPath
macOS / Linux~/.cache/stacy/
Windows%LOCALAPPDATA%\stacy\cache\

Contents:

FilePurpose
packages/Global package cache (shared across projects)
version-check.jsonLast update check result
update-availableFlag file for Stata-side notifications

To clean everything: rm -rf ~/.cache/stacy (packages will be re-downloaded on next stacy install).

Examples

Minimal (just Stata path)

stata_binary = "/usr/local/stata18/stata-mp"

CI / headless server

stata_binary = "/usr/local/stata18/stata-mp"
update_check = false

Default (auto-detect everything)

An empty file or no file at all is valid. stacy auto-detects Stata and enables update checks.

See Also

Commands Overview

stacy provides commands for Stata execution, package management, and project workflows.

By Category

Execution

Packages

Project

Utility

Getting Help

stacy --help          # General help
stacy run --help      # Command-specific help

See Exit Codes for exit code reference.

stacy run

Execute a Stata script with error detection

Synopsis

stacy run [SCRIPT] [OPTIONS]

Description

Executes Stata scripts in batch mode and parses log files for errors. Unlike stata-mp -b, returns proper exit codes that reflect whether the script succeeded or failed—enabling integration with Make, Snakemake, and CI/CD.

The command runs Stata with -b -q, parses the log for error patterns, and returns an appropriate exit code (0 for success, 1-10 for various errors).

Program output (boilerplate-stripped) streams to stdout live as Stata writes it — like Rscript or python — so stacy run foo.do > out.log and pipes behave as expected. stacy’s own status and error messages go to stderr. On failure, error details with official Stata documentation links and the log file path are displayed. Use -v to stream the raw log instead, or -q to suppress all output.

The batch log file is internal: removed on success, kept on failure with its path printed in the failure output. Inside a project, kept logs go to [run] log_dir from stacy.toml (logs/ by default); outside one they stay next to the run. The same rule applies to the scripts run by stacy task, stacy test and stacy bench, and to every output format — --format json and --format stata report an empty log_file for a run that succeeded, because there is no log to point at. Use --log <path> to keep the raw Stata log as a durable artifact — it wins over log_dir and is written whether the run passed or failed (--quiet --log out.log for a silent file-only run).

Multiple scripts can be run sequentially (default, fail-fast) or in parallel (--parallel). Parallel mode runs all scripts regardless of failures.

To check a quick result without a script file, use stacy run -c 'display ...'.

In a project with a stacy.lock, run builds the ado-path from the lockfile and checks it against the package cache before starting Stata. A cached package that no longer hashes to the checksum the lockfile records fails the run instead of executing, as does a production package that is not installed at all. dev and test packages are only checked if they are installed, since stacy install installs the production group by default. --no-verify skips the check.

Arguments

ArgumentDescription
<SCRIPT>Script to execute

Options

OptionDescription
--allow-globalAllow globally installed packages
--cacheEnable build cache (skip re-execution if script/deps unchanged)
--cache-onlyFail if not in cache (useful for CI)
--cdChange to script’s parent directory
-c, --codeInline Stata code
-C, --directoryRun Stata in this directory
--engineStata engine to use (overrides config and auto-detection)
--forceForce rebuild even if cached
-j, --jobsMax parallel jobs (default: CPU count)
--logWrite the raw Stata log to this path
--no-verifySkip the check of the package cache against stacy.lock
-P, --parallelRun scripts in parallel
--profileInclude execution metrics
-q, --quietSuppress output
--timeoutKill script if it exceeds this many seconds
--traceEnable execution tracing at given depth
--verboseExtra output

Examples

Run a script

stacy run analysis.do

Multiple scripts (sequential)

Runs in order, stops on first failure

stacy run clean.do analyze.do report.do

Parallel execution

Run all scripts concurrently for faster execution

stacy run --parallel *.do
stacy run --parallel -j4 a.do b.do c.do

Inline code

Execute Stata code without creating a file

stacy run -c 'display 2+2'
stacy run -c 'sysuse auto, clear
summarize price'

Working directory

Run in a specific directory (script paths resolved before cd)

stacy run -C reports/pilot/ table.do
stacy run --cd reports/pilot/table.do

Verbose output

Stream log file in real-time

stacy run -v long_analysis.do

JSON output

Machine-readable output for CI/CD

stacy run --format json analysis.do

Execution tracing

Enable Stata’s set trace on for debugging

stacy run --trace 2 analysis.do
stacy run --trace 2 -v analysis.do

Timeout

Kill script if it takes longer than 60 seconds

stacy run --timeout 60 long_analysis.do

Exit Codes

CodeMeaning
0Success
1Stata error (r() code detected)
2Syntax error
3File error (not found, permission denied)
4Memory error
5Internal stacy error
6Statistical error (convergence, model problems)
10Environment error (Stata not found)

See Exit Codes Reference for details.

See Also

stacy bench

Benchmark script execution

Synopsis

stacy bench <SCRIPT> [OPTIONS]

Description

Runs a Stata script multiple times and reports timing statistics (mean, median, min, max, stddev). Includes warmup runs by default to account for JIT and caching effects.

Arguments

ArgumentDescription
<SCRIPT>Stata script to benchmark (required)

Options

OptionDescription
--no-warmupSkip warmup runs
-q, --quietSuppress progress output
-n, --runsNumber of measured runs
-w, --warmupNumber of warmup runs

Examples

Benchmark a script

stacy bench analysis.do

Custom run count

stacy bench -n 20 analysis.do

Exit Codes

CodeMeaning
0Success
1Script failed during benchmark
3Script not found

See Exit Codes Reference for details.

See Also

stacy init

Initialize new stacy project

Synopsis

stacy init <PATH> [OPTIONS]

Description

Creates a new stacy project with standard directory structure and configuration. This sets up stacy.toml for project settings and ado/ for local packages.

Run this in an existing directory or specify a path to create a new one.

Arguments

ArgumentDescription
<PATH>Project directory (default: current)

Options

OptionDescription
--forceOverwrite existing files
-i, --interactiveInteractive mode: prompt for project details and packages

Examples

Initialize in current directory

stacy init

Initialize in new directory

stacy init my-project

Exit Codes

CodeMeaning
0Project created successfully
1Initialization failed

See Exit Codes Reference for details.

See Also

stacy add

Add packages to project

Synopsis

stacy add <PACKAGES> [OPTIONS]

Description

Adds packages to your project’s stacy.toml and installs them. Supports SSC (default) and GitHub sources. Packages are recorded with versions for reproducible installs via stacy install.

Arguments

ArgumentDescription
<PACKAGES>Package names to add (required)

Options

OptionDescription
--devAdd as development dependency
--sourcePackage source: ssc or github:user/repo[@ref]
--testAdd as test dependency

Examples

Add from SSC

stacy add estout
stacy add estout reghdfe

Add from GitHub

stacy add --source github:sergiocorreia/ftools ftools

Add as dev dependency

stacy add --dev assert

Exit Codes

CodeMeaning
0Success
1A package failed to add

See Exit Codes Reference for details.

See Also

stacy remove

Remove packages from project

Synopsis

stacy remove <PACKAGES> 

Description

Removes packages from stacy.toml and deletes them from the local ado/ directory. Does not affect globally installed packages.

Arguments

ArgumentDescription
<PACKAGES>Package names to remove (required)

Examples

Remove a package

stacy remove estout

Remove multiple packages

stacy remove estout reghdfe

Exit Codes

CodeMeaning
0Success
1No packages removed

See Exit Codes Reference for details.

See Also

stacy update

Update packages to latest versions

Synopsis

stacy update <PACKAGES> [OPTIONS]

Description

Checks for newer versions of installed packages and updates them. Updates both stacy.toml and stacy.lock to reflect new versions. Use --dry-run to preview changes without applying them.

A local: package lives in the project, so there is no source to check for a newer version. It is reported as skipped and does not fail the command.

Arguments

ArgumentDescription
<PACKAGES>Package names to update (default: all)

Options

OptionDescription
--dry-runShow what would be updated without making changes

Examples

Update all packages

stacy update

Update specific package

stacy update estout

Preview updates

stacy update --dry-run

Exit Codes

CodeMeaning
0Success
1A package failed to update, or its latest version could not be checked

See Exit Codes Reference for details.

See Also

stacy install

Install packages from lockfile or SSC/GitHub

Synopsis

stacy install [OPTIONS]

Description

Installs the packages stacy.lock pins, at the versions and checksums it records.

install reads the lockfile; it never writes it. If a source no longer serves the pinned version, or serves different bytes under it, the install fails and stacy.lock is left untouched. Use stacy update to move a pin.

SSC serves only the current revision of a package, so a pinned version that has left the package cache cannot be downloaded again. A cold-cache install of a superseded pin fails rather than installing a different version under it.

The version pin is checked where the package names its own version. A .pkg manifest with no Distribution-Date line names none, so for those packages the checksum alone decides whether the pin is satisfied.

Options

OptionDescription
--frozenFail if lockfile doesn’t match stacy.toml
--no-verifySkip checksum verification (a version the source names is still checked)
--withInclude dependency groups (comma-separated: dev, test)

Examples

Install from lockfile

Install all packages at locked versions

stacy install

Install specific package

stacy install estout

Exit Codes

CodeMeaning
0Success
1A package failed to install or failed checksum verification

See Exit Codes Reference for details.

See Also

stacy list

List installed packages

Synopsis

stacy list [OPTIONS]

Description

Shows all packages installed in the current project with their versions and sources. Use --tree to group by dependency type (production, dev, test).

Options

OptionDescription
--treeGroup packages by dependency type

Examples

List packages

stacy list

List by dependency group

stacy list --tree

Exit Codes

CodeMeaning
0Success

See Exit Codes Reference for details.

See Also

stacy outdated

Check for package updates

Synopsis

stacy outdated 

Description

Compares installed package versions against the latest available from their sources. Shows which packages have updates available without modifying anything.

Examples

Check for updates

stacy outdated

Exit Codes

CodeMeaning
0Success
1A package’s latest version could not be checked

See Exit Codes Reference for details.

See Also

stacy lock

Generate or verify lockfile

Synopsis

stacy lock [OPTIONS]

Description

Generates stacy.lock from stacy.toml, recording exact versions of all packages. The lockfile ensures reproducible installs across machines. Use --check in CI to verify the lockfile is up-to-date.

Options

OptionDescription
--checkVerify lockfile matches stacy.toml without updating
--refreshRecompute checksums from the packages installed in the global cache

Examples

Generate lockfile

stacy lock

Verify lockfile (for CI)

stacy lock --check

Exit Codes

CodeMeaning
0Success / in sync
1A package could not be resolved, or the lockfile is out of sync (with –check)

See Exit Codes Reference for details.

See Also

stacy deps

Show dependency tree for Stata scripts

Synopsis

stacy deps <SCRIPT> [OPTIONS]

Description

Analyzes a Stata script to find all files it depends on (via do, run, include) and package dependencies (via require). Shows a tree view of the dependency graph, detects circular dependencies, and identifies missing files.

require statements (including cap require and capture require) are recognized as package dependencies and shown as leaf nodes in the tree.

A path that holds a Stata macro, such as do "$root/prep.do", only points somewhere once Stata expands the macro. stacy reads the script but does not run it, so it lists the path as written and marks it as resolved at run time. Such a path is not a missing file and does not fail the command.

Arguments

ArgumentDescription
<SCRIPT>Script to analyze (required)

Options

OptionDescription
--flatShow flat list instead of tree

Examples

Show dependency tree

stacy deps main.do

Show flat list

stacy deps --flat main.do

Exit Codes

CodeMeaning
0Analysis complete
1Circular dependencies detected
3Script not found, or a dependency is missing

See Exit Codes Reference for details.

See Also

stacy task

Run tasks from stacy.toml

Synopsis

stacy task <TASK> [OPTIONS]

Description

Runs named tasks defined in stacy.toml. Tasks are like npm scripts—define sequences of commands once and run them by name. Use --list to see available tasks.

Arguments

ArgumentDescription
<TASK>Task name to run

Options

OptionDescription
--frozenFail if lockfile doesn’t match stacy.toml
--listList available tasks

Examples

Run a task

stacy task build

List available tasks

stacy task --list

Exit Codes

CodeMeaning
0Success
1Task failed
5Task not found

See Exit Codes Reference for details.

See Also

stacy test

Run tests

Synopsis

stacy test <TEST> [OPTIONS]

Description

Discovers and runs test scripts from the tests/ or test/ directory. Tests are Stata scripts that use assertion commands. Supports filtering, parallel execution, and verbose output for debugging failures.

Each test runs with the project root as the working directory, so relative paths in tests resolve from the project root regardless of where stacy test is invoked. Use --directory <dir> to run tests in a specific directory, or --cd to run each test in its own parent directory.

Arguments

ArgumentDescription
<TEST>Specific test to run

Options

OptionDescription
--cdRun each test in its own parent directory
-C, --directoryRun tests in this directory
-f, --filterFilter tests by pattern
--listList tests without running
--parallelRun tests in parallel
-q, --quietSuppress progress output
-V, --verboseShow full log context for failures

Examples

Run all tests

stacy test

Run specific test

stacy test test_regression

Filter tests

stacy test -f 'regression*'

Run each test in its own directory

stacy test --cd

Exit Codes

CodeMeaning
0All tests passed
1One or more tests failed
5Test not found

See Exit Codes Reference for details.

See Also

stacy cache info

Show cache statistics

Synopsis

stacy cache info 

Description

Displays information about the build cache used by stacy run --cache. Shows number of cached entries and approximate size. The cache stores results to skip re-execution of unchanged scripts.

Use stacy cache clean to remove old entries.

Examples

Show cache info

stacy cache info

Clean old entries

stacy cache clean
stacy cache clean --older-than 7

Exit Codes

CodeMeaning
0Success
10Not in project

See Exit Codes Reference for details.

See Also

stacy env

Show environment configuration

Synopsis

stacy env 

Description

Displays the current stacy configuration: Stata binary location, project root, path settings, and adopath order. Useful for debugging configuration issues.

Examples

Show environment

stacy env

Exit Codes

CodeMeaning
0Success
10Environment error (Stata not found)

See Exit Codes Reference for details.

See Also

stacy doctor

Run system diagnostics

Synopsis

stacy doctor [OPTIONS]

Description

Checks your system configuration and reports any issues. Verifies Stata installation, project detection, and write permissions. Run this first when troubleshooting.

Options

OptionDescription
--refreshRe-extract error codes from Stata

Examples

Run diagnostics

stacy doctor

Exit Codes

CodeMeaning
0All checks passed
1One or more checks failed

See Exit Codes Reference for details.

See Also

stacy explain

Look up Stata error code details

Synopsis

stacy explain <CODE> 

Description

Displays detailed information about Stata error codes. Includes the error name, category, full description from the Stata Programming Manual, and link to official documentation. Useful for understanding r() return codes.

Arguments

ArgumentDescription
<CODE>Error code (e.g., 199 or r(199)) (required)

Examples

Look up error code

stacy explain 199

Using r() syntax

stacy explain r(601)

Exit Codes

CodeMeaning
0Error code found
1Unknown error code

See Exit Codes Reference for details.

See Also

How It Works

What actually happens when stacy runs a script or installs a package. stacy has four moving parts: an execution engine, an error detector, package management, and a build cache. This page walks through each, then covers the machine interface and stacy’s boundaries.

Contents


Script Execution

stacy run script.do does four things:

┌───────────┐     ┌───────────┐     ┌─────────┐     ┌──────────┐
│ Build     │ ──▶ │ Stata     │ ──▶ │ Log     │ ──▶ │ Exit     │
│ S_ADO     │     │ -b -q     │     │ Parser  │     │ Code 0-10│
└───────────┘     └───────────┘     └─────────┘     └──────────┘
 from lockfile     fresh process     from the end    translated
  1. Build the environment. If a lockfile is present, stacy constructs the S_ADO search path from it, so Stata sees exactly the locked packages (see Package Isolation).
  2. Run Stata. The script runs in a fresh batch-mode process (-b -q). The -q flag skips your profile.do, so execution doesn’t depend on machine-specific startup configuration.
  3. Parse the log. stacy reads the log Stata produced and determines whether the script succeeded (see Error Detection).
  4. Translate the outcome. Stata error codes become standard shell exit codes that any build tool understands.

Extras that matter in practice:

  • --timeout <seconds> kills a hung script (SIGTERM, then SIGKILL after a grace period) – useful for convergence loops on shared clusters.
  • --parallel runs multiple scripts concurrently, each in its own Stata process; output prints as a grouped block per script on completion, and internal logs are uniquely named, so make -j and Snakemake can run same-named scripts safely.
  • -c 'display ...' runs inline code without a script file.

Error Detection

The Problem

Stata’s batch mode always exits with code 0, even when scripts fail. Errors are only visible in log files.

stacy’s Solution

stacy parses the log from the end. It locates the last end of do-file marker – which corresponds to the outermost do-file in nested execution – and scans the lines after it for a return-code pattern (r(N);). Found: the script failed with that code. Not found: it succeeded.

This design handles the edge cases correctly:

ScenarioBehavior
Uncaptured error, e.g. r(601)r(N); appears after the final marker – failure
captured errorDoesn’t propagate past end of do-file – success
Error in a nested do-filePropagates to the outermost marker – failure
Script prints "r(199);"Appears before the marker – ignored
Stata killed / crashedNo final marker at all – reported as error, never as success

The error-detection logic is exercised by a test suite of 250+ cases covering nested do-files, captured errors, false positives from display output, and incomplete logs.

Error Descriptions

To describe an error rather than just number it, stacy extracts Stata’s own error descriptions from your installation at first run (stacy doctor --refresh re-extracts after a Stata upgrade). Where no description is available, it falls back to the documented range categories – see Exit Codes for the mapping.

Failures print a human-readable description plus a link to the official manual page, so you can diagnose a remote job from the error output alone:

FAIL  broken.do  (0.8s)

   Error: r(199) - unrecognized command

   See: https://www.stata.com/manuals/perror.pdf#r199

Package Isolation

The Problem

Stata packages install globally to ~/ado/plus/. Every project shares the same versions. When SSC updates a package, all projects change silently.

stacy’s Solution

stacy uses a global cache with per-project isolation:

~/.cache/stacy/packages/
├── estout/
│   ├── 2024.01.15/
│   │   └── estout.ado
│   └── 2024.03.15/
│       └── estout.ado
└── reghdfe/
    └── 6.12.3/
        └── reghdfe.ado

Multiple versions coexist in the cache, projects share it (disk-efficient), and cached packages install offline.

Runtime Isolation

When you run stacy run script.do, stacy reads stacy.lock, builds an S_ADO search path pointing at the exact cached versions, and launches Stata with it. Each project’s path is built from its own lockfile:

Project A (stacy.lock):          Project B (stacy.lock):
  estout = 2024.01.15            estout = 2024.03.15
  reghdfe = 6.12.3               reghdfe = 6.12.3

Both use the same cache, but see different versions.

Two modes:

  • Strict (default): only locked packages and Stata’s built-ins (BASE) are visible. Nothing leaks in from your global PLUS or PERSONAL directories, so “works because of something installed on my machine” cannot happen.
  • Allow-global (--allow-global): locked packages take precedence, but globally installed packages remain available. Useful during development or incremental migration.

Project-local .ado directories can be added to the path via the [paths] config section.

Lockfile Verification

The lockfile includes SHA256 checksums:

[packages.estout]
version = "2024.03.15"
checksum = "sha256:14af94e03edd..."

On stacy install, checksums are verified to ensure downloaded files match expected content, cached packages haven’t been modified, and SSC hasn’t silently updated the package. See Lockfile Format.


Build Cache

Pipelines often re-run scripts that haven’t changed. stacy run --cache skips that work:

  1. stacy hashes the script and every do-file it depends on (do, run, and include statements, traced recursively – the same parser behind stacy deps).
  2. If nothing changed since the last successful run, stacy replays the previous result (exit code, log path, duration) without launching Stata.

The cache is project-local (.stacy/cache/build.json) and opt-in. --force re-runs regardless; --cache-only fails when no cached result exists, letting CI require a pre-populated cache. Files outside the do-file graph – datasets, environment variables – are not tracked; use --force when they change.


Output Streaming

Real-time Output

Program output streams to stdout live by default – boilerplate-stripped (command echoes removed, blank runs collapsed), both in a terminal and when piped. Removed are the . command prompt, its > continuations, and the body lines of loops, programs and input. Results are kept as Stata printed them, including the ones that are shaped like echoes: list rows ( 1. | ... |), the . row of tabulate, missing, a value label that begins with . , and output that wraps onto a > line. A . prompt only counts as an echo where a command can start – never in the middle of a command’s output. Use -v (verbose) to stream the raw, unstripped log instead:

stacy run -v long_analysis.do

Streaming stops when the Stata process exits, so killed or timed-out runs terminate cleanly, and closed pipes (stacy run foo.do | head) end the stream without error.

Log Files

The batch log is internal: it gets a unique name per invocation (so concurrent runs never collide), is removed on success, and is kept on failure — with its path printed in the failure output so you can inspect it. --log <path> writes the raw log to a chosen location regardless of outcome. Machine-readable formats keep the log and report its path.

Progress Reporting

Without verbose mode, stacy shows periodic progress:

⠋ Running: analysis.do (45s elapsed)

Configure the interval in stacy.toml:

[run]
progress_interval_seconds = 30

Structured Logging

For automated pipelines, use --format json. Machine-readable formats imply quiet execution (no streaming). The batch log follows the same rule as in human mode — removed on success, kept on failure — so log_file names the kept log of a failed run and is empty for one that passed. Add --log <path> to keep the raw log either way:

stacy run --format json analysis.do
stacy run --format json --log run.log analysis.do

Machine Interface

stacy is designed to be a good Unix citizen: standard exit codes, machine-readable output, and no interactive surprises (update checks and colors are suppressed automatically in CI and piped output).

JSON Output

Every command supports --format json:

stacy run --format json analysis.do
stacy install --format json
stacy doctor --format json

See JSON Output for complete schemas.

Exit Codes

Stable, semantic exit codes for scripting:

CodeMeaning
0Success
1Stata error
2Syntax error
3File error
4Memory error
5Internal error
6Statistical error
10Environment error

See Exit Codes for mapping details.

Build System Integration

stacy’s exit codes work with any tool that respects Unix conventions:

Make:

results.dta: analysis.do
	stacy run analysis.do  # Stops on non-zero

Shell scripts:

stacy run analysis.do || exit 1

CI pipelines:

- run: stacy run analysis.do  # Fails job on error

Programmatic Usage

Python:

import subprocess, json

result = subprocess.run(
    ['stacy', 'run', '--format', 'json', 'analysis.do'],
    capture_output=True
)
data = json.loads(result.stdout)
if not data['success']:
    print(f"Failed: {data['errors']}")

R:

result <- system2("stacy", c("run", "--format", "json", "analysis.do"),
                  stdout = TRUE)
data <- jsonlite::fromJSON(paste(result, collapse = "\n"))

What stacy Does Not Do

Knowing the boundaries is as useful as knowing the features:

  • It is not a build system. stacy decides whether a Stata step succeeded; Make, Snakemake, or statacons decide which steps run and in what order. They compose: point your build tool’s Stata rule at stacy run. See Build Integration.
  • It does not manage the Stata version, data files, or other languages. The lockfile pins Stata packages. For full-stack reproducibility (OS, Stata itself, Python/R), use Docker – stacy works the same inside a container.
  • It does not resolve transitive dependencies. SSC packages declare dependencies inconsistently, as free text, so automatic resolution would guess. If package A needs package B, add both: stacy add A B. stacy doctor and post-install scanning warn about likely missing dependencies.
  • It does not replace interactive Stata. stacy wraps batch execution. For exploratory work, use Stata as usual – and run the finished script through stacy run to verify it stands on its own.

See Also

Lockfile (stacy.lock)

Records installed package versions for reproducible environments. Auto-generated by stacy lock and stacy install.

Purpose

  • Reproducibility: Ensures identical packages across machines and over time
  • Verification: SHA256 checksums detect corruption or tampering
  • Documentation: Records exact sources for each package
  • Collaboration: Teammates get the same versions you tested with

Format Specification

The lockfile uses TOML format with a defined schema:

# Auto-generated by stacy. Do not edit manually.
version = "1"                    # Lockfile format version

[packages.<name>]                # One section per package
version = "<version>"            # Version string (date or semver)
checksum = "sha256:<hash>"       # SHA256 of package contents

[packages.<name>.source]         # Where the package came from
type = "SSC" | "GitHub"          # Source type
name = "<name>"                  # Package name (SSC only)
repo = "<owner>/<repo>"          # Repository (GitHub only)
tag = "<ref>"                    # Git ref (GitHub only)

Annotated Example

# Auto-generated by stacy. Do not edit manually.
# Lockfile format version - stacy checks compatibility
version = "1"

# ─────────────────────────────────────────────────────────────
# SSC Package
# ─────────────────────────────────────────────────────────────
[packages.estout]
# Version comes from SSC metadata (typically a date)
version = "2024.03.15"
# SHA256 hash of all .ado and .sthlp files concatenated
checksum = "sha256:14af94e03edd2e5f12021a8967afe1eee2dc7ebd..."

[packages.estout.source]
type = "SSC"
name = "estout"

# ─────────────────────────────────────────────────────────────
# GitHub Package
# ─────────────────────────────────────────────────────────────
[packages.reghdfe]
# Version from git tag or commit
version = "6.12.3"
checksum = "sha256:8f9234ab12cd56ef78901234567890abcdef..."

[packages.reghdfe.source]
type = "GitHub"
repo = "sergiocorreia/reghdfe"
# Tag, branch, or commit SHA
tag = "v6.12.3"

What the lockfile guarantees

The lockfile is an input to stacy install and stacy run, never an output of them:

  • stacy install installs what the lockfile pins. It does not re-resolve versions and it does not write stacy.lock. If the source no longer serves the pinned version, or serves different bytes under it, the install fails and the lockfile is left untouched. This holds with and without --frozen.
  • stacy run checks the cache against the lockfile before it starts Stata. If a cached package no longer hashes to the locked checksum, or a production package is not installed at all, the run fails instead of executing.
  • Only stacy add, stacy update, and stacy lock write stacy.lock. Moving a pin is an explicit act.

Which packages run requires

stacy install installs the production group by default, so that is the group run requires to be present: a locked production package that is not in the cache fails the run. dev and test packages are installed on request (stacy install --with dev,test), so run does not require them — but it does check them against their locked checksums when they are installed, since every locked package is on the ado-path.

A pinned version can become unfetchable

SSC serves only the current revision of a package. Once a pinned version leaves your package cache, it cannot be downloaded again. A cold-cache install of a superseded pin therefore fails:

estout: stacy.lock pins version 20240315, but SSC serves 20260413
  SSC serves only the current revision of a package, so once a pinned version
  leaves the package cache it cannot be downloaded again.
  hint: run `stacy update estout` to move the pin to 20260413 (your results may
        change), or restore 20240315 into the package cache from a machine that
        still has it.

This is a real limit of SSC, not something stacy can work around. The choice is to fail loudly or to run a different package than the one you locked; stacy fails.

The version pin is only enforced where the package names its own version. A .pkg manifest without a Distribution-Date line names none — stacy add records the date it fetched the package, which says nothing about the contents — so for those packages the checksum decides whether the pin is satisfied. A cold-cache install of such a package succeeds as long as the bytes still hash to the locked checksum, whatever the date in the lockfile says.

How Checksums Work

Checksums verify that the installed package matches exactly what was recorded:

  1. On install: stacy downloads the package, computes SHA256 of the contents
  2. On lock: Computed hash is stored in stacy.lock
  3. On verify: Cached package is re-hashed and compared to lockfile

The checksum covers all .ado and .sthlp files in the package, sorted and concatenated. This catches:

  • Corrupted downloads
  • SSC updates that changed the package
  • Manual modifications to cached files

Checksums are checked by stacy install and again by stacy run before every run. Verification on run is on by default: it reads and hashes the locked packages, which costs milliseconds against a Stata startup measured in seconds, and a default that silently runs modified code would not be a reproducibility guarantee.

--no-verify turns checksum verification off. It applies to both commands, and it has to: stacy install --no-verify caches whatever the source served, which by definition does not match the locked checksum, so stacy run on that cache needs --no-verify too. Prefer stacy update <package> to re-lock, and expect your results to change.

Fields Reference

FieldRequiredDescription
versionYesLockfile format version (currently “1”)
packages.<name>.versionYesPackage version string
packages.<name>.checksumYesSHA256 hash prefixed with sha256:
packages.<name>.source.typeYes"SSC" or "GitHub"
packages.<name>.source.nameSSC onlyPackage name on SSC
packages.<name>.source.repoGitHub onlyowner/repo format
packages.<name>.source.tagGitHub onlyGit ref (tag, branch, or commit)

Workflow

Creating a lockfile

# Add packages (creates/updates lockfile automatically)
stacy add estout reghdfe

# Or generate lockfile from existing stacy.toml
stacy lock

Installing from a lockfile

# Clone a project
git clone https://github.com/user/project
cd project

# Install exact versions from lockfile
stacy install

Verifying in CI

# Fails if lockfile doesn't match stacy.toml
stacy lock --check

Updating packages

# Update one package to latest
stacy update reghdfe

# Update all packages
stacy update

Version Control

FileCommit?Why
stacy.tomlYesDeclares dependencies
stacy.lockYesEnsures reproducibility
~/.cache/stacy/packages/NoCache, not source

Always commit both stacy.toml and stacy.lock. The lockfile is what ensures everyone gets the same package versions.

Troubleshooting

“Lockfile out of sync”

The lockfile doesn’t match stacy.toml:

stacy lock  # Regenerate

“Checksum mismatch”

The cached package differs from what’s in the lockfile:

stacy cache packages clean  # Clear cache
stacy install               # Re-download

If the re-download also mismatches, the source changed the package without changing its version. Run stacy update <package> to re-lock it, and expect your results to change.

“The package cache does not match stacy.lock”

stacy run reports this when a locked production package is missing from the cache, or when any locked package has been modified since it was installed:

stacy install                    # Install the locked packages
stacy cache packages clean       # ...or clear a modified cache first

A cached package that no longer hashes to its locked checksum is reported as modified whatever group it is in, since every locked package is on the ado-path.

Merge conflicts in lockfile

After a git merge with conflicts:

# Resolve stacy.toml conflicts first, then:
stacy lock  # Regenerate lockfile

See Also

Exit Codes

stacy uses consistent exit codes to indicate success or failure type.

Exit Code Table

CodeNameDescription
0SuccessOperation completed successfully
1Stata ErrorStata r() code detected in log
2Syntax ErrorInvalid Stata syntax
3File ErrorFile not found, permission denied, data errors
4Memory ErrorInsufficient memory
5Internal Errorstacy itself failed (not Stata)
6Statistical ErrorConvergence failure, model problems
10Environment ErrorStata not found or configuration invalid

Stata r() Code Mapping

The number inside r(N) is preserved in stacy’s output (JSON field r_code, stored result r(exit_code) in Stata). The shell exit code is a category derived from it, in two steps:

  1. Error database lookup. stacy extracts error descriptions and categories from your local Stata installation (run stacy doctor --refresh after a Stata upgrade). If the code is found there, its category decides the exit code.
  2. Range fallback. Otherwise, the documented ranges from Stata’s Programming Reference Manual apply:
Exit CodeStata r() Codes
1all r() codes not in other categories
2r(100)-r(199), e.g. r(198), r(199)
3r(600)-r(699), e.g. r(601), r(603)
4r(900)-r(999), e.g. r(950)
6r(400)-r(499)
10r(800)-r(899)

Usage

Shell

stacy run analysis.do
echo $?  # 0 on success, 1-10 on failure

Makefile

results.dta: analysis.do
	stacy run analysis.do  # Stops on non-zero exit

This mapping is many-to-one by design: it compresses Stata’s hundreds of return codes into a small, stable set that build tools can branch on.

Stability

Exit codes 0-10 are stable and will not change meaning. New categories may be added with codes 11+.

See Also

JSON Output

stacy supports JSON output for machine-readable results.

Usage

Add --format json to any command:

stacy run --format json analysis.do
stacy install --format json
stacy env --format json

Output Schemas

stacy run

Success:

{
  "success": true,
  "script": "analysis.do",
  "duration_secs": 12.45,
  "exit_code": 0,
  "log_file": ""
}

Failure:

{
  "success": false,
  "script": "analysis.do",
  "duration_secs": 0.45,
  "exit_code": 2,
  "log_file": "/path/to/wd/analysis_12345_1715000000123_0.log",
  "errors": [
    {
      "type": "StataCode",
      "r_code": 199,
      "name": "unrecognized command",
      "line": 15,
      "context": "reghdfe price mpg, absorb(make)"
    }
  ]
}
FieldTypeDescription
successboolWhether script completed without errors
scriptstringPath to script that was run
duration_secsfloatExecution time in seconds
exit_codeintstacy exit code (0-10)
log_filestringAbsolute path to the kept Stata log, empty when the run succeeded (a successful run’s log is removed). Each invocation gets a unique stem (<script>_<pid>_<nanos>_<n>.log) so concurrent runs from a shared cwd never collide. Pass --log <path> to keep the log of a passing run; log_file then reports that path.
errorsarrayError details (only on failure)
errors[].typestringError type (StataCode, Syntax, File)
errors[].r_codeintStata r() code if applicable
errors[].namestringHuman-readable error name
errors[].lineintLine number if detected
errors[].contextstringCode that caused the error

stacy install

{
  "success": true,
  "installed": [
    {
      "name": "estout",
      "version": "2024.03.15",
      "source": "SSC"
    },
    {
      "name": "reghdfe",
      "version": "6.12.3",
      "source": "GitHub"
    }
  ],
  "already_cached": [
    {
      "name": "ftools",
      "version": "2.49.0",
      "source": "SSC"
    }
  ],
  "failed": []
}
FieldTypeDescription
successboolWhether all packages installed
installedarrayPackages downloaded this run
already_cachedarrayPackages found in cache
failedarrayPackages that failed to install

stacy list

{
  "packages": [
    {
      "name": "estout",
      "version": "2024.03.15",
      "source": "SSC",
      "locked": true
    },
    {
      "name": "reghdfe",
      "version": "6.12.3",
      "source": "GitHub",
      "locked": true
    }
  ]
}

stacy env

{
  "stata": {
    "binary": "/Applications/StataNow/StataMP.app/Contents/MacOS/stata-mp",
    "version": "18.0",
    "flavor": "MP",
    "source": "user config"
  },
  "project": {
    "root": "/Users/user/projects/analysis",
    "has_config": true,
    "has_lockfile": true
  },
  "cache": {
    "path": "/Users/user/.cache/stacy/packages",
    "package_count": 12
  }
}

stacy doctor

{
  "ready": true,
  "checks": [
    {
      "name": "Stata binary",
      "status": "ok",
      "message": "Found at /Applications/StataNow/StataMP.app/Contents/MacOS/stata-mp"
    },
    {
      "name": "Stata version",
      "status": "ok",
      "message": "Stata 18.0 MP"
    },
    {
      "name": "Project config",
      "status": "ok",
      "message": "Found stacy.toml"
    },
    {
      "name": "Lockfile",
      "status": "warning",
      "message": "No stacy.lock found"
    }
  ]
}
StatusMeaning
okCheck passed
warningNon-blocking issue
errorBlocking issue

stacy deps

{
  "status": "success",
  "script": "master.do",
  "dependencies": {
    "path": "master.do",
    "type": null,
    "exists": true,
    "is_circular": false,
    "is_unresolved": false,
    "line_number": null,
    "children": [
      {
        "path": "config/settings.do",
        "type": "do",
        "exists": true,
        "is_circular": false,
        "is_unresolved": false,
        "line_number": 3,
        "children": []
      },
      {
        "path": "reghdfe",
        "type": "require",
        "exists": true,
        "is_circular": false,
        "is_unresolved": false,
        "line_number": 5,
        "children": []
      }
    ]
  },
  "summary": {
    "unique_count": 2,
    "has_circular": false,
    "has_missing": false,
    "circular_paths": [],
    "missing_paths": [],
    "unresolved_paths": [],
    "circular_count": 0,
    "missing_count": 0,
    "unresolved_count": 0
  }
}

status is success when the graph resolved and error when a dependency is missing or circular — branch on it rather than on the summary counts.

is_unresolved marks a path that holds a Stata macro, such as do "$root/prep.do". stacy reads scripts but does not run them, so it cannot say where the path points. Such a path is listed but not looked up, and it does not fail the command.

jq Examples

Check if a run succeeded

stacy run --format json analysis.do | jq '.success'

Get exit code

stacy run --format json analysis.do | jq '.exit_code'

Extract error codes

stacy run --format json analysis.do | jq '.errors[]?.r_code'

List installed package names

stacy list --format json | jq -r '.packages[].name'

Get Stata binary path

stacy env --format json | jq -r '.stata.binary'

Check if project has lockfile

stacy env --format json | jq '.project.has_lockfile'

Find failed doctor checks

stacy doctor --format json | jq '.checks[] | select(.status == "error")'

Count dependencies

stacy deps --format json master.do | jq '.files | length'

Get packages that need downloading

stacy install --format json | jq '.installed[].name'

Using JSON in Scripts

Shell

#!/bin/bash
result=$(stacy run --format json analysis.do)
if echo "$result" | jq -e '.success' > /dev/null; then
    echo "Success!"
else
    echo "Failed with errors:"
    echo "$result" | jq -r '.errors[].name'
    exit 1
fi

Python

import subprocess
import json

result = subprocess.run(
    ['stacy', 'run', '--format', 'json', 'analysis.do'],
    capture_output=True,
    text=True
)
data = json.loads(result.stdout)

if data['success']:
    print(f"Completed in {data['duration_secs']:.2f}s")
else:
    for error in data.get('errors', []):
        print(f"Error r({error['r_code']}): {error['name']}")

R

library(jsonlite)

result <- system2("stacy", c("run", "--format", "json", "analysis.do"),
                  stdout = TRUE, stderr = TRUE)
data <- fromJSON(paste(result, collapse = "\n"))

if (data$success) {
  cat(sprintf("Completed in %.2fs\n", data$duration_secs))
} else {
  cat("Errors:\n")
  print(data$errors)
}

Stability

The JSON schema follows semantic versioning:

  • Core fields (success, exit_code, errors) are stable from v1.0
  • New fields may be added in minor versions (backward compatible)
  • Field removal or type changes only in major versions

Tip: Use jq’s -e flag to handle missing fields gracefully in scripts.

See Also

Build Integration

stacy integrates with build systems through standard Unix exit codes. Any tool that stops on non-zero exit works with stacy.

Quick Examples

Make:

results.dta: analysis.do data.dta
	stacy run analysis.do

Snakemake:

rule analysis:
    input: "analysis.do", "data.dta"
    output: "results.dta"
    shell: "stacy run {input[0]}"

Shell:

stacy run step1.do && stacy run step2.do

GNU Make

Basic Makefile

STATA := stacy run

# Final output depends on analysis
results/tables.tex: src/03_tables.do results/estimates.dta
	$(STATA) $<

# Estimates depend on clean data
results/estimates.dta: src/02_analysis.do data/clean.dta
	$(STATA) $<

# Clean data depends on raw data
data/clean.dta: src/01_clean.do data/raw.dta
	$(STATA) $<

.PHONY: all clean
all: results/tables.tex
clean:
	rm -f data/clean.dta results/*.dta results/*.tex

With Package Installation

.PHONY: install
install:
	stacy install

results.dta: analysis.do | install
	stacy run $<

See GNU Make documentation for more patterns.


Snakemake

Basic Snakefile

rule all:
    input: "results/tables.tex"

rule clean:
    input: "src/01_clean.do", "data/raw.dta"
    output: "data/clean.dta"
    shell: "stacy run {input[0]}"

rule analysis:
    input: "src/02_analysis.do", "data/clean.dta"
    output: "results/estimates.dta"
    shell: "stacy run {input[0]}"

rule tables:
    input: "src/03_tables.do", "results/estimates.dta"
    output: "results/tables.tex"
    shell: "stacy run {input[0]}"

Parallel Execution

snakemake --cores 4

See Snakemake documentation for workflows, clusters, and more.


CI/CD

GitHub Actions

# .github/workflows/analysis.yml
name: Analysis
on: [push, pull_request]

jobs:
  build:
    runs-on: self-hosted  # With Stata installed
    steps:
      - uses: actions/checkout@v4

      - name: Install stacy
        run: |
          curl -fsSL https://stacy.janfasnacht.com/install.sh | bash
          echo "$HOME/.local/bin" >> $GITHUB_PATH

      - name: Install packages
        run: stacy install --frozen

      - name: Run analysis
        run: stacy run analysis.do

      - name: Upload results
        uses: actions/upload-artifact@v4
        with:
          name: results
          path: output/

Note: --frozen fails if lockfile doesn’t match stacy.toml, catching uncommitted dependency changes.

GitLab CI

# .gitlab-ci.yml
analysis:
  stage: build
  before_script:
    - curl -fsSL https://stacy.janfasnacht.com/install.sh | bash
    - export PATH="$HOME/.local/bin:$PATH"
    - stacy install
  script:
    - stacy run analysis.do
  artifacts:
    paths: [output/]

Caching Packages

- uses: actions/cache@v4
  with:
    path: ~/.cache/stacy/packages/
    key: stata-packages-${{ hashFiles('stacy.lock') }}

Stata Licensing in CI

Stata requires a license. Options:

  1. Self-hosted runner with Stata installed
  2. Docker container with Stata
  3. Skip Stata steps in CI (validate config only)

See GitHub Actions docs or GitLab CI docs for more.


Best Practices

  1. Use --frozen in CI to catch lockfile drift
  2. Commit stacy.lock for reproducibility
  3. Cache packages to speed up builds
  4. Use JSON output for programmatic checks: stacy run --format json
  5. Upload artifacts on failure for debugging

See Also

Migration Guide

How to adopt stacy in existing Stata projects.

Overview

stacy works with existing Stata scripts unchanged. Migration is incremental–start with error detection, add package management when ready.

Current workflowstacy equivalent
stata -b do script.dostacy run script.do
ssc install pkgstacy add pkg
master.do[scripts] section

From Batch Mode to stacy run

Before

stata-mp -b do analysis.do
# Always exits 0, even on error
# Must manually check analysis.log

After

stacy run analysis.do
# Exits 1-10 on error
# Shows error with documentation link

What changes:

  • Exit codes now reflect success/failure
  • Errors display with Stata documentation links
  • Build systems (Make, Snakemake) can detect failures

What stays the same:

  • Your .do files work unchanged
  • Output goes to the same log file
  • Stata runs in the background

Updating scripts

For shell scripts that check logs:

# Before: parse log for errors
stata-mp -b do analysis.do
if grep -q "^r(" analysis.log; then
    echo "Error!"
    exit 1
fi

# After: just check exit code
stacy run analysis.do
if [ $? -ne 0 ]; then
    echo "Error!"
    exit 1
fi

# Or more simply
stacy run analysis.do || exit 1

From ssc install to Lockfiles

Before

* At the top of master.do or a setup script
ssc install estout
ssc install reghdfe

Problems:

  • Different versions on different machines
  • “It worked last month” failures
  • No record of what’s actually installed

After

# One-time setup
stacy init
stacy add estout reghdfe

# Creates stacy.toml (what you want) and stacy.lock (what you have)
git add stacy.toml stacy.lock
git commit -m "Add stacy package management"

For collaborators:

git pull
stacy install  # Gets exact same versions

Step-by-step migration

  1. List current packages

    ado dir
    
  2. Initialize stacy

    stacy init
    
  3. Add each package

    stacy add estout reghdfe ftools
    
  4. Remove ssc install lines from scripts Delete or comment out ssc install commands–stacy handles this now.

  5. Commit both files

    git add stacy.toml stacy.lock
    git commit -m "Switch to stacy package management"
    

Handling GitHub packages

If you install from GitHub:

* Before
net install reghdfe, from("https://raw.githubusercontent.com/sergiocorreia/reghdfe/master/src/")
# After
stacy add github:sergiocorreia/reghdfe

From master.do to [scripts]

Before

* master.do
do "01_clean_data.do"
do "02_analysis.do"
do "03_tables.do"

Problems:

  • Running one script requires editing master.do
  • No parallelization
  • Error in script 2 still runs script 3 (unless you add capture logic)

After

Add to stacy.toml:

[scripts]
clean = "01_clean_data.do"
analysis = "02_analysis.do"
tables = "03_tables.do"
all = ["clean", "analysis", "tables"]

Run individual tasks or sequences:

stacy task clean      # Run just cleaning
stacy task analysis   # Run just analysis
stacy task all        # Run all in order

Benefits:

  • Named tasks are self-documenting
  • Each task stops on error by default
  • Can run tasks individually for debugging

Keeping master.do

You don’t have to remove master.do. Both can coexist:

# Using stacy tasks
stacy task all

# Or using master.do through stacy (still get exit codes)
stacy run master.do

From Make to Make + stacy

If you already use Make:

Before

%.log: %.do
    stata-mp -b do $<

After

%.log: %.do
    stacy run $<

That’s it. Make now stops on Stata errors.

Adding package management

# Ensure packages are installed before running
.PHONY: install
install:
    stacy install

results/analysis.dta: analysis.do install
    stacy run analysis.do

Checklist

Minimal migration (exit codes only)

  • Install stacy
  • Replace stata -b do with stacy run in scripts/Makefile
  • Verify stacy doctor passes

Full migration (packages + tasks)

  • Run stacy init
  • Add packages with stacy add
  • Remove ssc install lines from scripts
  • Add [scripts] section for common tasks
  • Commit stacy.toml and stacy.lock
  • Update CI to run stacy install before tests
  • Tell collaborators to run stacy install after pulling

See Also

FAQ

Getting Started

Do I need to change my Stata scripts?

No. stacy runs your existing .do files unchanged.

Can I use stacy with existing projects?

Yes. Run stacy init in any directory to create stacy.toml. Existing scripts work as before.

What if I don’t use Make or Snakemake?

stacy works standalone. You get error detection, lockfile packages, and the task runner:

[scripts]
clean = "clean_data.do"
analysis = "analysis.do"
all = ["clean", "analysis"]
stacy task all

How is stacy different from batch mode?

Batch modestacy
Always exits 0Exits 1-10 on errors
Errors in log onlyErrors shown with docs link
No package managementLockfile pins versions

Package Management

How is the lockfile different from net install?

net install gets whatever version exists today. The lockfile records exact versions with checksums. stacy install reproduces those exact versions.

Can I use packages not on SSC?

Yes:

stacy add github:sergiocorreia/reghdfe
stacy add github:user/repo@v1.2

What happens if SSC is down?

Packages are cached at ~/.cache/stacy/packages/. Cached packages work offline.

Where are packages stored?

Global cache at ~/.cache/stacy/packages/, organized by name/version. stacy sets S_ADO at runtime for project isolation.

Technical

How does stacy detect errors?

Runs Stata with -b -q, parses the log for r() patterns, returns appropriate exit code. See How It Works.

Does stacy modify my Stata installation?

No. stacy manages packages in its own cache and sets S_ADO at runtime.

What are the exit codes?

CodeMeaning
0Success
1Stata error
2Syntax error
3File error
4Memory error
5Internal error
6Statistical error
10Environment error

Updates

Does stacy check for updates automatically?

Yes. On startup, stacy checks a local cache for available updates and prints a notification to stderr. The cache is refreshed in the background every 24 hours via the GitHub Releases API. This never blocks or slows down commands.

How do I disable update checks?

Either set update_check = false in ~/.config/stacy/config.toml, or set the STACY_NO_UPDATE_CHECK environment variable. Update checks are also suppressed automatically in CI and non-interactive environments. See User Config for details.

Compatibility

Does stacy work on Windows?

Yes. Windows, macOS, and Linux.

Which Stata versions are supported?

Stata 14+ (MP, SE, BE, StataNow).

Can I use stacy in Docker?

Yes. Set STATA_BINARY environment variable.

Can I use stacy without leaving Stata?

Yes. Installing the Stata wrappers (net install stacy, from("https://stacy.janfasnacht.com/stata")) makes every command available from the Stata console: stacy run analysis.do, stacy add estout, and so on, with help stacy documentation. Under the hood, stacy run still executes your script in a fresh batch-mode Stata process – that separate process is what makes the outcome observable and the environment isolated.

Troubleshooting

Installation

stacy: command not found

Add ~/.local/bin to PATH:

export PATH="$HOME/.local/bin:$PATH"  # add to ~/.zshrc

Restart terminal.

Installation script fails

mkdir -p ~/.local/bin
curl -fsSL https://stacy.janfasnacht.com/install.sh | bash

macOS blocks the binary

xattr -d com.apple.quarantine ~/.local/bin/stacy

Stata Detection

Stata not found

Set path explicitly:

export STATA_BINARY=/path/to/stata-mp

Or create ~/.config/stacy/config.toml:

stata_binary = "/path/to/stata-mp"

Run stacy doctor to verify.

Wrong Stata version detected

stacy env  # see what was found
export STATA_BINARY=/path/to/correct/stata-mp

Permission denied running Stata

chmod +x /path/to/stata-mp

Runtime

Exit code doesn’t match error

Possible causes:

  • Script uses capture to suppress errors
  • stacy only catches r() errors, not warnings
  • Custom program writes non-standard messages

Report missed errors.

Script works in GUI but fails with stacy

Working directory: stacy runs from current shell directory.

Missing packages: Run stacy add packagename.

Profile.do: stacy uses -q flag, skipping profile.do.

Log file not found

Check write permissions. Try stacy run -v script.do for verbose output.

Packages

Failed to download from SSC

Check network: curl -I https://www.stata.com

Retry: stacy add packagename

Checksum mismatch

SSC updated the package: stacy update packagename

Or clear cache: stacy cache packages clean && stacy install

Package installed but Stata can’t find it

stacy list  # verify it's listed

Check package docs for unlisted dependencies.

Lockfile

Conflicts after git merge

Resolve stacy.toml conflicts first, then:

stacy lock

Lockfile out of sync

stacy lock          # regenerate
stacy lock --check  # verify

Different results on teammate’s machine

  1. Verify lockfile committed: git status stacy.lock
  2. Both have same lockfile: git diff origin/main -- stacy.lock
  3. Reinstall: stacy install
  4. Check Stata versions: stacy env

Update Notifications

How do I disable update notifications?

Set update_check = false in ~/.config/stacy/config.toml:

update_check = false

Or set an environment variable:

export STACY_NO_UPDATE_CHECK=1

Notifications don’t appear

Update notifications are suppressed when:

  • stderr is not a terminal (piped output, cron, scripts)
  • CI or GITHUB_ACTIONS environment variable is set
  • STACY_NO_UPDATE_CHECK environment variable is set
  • update_check = false in user config

If you want to check manually: stacy --version and compare with the releases page.

Notification shows wrong upgrade command

stacy detects the install method from the binary path. If detection is wrong (e.g., after moving the binary), the fallback shows the GitHub releases URL.

Getting Help

  1. Run stacy doctor
  2. Run failing command with -v
  3. Open an issue

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[Unreleased]

[1.5.0] - 2026-07-13

Commands that could not finish their work used to exit 0. They now exit nonzero, which will surface failures a script or CI step previously ran past. See Changed.

Changed

  • Package commands exit nonzero when their work did not complete, and report a non-success status in --format json/stata. install, lock, outdated, add, update and deps all treated a resolve, install or version-check failure as a warning and exited 0 (#94).
  • stacy.toml rejects unknown keys, naming the offending one. A misplaced or misspelled key — a dependency under [dependencies] instead of [packages.dependencies], a typo’d verison pin — was dropped without a word (#100).
  • [packages] ado_dir is rejected along with them. Nothing has ever read it; local ado directories are [paths] ado. Remove the key if your stacy.toml carries it (#100).
  • stacy install no longer writes stacy.lock. It installs the pinned version and fails when the source no longer serves it, instead of re-resolving and moving the pin. SSC serves only the current revision, so a cold-cache install of a superseded pin now fails rather than silently installing something else (#96).
  • stacy run checks every locked package against the cache before starting Stata and fails on a missing or modified one. run --no-verify skips the check (#97).
  • A successful run removes its log in every output format. --format json/stata kept it, so each in-Stata stacy_run left one behind (#98).

Fixed

  • stacy run no longer drops streamed output that looks like a command echo. Echo detection ran on the trimmed line, so indented result lines went with it: every data row of list, the missing-value row of tabulate, missing, display "1. step". The log was never affected (#95).
  • [run] log_dir is honored. Per-script logs were written to the project root and kept after a successful run (#98).
  • stacy env checks the cache before calling a locked package installed. A cold cache reported every package as installed (#99).
  • stacy add <name> --source local:<dir> requires the directory to hold the named package instead of installing whatever it contains (#100).
  • stacy doctor no longer reports a package’s own shipped files as missing dependencies. ftools’ internal .mata files were listed as missing SSC packages, with a stacy add tip that could not work (#101).
  • A task that defines no work — a table without script or parallel (e.g. a typo’d key, which TOML parsing silently drops) or an empty array — now fails with a config error instead of succeeding as a no-op (#92).

[1.4.0] - 2026-07-13

Added

  • Post-install dependency hints now also read the Requires: line of a package’s .pkg manifest, catching author-declared SSC dependencies that static .ado scanning misses (#78).
  • stacy add warns when a package’s manifest declares a newer minimum Stata version than the one stacy last detected (#82).
  • stacy test -C <dir>/--directory and --cd: control the test working directory, matching stacy run (#85).

Changed

  • stacy test runs tests with the project root as the working directory regardless of where it’s invoked (previously the inherited directory) (#85).

Fixed

  • .pkg manifests with bare \r (classic-Mac) line endings no longer parse as a title with no files (#79).
  • stacy task from the Stata console no longer fails with r(199): machine-readable formats no longer stream script output to stdout (#84).
  • Line breaks in --format stata string values are replaced with spaces.

[1.3.1] - 2026-07-10

Added

  • stacy lock --refresh: recompute lockfile checksums from the installed cache.

Fixed

  • Packages whose .pkg manifest lists a file twice (e.g. reghdfe) no longer fail checksum verification (#68). Run stacy lock --refresh to repair lockfile entries recorded by older versions.

[1.3.0] - 2026-07-09

Changed

  • stacy run streams program output to stdout live in piped mode, like Rscript (#24). Same content as before, just live; status and errors stay on stderr. stacy task streams too.
  • The log file is now internal: removed on success, kept on failure. Machine-readable formats keep it. Use --log <path> for a durable artifact.
  • --parallel prints each script’s output as a grouped block on completion instead of discarding it.

Added

  • stacy run --log <path>: write the raw Stata log to a chosen path (works with --quiet for silent file-artifact mode).

Removed

  • Dead log_reader::is_successful_completion (unused since the streaming rework, #65).

Fixed

  • Task arrays accept script paths: all = ["clean", "src/02_analyze.do"] (#64).
  • Post-install hints comma-separate package names (#63).
  • Failure context no longer loads the entire log into memory (#66).
  • Log streaming no longer hangs when Stata is killed or fails to launch, recovers from truncated logs, and survives closed pipes (| head).
  • --trace no longer leaks its temp script and log.

[1.2.1] - 2026-05-06

Added

  • Stata wrappers now verify that the stacy binary they invoke is version-compatible (#35). On mismatch, _stacy_exec aborts with a clear error and a stacy_setup, force hint instead of silently running against a stale binary. The check shells out once per Stata session (cached in $stacy_version_checked).

Fixed

  • Surface Stata’s stderr on launch failures instead of the misleading “Log file incomplete” (#21). Distinguish “no log produced” (launch failure) from “log truncated” (killed mid-run).
  • stacy install --format stata (and --format json) no longer emits a success-shaped block when checksum verification fails (#38). Status is now computed before output, so wrappers see global stacy_status "error" plus global stacy_error "<msg>" (and JSON gets matching status/error/failed fields) instead of a stale success preceding the non-zero exit.
  • Stata wrappers failed with command _stacy_check_version is unrecognized because the generated _stacy_compat.ado defined programs that didn’t match its filename and wasn’t listed in stacy.pkg (#37). Split into one file per program.
  • Parallel stacy run invocations on scripts that share a basename no longer collide on the log file (#20). Each run writes to a uniquely-named log in the working directory (<stem>_<pid>_<nanos>_<n>.log), so build orchestrators like Make -j and Snakemake can run same-stemmed scripts from a shared cwd safely. The path is reported in JSON output’s log_file field.
  • Non-UTF-8 characters in Stata log files no longer crash the log parser
  • Update check now compares against the running binary version, not a stale cached value
  • Cargo upgrade instruction now shows correct crate name (stacy, not stata-cli)

1.2.0 - 2026-03-15

Added

  • stacy run --timeout <seconds> to kill long-running scripts
  • [paths] config section for project-local ado directories in S_ADO
  • Post-install dependency scanning: warn about missing implicit dependencies after stacy add and in stacy doctor
  • Package naming hints: suggest correct SSC package on 404 (e.g. labmasklabutil)
  • Stata wrappers now expose all CLI flags (AllowGlobal, Trace, Timeout, Parallel, Cache, etc.)

Changed

  • stacy init generates minimal config (no default values the user will delete)
  • Dependencies in stacy.toml sorted alphabetically
  • stacy init and stacy add show package cache location

Fixed

  • Sync commands.toml schema with CLI (missing flags, stale args, missing exit code 6)

1.1.0 - 2026-02-22

Added

  • net: source type for arbitrary URL packages (stacy add grc1leg --source net:http://www.stata.com/users/vwiggins/)
  • local: source type for vendored/local packages (stacy add myutils --source local:./lib/myutils/)
  • GitHub fallback: synthesize manifest from repository tree when .pkg file is missing
  • Post-install hints for packages with known implicit dependencies (reghdfe, ivreghdfe, ppmlhdfe, grstyle, etc.)
  • stacy doctor now surfaces available updates (reads version check cache)
  • stacy deps now parses require statements as package dependencies (including cap require and capture require)

Changed

  • Improved SSC error messages: distinguish “package not found” from “mirror gap” from “server unreachable”

1.0.2 - 2026-02-17

Fixed

  • Fix SSC downloads always failing: use HTTP instead of HTTPS for fmwww.bc.edu (the server does not support TLS, causing every stacy add from SSC to fall back to the GitHub mirror)

1.0.1 - 2026-02-16

Fixed

  • Fix net install from Stata: remove phantom files from stacy.pkg that caused r(601)
  • Fix --format stata output: wrong global prefix, wrong quoting, bare types in syntax
  • Fix stacy init --name option and stacy task config section reference
  • Fix installation docs command name

Added

  • 24 tests for --format stata output and codegen correctness

Changed

  • Regenerate all Stata wrappers with fixes
  • Align docs and README with paper framing

1.0.0 - 2026-02-15

Initial public release.

Added

  • stacy run — Execute Stata scripts with proper error detection and exit codes
  • stacy run -c — Run inline Stata code
  • stacy run --parallel — Parallel execution of multiple scripts
  • stacy init — Initialize project with stacy.toml
  • stacy add / stacy remove — Manage dependencies
  • stacy install — Reproducible installs from lockfile
  • stacy update / stacy outdated — Keep packages current
  • stacy lock — Generate and verify lockfile
  • stacy task — Task runner (npm-style scripts in stacy.toml)
  • stacy deps — Script dependency analysis
  • stacy env / stacy doctor — Environment diagnostics
  • stacy explain — Error code lookup
  • Error codes dynamically extracted from user’s Stata installation
  • SSC and GitHub package sources (github:user/repo@tag)
  • Global package cache at ~/.cache/stacy/packages/
  • --format json and --format stata output modes
  • Cross-platform support: macOS, Linux, Windows

Contributing