Back to the catalog

local-ci

Autonomously run CI/CD pipelines on your behalf. This gives Claude Code the ability to validate code in real target environments — different

Open source Repository Open in the app JSON README (API)

About

Autonomously run CI/CD pipelines on your behalf. This gives Claude Code the ability to validate code in real target environments — different runtimes, OS images, or with real services like databases

Details

Kind
Plugins
Topic
Cloud & DevOps
Publisher
mrpuls
Origin
marketplace
Category
ferramentas
Stars
3
Last push
2026-06-11T11:04:51Z
Repository state
ativo
Language
Go
License
MIT
Added
2026-08-30 01:48:58
Updated
2026-08-30 01:48:58
Origin id
mrpuls/local-ci/local-ci

README

# Local CI

Local CI is a tool that allows you to run CI/CD pipelines locally using Docker containers. It helps developers test and debug their CI pipelines without pushing to remote repositories.

## Features

- Run CI pipeline jobs locally using Docker
- Stages-based execution similar to GitLab CI
- Configuration using YAML format
- Global and job-specific environment variables
- Working directory customization
- Cache support for dependencies and build artifacts
- Automatic file copying with .gitignore support
- Real-time log streaming from containers
- Automatic container cleanup
- Stage-based pipeline execution
- Job-based pipeline execution
- Parallel job execution (all jobs at once, or per-stage) with a live status board
- Per-job `parallel: true` keyword for detaching individual jobs from the sequential chain
- Matrix builds: parametrize a job with `matrix:` to fan it out across variable combinations
- Services: sidecar containers (databases, caches) on a private per-job network with readiness gates — `services: [postgres:16]`
- Artifacts: pass build outputs from one job to the next with `artifacts: paths: [...]`
- DAG scheduling: `needs: [job]` starts a job the moment its dependencies pass instead of waiting for the stage barrier
- Per-job `timeout:` and `retry:` for slow or flaky jobs
- Templates and includes: factor common config into `.dot-prefixed` templates and pull shared files with `include:`
- Stage placeholders: splice an included file's stages into the main pipeline at a chosen position
- GitLab utils
- Bootstrap scripts
- Cleanup scripts (companion to bootstrap)
- Per-job bootstrap and cleanup scripts
- Web UI: live pipeline graph, ANSI-colored searchable logs, run control (env vars, per-stage/per-job runs, failed-job re-run), desktop notifications, and a built-in YAML editor with live lint — served from a single binary with `local-ci ui`
- Run history with git context (branch + commit per run), plus per-job duration trends and flaky-job detection; inspect from the UI or `local-ci runs` / `local-ci log`
- Debug shell: `local-ci shell <job>` drops you into the job's exact container environment — image, variables, workspace, cache mounts, and running services
- Watch mode: `local-ci run --watch` re-runs the pipeline on every file change
- Config linting (`local-ci validate`) and a `.gitlab-ci.yml` importer (`local-ci import gitlab`)
- Claude Code agent plugin

## Installation

### Prerequisites

- Docker must be installed and running
- Your user must have permissions to access the Docker daemon
- Verify installation with `docker --version`

### Homebrew (macOS / Linux)
```bash
brew install --cask MrPuls/local-ci/local-ci
```
Shell completions for bash, zsh, and fish are installed automatically.

### Go Install

