A fast, local-first CI engine.
Project description
Locci — Local CI
Locci runs the safe parts of your CI pipeline locally — lint, tests, builds — before you push. It auto-detects your project stack, reads your GitHub Actions workflows, executes tasks through an embedded DAG engine with content-hash caching, and tells you exactly what it skipped and why.
Locci does not replace your remote CI runner. It catches the fast, side-effect-free failures locally so you waste fewer CI minutes on trivial errors.
Table of Contents
- Requirements
- Installation
- Quick start
- Commands
- Configuration reference — locci.yml
- Caching
- Secrets
- Remote cache (S3)
- GitHub Actions integration
- Exit codes
- Security caveats
Requirements
- Python 3.9+
- Git (for
preflight,--since) - Any language toolchains for stacks you want to run (
node,go,cargo,pytest, etc.)
Installation
Recommended — pipx (isolated, globally available)
pipx install locci
This puts locci on your PATH without polluting any project virtualenv.
pip
pip install locci
With optional extras
pip install "locci[ai]" # locci fix — AI-powered failure diagnosis (requires Anthropic key)
pip install "locci[s3]" # locci check --remote-cache s3://...
Quick start
cd my-project
# 1. Generate locci.yml and check your environment
locci setup
# 2. Run all safe local checks
locci check
# 3. Before every push — run only tasks affected by your changes
locci preflight
Commands
locci setup
Detects your project stack, generates a locci.yml, runs locci doctor, and optionally installs the git pre-push hook.
locci setup # interactive — writes locci.yml, prompts for hook install
locci setup --preview # print generated locci.yml to stdout, do not write anything
locci setup --force # back up existing locci.yml and replace it
locci setup --install-hook # install hook non-interactively
locci setup --no-install-hook # skip hook install non-interactively
locci check
Runs all detected local-safe tasks. This is the main command.
locci check # run everything in the current directory
locci check /path/to/project # run from a specific path
locci check --dry-run # show the full task list without running anything
locci check --verbose # stream full stdout/stderr for every task
locci check --no-cache # ignore cached results, re-run everything
locci check --jobs 8 # run up to 8 tasks in parallel (default: 4)
locci check --since main # run only tasks affected by changes since `main`
locci check --since HEAD~3 # affected by the last 3 commits
locci check --scope gha # run only tasks whose name starts with "gha"
locci check --matrix python=3.9,3.11 # expand tasks across a matrix of env variable values
locci check --allow-unsafe # run tasks Locci would normally skip as unsafe
locci check --strict-coverage # exit 2 when any tasks were skipped (coverage gap)
locci check --remote-cache s3://my-bucket/prefix # pull/push cache from S3
How tasks are selected:
- Auto-detected from your repo (GitHub Actions workflows,
pyproject.toml,package.json,go.mod,Cargo.toml, …). - Filtered by
--scope(prefix match on task name). - Filtered by
--since(only tasks whoseinput_globsoverlap changed files). - Safety policy applied — unsafe tasks are skipped unless
--allow-unsafeis set.
locci run
Backward-compatible alias for locci check. Accepts the same flags.
locci run
locci run --verbose --no-cache
locci preflight
Automation-facing affected check. Designed to be called from a git pre-push hook or a script. Never prompts.
locci preflight # detects base ref automatically (upstream branch or `main`)
locci preflight --strict-coverage
locci preflight --allow-unsafe
Locci resolves the base ref in this order:
LOCCI_OLD_SHAenvironment variable (set by the git hook).merge-baseofHEADand the tracked upstream branch.- Falls back to
main.
locci ready
Full pre-push confidence check. Same as check but always enforces --strict-coverage. Exits 2 if any tasks were skipped due to coverage gaps.
locci ready
locci ready --verbose
locci ready --allow-unsafe
locci watch
Watches for file changes and re-runs only the affected tasks on every save. Useful for tight feedback loops during development.
locci watch
locci watch /path/to/project
Press Ctrl-C to stop. Requires watchdog (bundled as a dependency).
locci fix
AI-powered diagnosis of the most recent failed task. Reads the failure from the local cache and explains what went wrong.
locci fix # diagnose the latest failure
locci fix --flaky # list tasks that have both passed and failed recently
Requires the [ai] extra: pip install "locci[ai]" and the ANTHROPIC_API_KEY environment variable.
locci doctor
Checks that all tools required by your project are installed and on PATH. Prints a status table with fix hints for anything missing.
locci doctor
locci doctor /path/to/project
Detected stacks and their required tools:
| Stack | Tools checked |
|---|---|
| Python | python3, pip, pytest, ruff (optional) |
| Node.js | node, npm |
| Go | go |
| Rust | cargo |
| Terraform | terraform |
| Protobuf | buf |
| Docker | docker (optional) |
Exit code 0 if all required tools are found, 3 if any required tool is missing.
locci graph
Prints the full task dependency graph (DAG) without running anything.
locci graph
locci graph /path/to/project
Output shows each task name, its command, its dependencies, and skip status.
locci logs
View stdout/stderr stored in the local task cache.
locci logs my-task-name # view the last run of a specific task
locci logs --failed # view the last failed task
locci cache-clear
Deletes all cached task results from ~/.locci/cache.db.
locci cache-clear
locci init
Generates a locci.yml from auto-detection or by importing from GitHub Actions workflows. Lower-level alternative to locci setup.
locci init # generate from auto-detected stack
locci init --from-github # import tasks from .github/workflows/*.yml
Exits 1 if locci.yml already exists — use locci setup --force to overwrite.
locci export
Exports the Locci pipeline to a native CI provider workflow file.
locci export # exports to .github/workflows/locci-generated.yml
locci export --format github # explicit GitHub Actions format (currently the only supported format)
The generated workflow uses the literal ${{ secrets.X }} expressions — no secret values are embedded in the output.
locci hook
Manages the Locci git pre-push hook.
locci hook install # install .git/hooks/pre-push that calls `locci preflight`
locci hook uninstall # remove the hook
locci hook status # print: installed | not-installed | foreign
The hook sets LOCCI_OLD_SHA so locci preflight can compute the exact changed ref range.
Configuration reference
Locci works without any config — it auto-detects tasks from your project. locci.yml (or locci.yaml) is optional and lets you tune, override, or add tasks.
version: 1
# --- Optional: override safety policy ---
safety:
skip_unsafe: true # default: true
unsafe_keywords: # tasks containing these words are skipped
- deploy
- publish
- release
- production
- prod
- upload
# --- Optional: caching ---
cache:
enabled: true # default: true
# --- Optional: add custom tasks ---
tasks:
my-lint:
run: ["ruff", "check", "."] # "run" and "cmd" are aliases
input_globs: ["**/*.py"]
timeout: 120 # seconds; null = no timeout
my-integration-test:
run: ["pytest", "tests/integration/"]
needs: ["my-lint"] # "needs" and "depends_on" are aliases
env:
DATABASE_URL: "sqlite:///test.db"
required_secrets: ["API_KEY"] # resolved from .env or shell env
output_dirs: [".pytest_cache"]
cwd: "."
local_safe: true # force-mark as safe (bypass keyword check)
# --- Optional: override auto-detected tasks ---
overrides:
gha:build:
run: ["make", "build"]
timeout: 300
Task fields
| Field | Type | Default | Description |
|---|---|---|---|
run / cmd |
list[str] |
— | Command to execute (required) |
needs / depends_on |
list[str] |
[] |
Task names that must succeed first |
input_globs |
list[str] |
["**/*"] |
Files that invalidate the cache when changed |
env |
dict |
{} |
Extra environment variables for this task |
required_secrets |
list[str] |
[] |
Secret names to resolve from .env or environment |
output_dirs |
list[str] |
[] |
Output directories included in the cache key |
cwd |
str |
"." |
Working directory relative to project root |
timeout |
int | null |
null |
Timeout in seconds |
local_safe |
bool | null |
null |
Explicitly mark safe (true) or unsafe (false) |
Caching
Locci caches task results in ~/.locci/cache.db (SQLite).
Cache key = SHA-256 of:
- The task command
- Contents of all files matched by
input_globs - Contents of all directories in
output_dirs - Extra environment variables (
env+ resolved secrets)
A task is cache-hit if the key matches the last successful run. It is then skipped and shown as cached in the summary.
locci check --no-cache # bypass cache, re-run everything
locci cache-clear # wipe the cache database
Secrets
Locci resolves secrets from your local .env file (project root) or shell environment.
Mark which secrets a task needs in locci.yml:
tasks:
my-task:
run: ["pytest", "tests/"]
required_secrets: ["STRIPE_API_KEY", "DATABASE_URL"]
At runtime, Locci reads .env, injects matched values into the task's environment, and masks them from all log output. If a secret is not found, the task is skipped with the category secret-required.
For GitHub Actions workflows, ${{ secrets.FOO }} expressions are automatically detected and translated to the corresponding required_secrets entry.
Remote cache (S3)
Share the task cache across machines or CI runners.
pip install "locci[s3]"
locci check --remote-cache s3://my-bucket/locci-cache
On cache-miss, Locci falls back to running locally and then pushes the result. On cache-hit, it pulls and restores without running.
⚠️ Security: Remote cache artifacts are not cryptographically signed. Only use shared S3 caches with teams you trust. See Security caveats.
GitHub Actions integration
Locci reads .github/workflows/*.yml automatically — no config needed. It translates each job step into a local task with the following logic:
run:steps → executed as shell commands.uses:steps (known setup actions) → translated to local equivalents:
| Action | Local equivalent |
|---|---|
actions/setup-python |
python3 -m pip install --upgrade pip |
actions/setup-node |
node --version (checks node is present) |
actions/setup-go |
go version |
actions/setup-java |
java -version |
actions/setup-dotnet |
dotnet --version |
ruby/setup-ruby |
ruby --version |
dtolnay/rust-toolchain |
cargo --version |
actions/cache |
no-op (Locci has its own cache) |
actions/checkout |
no-op (repo is already checked out) |
Any unknown uses: |
no-op (silently skipped) |
- Dangerous deploy/publish actions (ECS deploy, Terraform apply, PyPI publish, etc.) → blocked as
unsafe.
Matrix jobs: Only the first matrix leg runs locally. Additional legs are reported as remote-only in the summary.
Conditional steps: if: expressions are evaluated. github.event_name is treated as push during local runs.
Exit codes
| Code | Meaning |
|---|---|
0 |
All runnable tasks passed |
1 |
One or more runnable tasks failed |
2 |
All runnable tasks passed, but --strict-coverage was set and tasks were skipped |
3 |
Required host tools are missing (locci doctor for details) |
4 |
Invalid or missing config / bad CLI arguments |
Security caveats
Local safety heuristics are best-effort.
Locci identifies unsafe tasks using a keyword blocklist (deploy, publish, release, production, prod, upload). This is not a security boundary. A task that modifies production state without using these keywords will still execute locally. Use local_safe: false in locci.yml to explicitly block a task.
Remote cache supply chain risk.
When using --remote-cache s3://..., Locci pulls cache artifacts directly into your workspace. There is no cryptographic signature or authenticity verification on these artifacts. Anyone with write access to the S3 bucket could plant a malicious payload or falsify a test outcome. Only use shared remote caching with trusted teams.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file locci-0.1.1.tar.gz.
File metadata
- Download URL: locci-0.1.1.tar.gz
- Upload date:
- Size: 58.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f0c08a705838f605f6db2c0d5df2a7bf299fc91db49bbf95bec55c6375b09b8
|
|
| MD5 |
546364ae0b63f2b7e59e950d187f38ac
|
|
| BLAKE2b-256 |
f427876f9060f68a9238a3ef7c81221e3f458f889258e07578e0471c0c85d9ad
|
File details
Details for the file locci-0.1.1-py3-none-any.whl.
File metadata
- Download URL: locci-0.1.1-py3-none-any.whl
- Upload date:
- Size: 53.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d43321993aab7c790cee333702353ccc9151d91ffd0b8ec5b58c7b5fd4c12d1d
|
|
| MD5 |
705fefdbbaf5ef1a88e4d9848f239abe
|
|
| BLAKE2b-256 |
b5618ff3630ad28e0b01727ef26d06ce15c34c2e5f209eda5857af16a5ad6427
|