Skip to main content

A fast, local-first CI engine.

Project description

Locci — Local CI

PyPI version Python License: MIT

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

  • 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:

  1. Auto-detected from your repo (GitHub Actions workflows, pyproject.toml, package.json, go.mod, Cargo.toml, …).
  2. Filtered by --scope (prefix match on task name).
  3. Filtered by --since (only tasks whose input_globs overlap changed files).
  4. Safety policy applied — unsafe tasks are skipped unless --allow-unsafe is 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:

  1. LOCCI_OLD_SHA environment variable (set by the git hook).
  2. merge-base of HEAD and the tracked upstream branch.
  3. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

locci-0.1.1.tar.gz (58.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

locci-0.1.1-py3-none-any.whl (53.8 kB view details)

Uploaded Python 3

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

Hashes for locci-0.1.1.tar.gz
Algorithm Hash digest
SHA256 7f0c08a705838f605f6db2c0d5df2a7bf299fc91db49bbf95bec55c6375b09b8
MD5 546364ae0b63f2b7e59e950d187f38ac
BLAKE2b-256 f427876f9060f68a9238a3ef7c81221e3f458f889258e07578e0471c0c85d9ad

See more details on using hashes here.

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

Hashes for locci-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d43321993aab7c790cee333702353ccc9151d91ffd0b8ec5b58c7b5fd4c12d1d
MD5 705fefdbbaf5ef1a88e4d9848f239abe
BLAKE2b-256 b5618ff3630ad28e0b01727ef26d06ce15c34c2e5f209eda5857af16a5ad6427

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page