Requires Go 1.26 or later ([download](https://golang.org/dl/)). The web UI build is
committed, so the installed binary includes `local-ci ui` with no extra tooling.
```bash
go install github.com/MrPuls/local-ci/cmd/local-ci@latest
```

### Manual

Download the latest binary for your platform (Linux, macOS, or Windows) from the
[releases page](https://github.com/MrPuls/local-ci/releases). The archives also
carry completion scripts (`completions/`) for bash, zsh, fish, and PowerShell;
or generate them on the fly with `local-ci completion <shell>`.

### Shell completions

Completions are context-aware: `local-ci shell <TAB>` lists the jobs defined in
your config, `-j`/`-s` complete job and stage names, `local-ci log <TAB>`
completes recent run ids (with their status), and `-c` offers the discovered
config files. Homebrew installs them for you; otherwise see
`local-ci completion --help`.

### Build from source

A `Makefile` wraps the common tasks (run `make help` for the full list). Building
the UI needs [Bun](https://bun.sh); the Go binary needs Go 1.26+.
```bash
make build      # build the web UI + the local-ci binary into ./bin
make install    # build the UI and `go install` the binary
```
After changing anything under `web/`, run `make web` and commit the regenerated
`internal/web/dist` so the embedded UI stays in sync.


## Usage

### Check Installation

```bash
local-ci --version
```

### Run a Pipeline

```bash
# Run using default .local-ci.yaml in current directory
local-ci run

# Run with a specific config file using --config/-c flag
local-ci run --config my-pipeline.yaml

# Run a specific job using --job/-j
local-ci run --job JobName

# Or to run multiple jobs
local-ci run --job jobName1,JobName2

# Run jobs from a specific stage using --stage/-s
local-ci run --stage stageName

# Or use multiple stages
local-ci run --stage stageName1,stageName2

# Run all jobs in parallel with --parallel/-p
local-ci run --parallel

# Or run stages in order, with jobs inside each stage in parallel
local-ci run --parallel-stages

# Clone/update the repository and run it's local-ci.yaml with --remote/-r
local-ci run --remote <repository_url>

# Pass additional environment variables with --env/-e
local-ci run --env NEW_VAR=var_value,SECOND_VAR=new_value
```

When you don't pass `-c/--config`, `run` scans the working directory for config
files — the canonical `.local-ci.yaml`/`.local-ci.yml` plus any
`<name>.local-ci.yaml` / `<name>-local-ci.yaml` / `<name>_local-ci.yaml`
variant — and asks which one to load (Enter picks the first). Non-interactive
sessions never block: a single discovered file is used as-is, anything else
falls back to `.local-ci.yaml`.

### Developer loop

```bash
# Re-run the pipeline on every file change (Ctrl-C to stop)
local-ci run --watch

# Drop into a job's exact container environment to debug it from the inside:
# same image, variables, workdir, cache mounts, copied workspace — and its
# services running on the job network
local-ci shell Test

# Lint the config without running anything (exit 1 when invalid — git-hook friendly)
local-ci validate

# Convert an existing GitLab CI config (prints notes for anything that can't carry over)
local-ci import gitlab
```

### Web UI

`local-ci ui` serves the whole web app — its UI **and** API — from this single
binary, then opens it in your browser. No separate dev server or token to manage.

```bash
# Serve the UI for the project in the current directory and open a browser
local-ci ui

# Bind a specific port and don't auto-open a browser
local-ci ui --port 8080 --no-open

# Use a non-default config file
local-ci ui --config my-pipeline.yaml
```

It binds loopback only (`127.0.0.1`) and shows the configured pipeline as a live
graph: trigger and cancel runs, watch job status update in real time, stream
logs, and browse run history — all backed by the same engine as `local-ci run`.

On load the UI scans the project directory for config files (same patterns as
`run`) and asks which one to drive the session; switch any time via the `FILE:`
chip in the top bar. The **EDITOR** tab is a built-in YAML editor with syntax
highlighting, live lint (undefined stages, unknown `needs` targets, missing
fields — flagged before you save), validation feedback, a diff preview before
discarding edits, and a live pipeline graph — `Ctrl+S` writes to disk.

The pipeline view exposes the full trigger surface: pick a run mode, set env
vars, run a single stage from its column header, or a single job from the
inspector (failed jobs get a one-click re-run). Logs render ANSI colors and
are searchable. History shows each run's git context (`branch@sha`) and a
JOB_TRENDS panel: per-job duration sparklines, pass rates, and an
INTERMITTENT flag for jobs that flip between pass and fail. The bell in the
top bar enables desktop notifications when a run finishes in a hidden tab.

> For **frontend development** against a hot-reloading dev server, use
> `local-ci serve` (the API-only backend) together with the Vite dev server —
> see [web/README.md](web/README.md).

### Inspecting past runs

Every run (CLI or UI) is recorded to a local history store.

```bash
# List recent runs for the current project (newest first)
local-ci runs

# List runs across all projects, capping the count
local-ci runs --all --limit 50

# Show one run's per-job breakdown
local-ci runs <run-id>

# Print a recorded run's logs — all jobs, or one job
local-ci log <run-id>
local-ci log <run-id> --job Build
local-ci log <run-id> --job pipeline   # run-level diagnostics
```

### Command reference

| Command | Description | Flags |
|---|---|---|
| `run` | Run the pipeline | `-c/--config`, `-j/--job`, `-s/--stage`, `-r/--remote`, `-e/--env`, `-p/--parallel`, `--parallel-stages`, `-w/--watch`, `--no-record` |
| `shell <job>` | Open an interactive shell in the job's container environment (services included) | `-c/--config`, `-v/--verbose` |
| `validate [file]` | Lint a config without running it (exit 1 when invalid) | `-c/--config` |
| `import gitlab [file]` | Convert a `.gitlab-ci.yml` into a local-ci config | `-o/--output` (default `.local-ci.yaml`, `-` for stdout), `--force` |
| `runs [run-id]` | List recorded runs, or show one run's details | `-a/--all`, `-n/--limit` (default 20) |
| `log <run-id>` | Print a recorded run's logs | `-j/--job` (use `pipeline` for diagnostics) |
| `ui` | Serve the embedded web UI **and** API from one binary, then open a browser | `--host` (default `127.0.0.1`), `--port` (default `4123`), `-c/--config`, `--no-open` |
| `serve` | Run the API-only backend (for the web dev server or a future desktop shell) | `--host` (default `127.0.0.1`), `--port` (default ephemeral), `--token` (default random), `-c/--config` |

Global: `local-ci --version`, `local-ci --help`, `local-ci <command> --help`.

## Quick Start

1. Start Docker

2. Create a `.local-ci.yaml` file in your project root:

```yaml
stages:
  - build
  - test

variables:
  GLOBAL_VAR: global_value

Build:
  stage: build
  image: golang:1.21
  variables:
    GO_FLAGS: "-v"
  script:
    - echo "Building application..."
    - go build $GO_FLAGS
  cache:
    key: go-build-cache
    paths:
      - .go/
      - build/

Test:
  stage: test
  image: golang:1.21
  script:
    - echo "Testing with global var: $GLOBAL_VAR"
    - go test ./...
  cache:
    key: go-build-cache
    paths:
      - .go/
```

3. Run the pipeline:

```bash
local-ci run
```

## YAML Configuration

### Basic Structure

```yaml
# Define stages and their order
stages:
  - build
  - test
  - deploy

# Global variables (available to all jobs)
variables:
  GLOBAL_KEY: global_value

# Job definitions
job_name:
  stage: build    # Must match one of the defined stages
  image: image_name
  workdir: /path   # Optional
  variables:       # Job-specific variables (override globals)
    KEY: value
  script:
    - command1
    - command2
  cache:           # Optional cache configuration
    key: cache-key
    paths:
      - path/to/cache
      - another/path
```

## Claude Code Agent

Local CI ships as a [Claude Code](https://claude.ai/code) plugin. Once installed, Claude Code can autonomously write pipeline configs, run them, and validate your code in real Docker environments.

Install the plugin

```bash
/plugin marketplace add MrPuls/local-ci

/plugin install local-ci@MrPuls-local-ci
```

See the [Technical Reference](docs/tech-reference.md#claude-code-agent) for details.

## Documentation

- [YAML Configuration Reference](docs/yaml-reference.md)
- [Technical Reference](docs/tech-reference.md)
- [Claude Code Agent](docs/agent.md)

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

[MIT License](LICENSE)

More