Introduction
stacy is a modern workflow tool for Stata. It runs scripts with proper exit codes, manages packages with lockfiles, and integrates Stata into reproducible pipelines.
For those familiar with other ecosystems:
| If you know… | stacy is like… | Key similarity |
|---|---|---|
| Rust | Cargo | Manifest + lockfile + build orchestration |
| Python | uv or Poetry | Project dependencies + reproducible environments |
| JavaScript | npm | package.json / package-lock.json workflow |
| R | renv | Project-local library snapshots |
| Stata | (nothing existed) | This is what stacy provides |
The Problem
Stata’s defaults leave two critical things implicit:
Dependencies are global and unversioned. Packages install to a global path. Versions are whatever SSC has today. When a package updates, every project using it changes silently. A replication package that worked six months ago may fail today because reghdfe changed its defaults.
Execution always returns success. 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 orchestration tools cannot detect failure–they proceed as if nothing went wrong.
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
Now your builds stop on errors and your environments reproduce:
results/output.dta: analysis.do data/input.dta
stacy run analysis.do # Stops on failure
Before and After
| Without stacy | With stacy |
|---|---|
stata -b do script.do returns 0 even on error | stacy run script.do returns 1-10 on error |
| Packages are global, unversioned | stacy.lock pins exact versions |
| Errors buried in log files | Errors displayed with documentation links |
| “It worked on my machine” | Same versions everywhere via lockfile |
Manual ssc install in scripts | stacy install from lockfile |
Key Features
| Feature | What it provides |
|---|---|
| Proper exit codes | Maps 182 official Stata error codes to Unix exit codes |
| Lockfile management | stacy.lock pins exact versions with SHA256 checksums |
| Global package cache | Packages cached at ~/.cache/stacy/packages/, shared across projects |
| Build system integration | Works with Make, Snakemake, CI/CD |
| Single binary | No runtime dependencies, easy to deploy |
Note: Error detection uses 182 official Stata error codes from the Stata Programming Reference Manual–not heuristics.
Incremental Adoption
Even minimal usage restores critical functionality:
| Level | What you do | What you get | Who this is for |
|---|---|---|---|
| 1 | stacy run script.do | Exit codes work | Anyone using Make/CI |
| 2 | stacy init | Project configuration | Teams wanting standards |
| 3 | stacy add pkg | Locked dependencies | Reproducibility needs |
| 4 | Add [scripts] | Task automation | Complex workflows |
| 5 | Integrate with Make/CI | Full pipeline | Publication-ready research |
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
- Just want to run scripts? Start with Quick Start
- Setting up a project? See Project Config
- Integrating with build tools? Read Build Integration
- Looking up a command? Check the Command Reference
- Something not working? Try Troubleshooting or FAQ
Next Steps
- Installation - Get stacy installed
- Quick Start - Run your first script
- FAQ - Common questions answered
Installation
stacy is a single static binary with no runtime dependencies.
Quick Install
macOS / Linux:
curl -fsSL https://raw.githubusercontent.com/janfasnacht/stacy/main/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.
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:
| Platform | Searched paths |
|---|---|
| macOS | /Applications/Stata*/, /Applications/StataNow/ |
| Linux | /usr/local/stata*, ~/stata* |
| Windows | C:\Program Files\Stata*\ |
If Stata is elsewhere, configure via (in precedence order):
- CLI flag:
stacy run --engine /path/to/stata-mp script.do - Environment:
export STATA_BINARY=/path/to/stata-mp - Config file:
~/.config/stacy/config.toml
Troubleshooting
Common installation issues:
| Problem | Solution |
|---|---|
stacy: command not found | Add ~/.local/bin to PATH, restart terminal |
| macOS blocks binary | Run xattr -d com.apple.quarantine ~/.local/bin/stacy |
| Stata not found | Set 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: v0.1.0 → v0.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 - Run your first script
- stacy doctor - Troubleshoot detection issues
Quick Start
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
- Commands - Full reference
- Configuration - Project settings
- FAQ - Common questions
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
[packages.dependencies]
estout = "ssc"
reghdfe = "github:sergiocorreia/reghdfe"
[packages.dev]
assert = "ssc"
[scripts]
clean = "src/01_clean.do"
build = ["clean", "src/02_build.do", "src/03_analyze.do"]
Sections
[project]
Project metadata. Optional but recommended for collaborative projects.
| Field | Type | Default | Description |
|---|---|---|---|
name | string | directory name | Project name |
authors | array | [] | List of authors |
description | string | none | Project description |
url | string | none | Project URL |
[run]
Settings for stacy run command.
| Field | Type | Default | Description |
|---|---|---|---|
log_dir | string | "logs" | Directory for log files |
show_progress | bool | true | Show progress during execution |
progress_interval_seconds | int | 10 | Progress update interval |
max_log_size_mb | int | 50 | Log size warning threshold |
[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: run a single script
clean = "src/01_clean.do"
# Sequential: run tasks/scripts in order
build = ["clean", "src/02_build.do", "src/03_analyze.do"]
# Parallel: run scripts concurrently
test = { parallel = ["test/test1.do", "test/test2.do"] }
Important Notes
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 Tasks
[project]
name = "analysis"
[packages.dependencies]
estout = "ssc"
[scripts]
clean = "src/01_clean.do"
build = ["clean", "src/02_build.do"]
all = ["build", "src/03_report.do"]
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 - Machine-specific settings (
~/.config/stacy/config.toml) - stacy init - Create stacy.toml
- stacy env - View loaded configuration
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
| Platform | Path |
|---|---|
| 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):
--engineCLI flagSTATA_BINARYenvironment variablestata_binaryin user config- 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:
- Reads a local cache (
~/.cache/stacy/version-check.json) on startup - Prints a notification to stderr if a newer version is available
- 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:
| Variable | Effect |
|---|---|
STATA_BINARY | Stata binary path (overrides config file) |
STACY_NO_UPDATE_CHECK | Suppress update notifications (set to any value) |
CI | Suppresses update notifications automatically |
GITHUB_ACTIONS | Suppresses update notifications automatically |
Update Notification Suppression
Update notifications are automatically suppressed when:
update_check = falsein user configSTACY_NO_UPDATE_CHECKenvironment variable is setCIorGITHUB_ACTIONSenvironment variable is set- stderr is not a terminal (piped output, cron jobs, etc.)
The notification looks like:
Update available: v0.1.0 → v0.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:
| Platform | Path |
|---|---|
| macOS / Linux | ~/.cache/stacy/ |
| Windows | %LOCALAPPDATA%\stacy\cache\ |
Contents:
| File | Purpose |
|---|---|
packages/ | Global package cache (shared across projects) |
version-check.json | Last update check result |
update-available | Flag 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
- Project Config - Per-project settings (
stacy.toml) - stacy env - View resolved configuration
- stacy doctor - Diagnose configuration issues
- Installation - Install methods and Stata detection
Commands Overview
stacy provides commands for Stata execution, package management, and project workflows.
By Category
Execution
stacy run- Execute scripts with error detectionstacy bench- Benchmark script performancestacy task- Run tasks from stacy.tomlstacy test- Run tests
Packages
stacy add/remove/update- Manage dependenciesstacy install- Install from lockfilestacy list/outdated- View package statusstacy lock- Generate/verify lockfile
Project
stacy init- Initialize new projectstacy deps- Analyze script dependencies
Utility
stacy env- Show configurationstacy doctor- System diagnosticsstacy explain- Look up error codesstacy cache- Manage build cache
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).
By default, clean output is shown after execution (boilerplate stripped). On
failure, error details with official Stata documentation links and the log file
path are displayed. Use -v to stream the raw log in real-time instead, or
-q to suppress all output.
Multiple scripts can be run sequentially (default, fail-fast) or in parallel
(--parallel). Parallel mode runs all scripts regardless of failures.
For interactive use where you want to quickly check a result, see stacy eval.
Arguments
| Argument | Description |
|---|---|
<SCRIPT> | Script to execute |
Options
| Option | Description |
|---|---|
--cd | Change to script’s parent directory |
-c, --code | Inline Stata code |
-C, --directory | Run Stata in this directory |
--profile | Include execution metrics |
-q, --quiet | Suppress output |
--trace | Enable execution tracing at given depth |
--verbose | Extra 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
stt run --trace 2 analysis.do
stt run --trace 2 -v analysis.do
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Stata error (r() code detected) |
| 2 | Syntax error |
| 3 | File error (not found, permission denied) |
| 4 | Memory error |
| 5 | Internal stacy error |
| 10 | Environment 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
| Argument | Description |
|---|---|
<SCRIPT> | Stata script to benchmark (required) |
Options
| Option | Description |
|---|---|
--no_warmup | Skip warmup runs |
-q, --quiet | Suppress progress output |
-n, --runs | Number of measured runs |
-w, --warmup | Number of warmup runs |
Examples
Benchmark a script
stacy bench analysis.do
Custom run count
stacy bench -n 20 analysis.do
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Script failed during benchmark |
| 3 | Script 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
| Argument | Description |
|---|---|
<PATH> | Project directory (default: current) |
Options
| Option | Description |
|---|---|
--force | Overwrite existing files |
--name | Project name |
--yes | Skip interactive prompts (always set in Stata) |
Examples
Initialize in current directory
stacy init
Initialize in new directory
stacy init my-project
Initialize with project name
stacy init --name "My Analysis"
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Project created successfully |
| 1 | Initialization 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
| Argument | Description |
|---|---|
<PACKAGES> | Package names to add (required) |
Options
| Option | Description |
|---|---|
--dev | Add as development dependency |
--source | Package source: ssc or github:user/repo[@ref] |
--test | Add 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
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | All packages 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
| Argument | Description |
|---|---|
<PACKAGES> | Package names to remove (required) |
Examples
Remove a package
stacy remove estout
Remove multiple packages
stacy remove estout reghdfe
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | No 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.
Arguments
| Argument | Description |
|---|---|
<PACKAGES> | Package names to update (default: all) |
Options
| Option | Description |
|---|---|
--dry_run | Show 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
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | All updates failed |
See Exit Codes Reference for details.
See Also
stacy install
Install packages from lockfile or SSC/GitHub
Synopsis
stacy install <PACKAGE> [OPTIONS]
Description
Installs packages defined in stacy.lock (or stacy.toml if no lockfile exists).
This ensures reproducible environments by installing exact versions from the
lockfile. Can also install individual packages directly from SSC or GitHub.
Arguments
| Argument | Description |
|---|---|
<PACKAGE> | Package name (optional) |
Options
| Option | Description |
|---|---|
--from | Source: ssc or github:user/repo |
Examples
Install from lockfile
Install all packages at locked versions
stacy install
Install specific package
stacy install estout
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Installation failed |
| 3 | Package not found |
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
| Option | Description |
|---|---|
--tree | Group packages by dependency type |
Examples
List packages
stacy list
List by dependency group
stacy list --tree
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
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
| Code | Meaning |
|---|---|
| 0 | Success |
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
| Option | Description |
|---|---|
--check | Verify lockfile matches stacy.toml without updating |
Examples
Generate lockfile
stacy lock
Verify lockfile (for CI)
stacy lock --check
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success / in sync |
| 1 | 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). Shows a tree view of the dependency graph, detects circular
dependencies, and identifies missing files.
Arguments
| Argument | Description |
|---|---|
<SCRIPT> | Script to analyze (required) |
Options
| Option | Description |
|---|---|
--flat | Show flat list instead of tree |
Examples
Show dependency tree
stacy deps main.do
Show flat list
stacy deps --flat main.do
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Analysis complete |
| 3 | Script not found |
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
| Argument | Description |
|---|---|
<TASK> | Task name to run |
Options
| Option | Description |
|---|---|
--frozen | Fail if lockfile doesn’t match stacy.toml |
--list | List available tasks |
Examples
Run a task
stacy task build
List available tasks
stacy task --list
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Task failed |
| 5 | Task 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 test/ directory. Tests are Stata
scripts that use assertion commands. Supports filtering, parallel execution,
and verbose output for debugging failures.
Arguments
| Argument | Description |
|---|---|
<TEST> | Specific test to run |
Options
| Option | Description |
|---|---|
-f, --filter | Filter tests by pattern |
--list | List tests without running |
--parallel | Run tests in parallel |
-q, --quiet | Suppress progress output |
-V, --verbose | Show full log context for failures |
Examples
Run all tests
stacy test
Run specific test
stacy test test_regression
Filter tests
stacy test -f 'regression*'
Exit Codes
| Code | Meaning |
|---|---|
| 0 | All tests passed |
| 1 | One or more tests failed |
| 5 | Test 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
| Code | Meaning |
|---|---|
| 0 | Success |
| 10 | Not 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
| Code | Meaning |
|---|---|
| 0 | Success |
| 10 | Environment error (Stata not found) |
See Exit Codes Reference for details.
See Also
stacy doctor
Run system diagnostics
Synopsis
stacy doctor
Description
Checks your system configuration and reports any issues. Verifies Stata installation, project detection, and write permissions. Run this first when troubleshooting.
Examples
Run diagnostics
stacy doctor
Exit Codes
| Code | Meaning |
|---|---|
| 0 | All checks passed |
| 1 | One 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
| Argument | Description |
|---|---|
<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
| Code | Meaning |
|---|---|
| 0 | Error code found |
| 1 | Unknown error code |
See Exit Codes Reference for details.
See Also
How It Works
Technical details on stacy’s architecture.
Contents
Error Detection
The Problem
Stata’s batch mode (stata -b do script.do) always exits with code 0, even when scripts fail. Errors are only visible in log files.
stacy’s Solution
- Execute: stacy runs Stata with
-b -qflags - Parse: After Stata exits, stacy parses the log file
- Detect: Matches against 182 official error patterns
- Report: Returns appropriate exit code (1-10)
┌───────────┐ ┌───────┐ ┌─────────┐ ┌──────────┐
│ stacy run │ ──▶ │ Stata │ ──▶ │ Log │ ──▶ │ Exit │
│ │ │ -b -q │ │ Parser │ │ Code 0-10│
└───────────┘ └───────┘ └─────────┘ └──────────┘
Error Patterns
stacy recognizes errors in two forms:
r() codes (primary):
r(199);
Error messages (secondary):
unrecognized command: foobar
file myfile.dta not found
Official Stata Error Codes
stacy includes all 182 error codes from the Stata Programming Reference Manual:
| Range | Category | Examples |
|---|---|---|
| r(1-99) | General errors | r(1) generic error |
| r(100-199) | Syntax/variable errors | r(111) not found, r(199) unrecognized command |
| r(400-499) | System limits | r(459) not sorted |
| r(600-699) | File errors | r(601) file not found, r(603) file exists |
| r(900-999) | Resource errors | r(950) insufficient memory |
10 Most Common Errors
| Code | Name | Typical Cause |
|---|---|---|
| r(100) | varlist required | Command needs variable list |
| r(109) | type mismatch | String operation on numeric or vice versa |
| r(111) | not found | Variable doesn’t exist in dataset |
| r(198) | invalid syntax | Malformed command |
| r(199) | unrecognized command | Command doesn’t exist or package missing |
| r(459) | not sorted | Data must be sorted |
| r(601) | file not found | File doesn’t exist |
| r(603) | file already exists | Need replace option |
| r(950) | insufficient memory | Operation too large |
Accuracy
Error detection achieves 97% accuracy on common patterns. Edge cases:
captureblocks: Intentionally suppressed errors are not reported (captured errors don’t producer(N);after the “end of do-file” marker)- Custom programs: User-written error messages may not match patterns
- Unusual formatting: Some packages produce non-standard log output
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
Cache benefits:
- Multiple versions coexist
- Shared across projects (disk efficient)
- Offline installation from cache
Runtime Isolation
When you run stacy run script.do, stacy:
- Reads
stacy.lockto determine required packages - Builds a custom
S_ADOpath pointing to cached versions - Launches Stata with this adopath
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.
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
- SSC hasn’t silently updated the package
Output Streaming
Real-time Logs
Use -v (verbose) to stream Stata’s log output as it runs:
stacy run -v long_analysis.do
This displays log lines in real-time, useful for:
- Monitoring long-running scripts
- Debugging interactively
- Seeing progress indicators
Progress Reporting
For scripts 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, combine --format json with verbose output:
stacy run --format json -v analysis.do 2>log.txt
- stdout: JSON result
- stderr: Real-time log stream
Machine Interface
stacy is designed for integration with other tools.
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:
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Stata error |
| 2 | Syntax error |
| 3 | File error |
| 4 | Memory error |
| 5 | Internal error |
| 10 | Environment error |
See Exit Codes for mapping details.
Build System Integration
stacy’s exit codes enable integration 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"))
See Also
- Exit Codes - Exit code reference
- JSON Output - JSON schemas
- Stata Error Manual - Official documentation
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"
How Checksums Work
Checksums verify that the installed package matches exactly what was recorded:
- On install: stacy downloads the package, computes SHA256 of the contents
- On lock: Computed hash is stored in
stacy.lock - 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
If checksums don’t match, stacy install fails with an error explaining the mismatch.
Fields Reference
| Field | Required | Description |
|---|---|---|
version | Yes | Lockfile format version (currently “1”) |
packages.<name>.version | Yes | Package version string |
packages.<name>.checksum | Yes | SHA256 hash prefixed with sha256: |
packages.<name>.source.type | Yes | "SSC" or "GitHub" |
packages.<name>.source.name | SSC only | Package name on SSC |
packages.<name>.source.repo | GitHub only | owner/repo format |
packages.<name>.source.tag | GitHub only | Git 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
| File | Commit? | Why |
|---|---|---|
stacy.toml | Yes | Declares dependencies |
stacy.lock | Yes | Ensures reproducibility |
~/.cache/stacy/packages/ | No | Cache, 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
Merge conflicts in lockfile
After a git merge with conflicts:
# Resolve stacy.toml conflicts first, then:
stacy lock # Regenerate lockfile
See Also
- stacy install - Install packages from lockfile
- stacy lock - Generate/verify lockfile
- stacy add - Add packages
- Project Config - The stacy.toml file
Exit Codes
stacy uses consistent exit codes to indicate success or failure type.
Exit Code Table
| Code | Name | Description |
|---|---|---|
| 0 | Success | Operation completed successfully |
| 1 | Stata Error | Stata r() code detected in log |
| 2 | Syntax Error | Invalid Stata syntax |
| 3 | File Error | File not found, permission denied, data errors |
| 4 | Memory Error | Insufficient memory |
| 5 | Internal Error | stacy itself failed (not Stata) |
| 10 | Environment Error | Stata not found or configuration invalid |
Stata r() Code Mapping
stacy maps Stata’s r() error codes to exit codes:
| Exit Code | Stata r() Codes |
|---|---|
| 1 | most r() codes not in other categories |
| 2 | r(198), r(199) |
| 3 | r(601), r(603), r(610), r(639), r(2000-2999) |
| 4 | r(950) |
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
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": "analysis.log"
}
Failure:
{
"success": false,
"script": "analysis.do",
"duration_secs": 0.45,
"exit_code": 2,
"log_file": "analysis.log",
"errors": [
{
"type": "StataCode",
"r_code": 199,
"name": "unrecognized command",
"line": 15,
"context": "reghdfe price mpg, absorb(make)"
}
]
}
| Field | Type | Description |
|---|---|---|
success | bool | Whether script completed without errors |
script | string | Path to script that was run |
duration_secs | float | Execution time in seconds |
exit_code | int | stacy exit code (0-10) |
log_file | string | Path to Stata log file |
errors | array | Error details (only on failure) |
errors[].type | string | Error type (StataCode, Syntax, File) |
errors[].r_code | int | Stata r() code if applicable |
errors[].name | string | Human-readable error name |
errors[].line | int | Line number if detected |
errors[].context | string | Code 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": []
}
| Field | Type | Description |
|---|---|---|
success | bool | Whether all packages installed |
installed | array | Packages downloaded this run |
already_cached | array | Packages found in cache |
failed | array | Packages 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"
}
]
}
| Status | Meaning |
|---|---|
ok | Check passed |
warning | Non-blocking issue |
error | Blocking issue |
stacy deps
{
"root": "master.do",
"files": [
"master.do",
"config/settings.do",
"src/01_clean_data.do",
"src/utils/helpers.do"
],
"missing": [],
"circular": []
}
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
-eflag to handle missing fields gracefully in scripts.
See Also
- stacy run - Running scripts
- Build Integration - CI/CD and build tools
- Exit Codes - Exit code meanings
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://raw.githubusercontent.com/janfasnacht/stacy/main/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:
--frozenfails if lockfile doesn’t match stacy.toml, catching uncommitted dependency changes.
GitLab CI
# .gitlab-ci.yml
analysis:
stage: build
before_script:
- curl -fsSL https://raw.githubusercontent.com/janfasnacht/stacy/main/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:
- Self-hosted runner with Stata installed
- Docker container with Stata
- Skip Stata steps in CI (validate config only)
See GitHub Actions docs or GitLab CI docs for more.
Best Practices
- Use
--frozenin CI to catch lockfile drift - Commit
stacy.lockfor reproducibility - Cache packages to speed up builds
- Use JSON output for programmatic checks:
stacy run --format json - Upload artifacts on failure for debugging
See Also
- How It Works - Exit codes and JSON
- Exit Codes - Code meanings
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 workflow | stacy equivalent |
|---|---|
stata -b do script.do | stacy run script.do |
ssc install pkg | stacy 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
.dofiles 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
-
List current packages
ado dir -
Initialize stacy
stacy init -
Add each package
stacy add estout reghdfe ftools -
Remove ssc install lines from scripts Delete or comment out
ssc installcommands–stacy handles this now. -
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
capturelogic)
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 dowithstacy runin scripts/Makefile - Verify
stacy doctorpasses
Full migration (packages + tasks)
- Run
stacy init - Add packages with
stacy add - Remove
ssc installlines from scripts - Add
[scripts]section for common tasks - Commit
stacy.tomlandstacy.lock - Update CI to run
stacy installbefore tests - Tell collaborators to run
stacy installafter pulling
See Also
- Quick Start - Getting started guide
- Project Config - stacy.toml reference
- Build Integration - Make, Snakemake, CI/CD
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"
all = ["clean", "analysis.do"]
stacy task all
How is stacy different from batch mode?
| Batch mode | stacy |
|---|---|
| Always exits 0 | Exits 1-10 on errors |
| Errors in log only | Errors shown with docs link |
| No package management | Lockfile 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?
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Stata error |
| 2 | Syntax error |
| 3 | File error |
| 4 | Memory error |
| 5 | Internal error |
| 10 | Environment 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.
Does stacy work with Stata GUI?
stacy is for command-line workflows (batch mode). Use Stata directly for interactive work.
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://raw.githubusercontent.com/janfasnacht/stacy/main/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
captureto suppress errors - stacy only catches
r()errors, not warnings - Custom program writes non-standard messages
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
- Verify lockfile committed:
git status stacy.lock - Both have same lockfile:
git diff origin/main -- stacy.lock - Reinstall:
stacy install - 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)
CIorGITHUB_ACTIONSenvironment variable is setSTACY_NO_UPDATE_CHECKenvironment variable is setupdate_check = falsein 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
- Run
stacy doctor - Run failing command with
-v - 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.0.0 - 2026-02-15
Initial public release.
Added
stacy run— Execute Stata scripts with proper error detection and exit codesstacy run -c— Run inline Stata codestacy run --parallel— Parallel execution of multiple scriptsstacy init— Initialize project withstacy.tomlstacy add/stacy remove— Manage dependenciesstacy install— Reproducible installs from lockfilestacy update/stacy outdated— Keep packages currentstacy lock— Generate and verify lockfilestacy task— Task runner (npm-style scripts instacy.toml)stacy deps— Script dependency analysisstacy env/stacy doctor— Environment diagnosticsstacy 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 jsonand--format stataoutput modes- Cross-platform support: macOS, Linux, Windows