README
¶
SYKLI
CI pipelines in your language. No YAML. No DSL. Just code.
Go · Rust · TypeScript · Elixir · Python
Getting Started · Installation · SDK Examples · CLI Reference · Documentation
Warning Sykli is experimental software in active development. APIs may change between releases. We're building in public and welcome feedback, but please evaluate carefully before using in production.
What is Sykli?
Sykli is a CI orchestrator where your pipeline configuration is real code in your language of choice. No YAML, no proprietary DSL — just a program that defines tasks and their dependencies.
// sykli.go — this IS your CI config
package main
import sykli "github.com/yairfalse/sykli/sdk/go"
func main() {
s := sykli.New()
s.Task("test").Run("go test ./...").Inputs("**/*.go")
s.Task("build").Run("go build -o app").After("test")
s.Emit()
}
Run sykli and it executes your tasks in parallel, with caching, retries, and container support.
Why Code Instead of YAML?
| YAML Config | Sykli |
|---|---|
| String interpolation hacks | Real variables and functions |
| Copy-paste for reuse | Templates and composition |
| Runtime errors | Compile-time type checking |
| Vendor lock-in | Standard language tooling |
| Limited logic | Full programming language |
Features
| Feature | Description |
|---|---|
| Multi-language SDKs | Go, Rust, TypeScript, Elixir, Python |
| Parallel Execution | Tasks run concurrently by dependency level |
| Content-addressed Caching | Skip unchanged tasks automatically |
| Container Support | Docker containers with volume mounts |
| Node Placement | Route tasks to nodes with specific labels (GPU, etc.) |
| Mesh Distribution | Spread work across machines on your network |
| AI-Native Context | Structured occurrence reports for AI assistants |
| Cross-platform Verify | Re-run tasks on different OS/arch via mesh |
| Delta Builds | Run only tasks affected by git changes |
| Watch Mode | Re-run on file changes |
| Matrix Builds | Test across multiple configurations |
| Gate Tasks | Approval points that pause the pipeline |
| Capability Dependencies | Tasks declare what they provide and need |
Installation
Binary (Recommended)
# macOS & Linux
curl -fsSL https://raw.githubusercontent.com/yairfalse/sykli/main/install.sh | bash
This installs a prebuilt binary to ~/.local/bin/sykli.
Manual Download
Download from GitHub Releases:
| Platform | Binary |
|---|---|
| macOS Apple Silicon | sykli-macos-aarch64 |
| macOS Intel | sykli-macos-x86_64 |
| Linux x86_64 | sykli-linux-x86_64 |
| Linux ARM64 | sykli-linux-aarch64 |
Build from Source
git clone https://github.com/yairfalse/sykli.git
cd sykli/core
mix deps.get
mix escript.build
sudo mv sykli /usr/local/bin/
Requires Elixir 1.14+.
Quick Start
1. Initialize
sykli init # Auto-detects Go, Rust, or Elixir projects
Or create the SDK file manually — see SDK Setup below.
2. Run
sykli
── Level with 1 task(s) ──
▶ test cargo test
✓ test 124ms
── Level with 1 task(s) ──
▶ build cargo build --release
✓ build 1.2s
test ✓ → build ✓
✓ 2 passed in 1.4s
SDK Setup
Sykli detects your pipeline by looking for a sykli.* file in the project root. Pick your language:
Go
go get github.com/yairfalse/sykli/sdk/go@latest
Create sykli.go in your project root:
package main
import sykli "github.com/yairfalse/sykli/sdk/go"
func main() {
s := sykli.New()
s.Task("test").Run("go test ./...").Inputs("**/*.go", "go.mod")
s.Task("build").Run("go build -o app").After("test")
s.Emit()
}
Rust
Create sykli.rs in your project root, and add the dependency and binary target to your Cargo.toml:
# Add to your existing Cargo.toml (or create one)
[dependencies]
sykli = "0.5"
[[bin]]
name = "sykli"
path = "sykli.rs"
If you use a Cargo workspace, add the [dependencies] and [[bin]] sections to the root Cargo.toml (not a subdirectory).
Then create sykli.rs:
use sykli::Pipeline;
fn main() {
let mut p = Pipeline::new();
p.task("test").run("cargo test").inputs(&["src/**/*.rs", "Cargo.toml"]);
p.task("build").run("cargo build --release").after(&["test"]);
p.emit();
}
TypeScript
npm install sykli
Create sykli.ts in your project root:
import { Pipeline } from 'sykli';
const p = new Pipeline();
p.task('test').run('npm test');
p.task('build').run('npm run build').after('test');
p.emit();
Elixir
# Add to mix.exs deps
{:sykli_sdk, "~> 0.5.1"}
Create sykli.exs in your project root:
Sykli.pipeline do
task "test" do
run "mix test"
inputs ["lib/**/*.ex", "test/**/*.exs", "mix.exs"]
end
task "build" do
run "mix compile --warnings-as-errors"
after_ ["test"]
end
end
Python
pip install sykli
Create sykli.py in your project root:
from sykli import Pipeline
p = Pipeline()
p.task("test").run("pytest")
p.task("build").run("python -m build").after("test")
p.emit()
Important: The
sykli.*file must be in the project root directory — not in a subdirectory. Sykli searches the current directory (or the path you pass) for the SDK file.
SDK Examples
Caching with Inputs
Skip tasks when input files haven't changed:
s.Task("test").
Run("go test ./...").
Inputs("**/*.go", "go.mod", "go.sum")
⊙ test CACHED (no input changes)
Container Execution
Run tasks in Docker containers:
s := sykli.New()
src := s.Dir(".")
cache := s.Cache("go-mod")
s.Task("test").
Container("golang:1.22").
Mount(src, "/src").
MountCache(cache, "/go/pkg/mod").
Workdir("/src").
Run("go test ./...")
Templates (DRY)
Define configuration once, reuse everywhere:
s := sykli.New()
src := s.Dir(".")
golang := s.Template("golang").
Container("golang:1.22").
Mount(src, "/src").
Workdir("/src")
s.Task("test").From(golang).Run("go test ./...")
s.Task("lint").From(golang).Run("go vet ./...")
s.Task("build").From(golang).Run("go build -o app")
Node Placement
Route tasks to nodes with specific capabilities:
s.Task("train").
Requires("gpu").
Run("python train.py")
s.Task("build-arm").
Requires("arm64", "docker").
Run("docker buildx build --platform=linux/arm64")
Nodes expose automatic labels (darwin, linux, arm64, amd64, docker) plus user-defined labels:
SYKLI_LABELS=gpu,team:ml sykli daemon start
Capability Dependencies
Tasks declare what they provide and what they need:
s.Task("build").
Run("go build -o app").
Provides("binary", "./app")
s.Task("deploy").
Run("./deploy.sh").
Needs("binary") // auto-ordered after build
Gate Tasks
Approval points that pause the pipeline:
s.Gate("approve-deploy").
Message("Deploy to production?").
Strategy("prompt"). // interactive TTY
Timeout("1h")
s.Task("deploy").
Run("./deploy.sh").
After("approve-deploy")
Conditional Execution
s.Task("deploy").
Run("./deploy.sh").
When("branch == 'main'").
Secret("DEPLOY_TOKEN")
Matrix Builds
Test across multiple configurations:
s.Task("test").
Run("go test ./...").
Matrix("go", "1.21", "1.22", "1.23")
Expands to: test[go=1.21], test[go=1.22], test[go=1.23]
Cross-platform Verification
Verify tasks pass on different OS/architecture:
s.Task("build").
Run("go build -o app").
Verify("cross_platform") // re-run on different OS/arch
sykli verify # verify latest run on mesh
sykli verify --dry-run # show what would be verified
Parallel Groups
checks := s.Parallel("checks",
s.Task("lint").Run("go vet ./..."),
s.Task("test").Run("go test ./..."),
s.Task("fmt").Run("gofmt -l ."),
)
s.Task("build").After(checks)
Artifact Passing
build := s.Task("build").
Run("go build -o /out/app").
Output("binary", "/out/app")
s.Task("deploy").
InputFrom(build, "binary", "/app/bin").
Run("./deploy.sh /app/bin")
CLI Reference
Running Pipelines
sykli # Run all tasks
sykli --filter=test # Run tasks matching pattern
sykli --timeout=5m # Per-task timeout (default: 5m)
sykli --timeout 30s # Also accepts space-separated
sykli --mesh # Distribute across mesh nodes
sykli --target=k8s # Run on Kubernetes
Commands
sykli init # Create sykli file (auto-detects language)
sykli init --rust # Force specific language
sykli validate # Check pipeline without running
sykli validate --json # Machine-readable validation output
sykli delta # Run only git-affected tasks
sykli delta --from=main # Compare against branch
sykli delta --dry-run # Show what would run
sykli watch # Re-run on file changes
sykli graph # Mermaid diagram of task graph
sykli graph --dot # Graphviz format
sykli verify # Cross-platform verification via mesh
sykli verify --dry-run --json # Preview verification plan
sykli explain # Show last run occurrence (AI-readable)
sykli explain --json # Raw occurrence JSON
sykli report # Show last run summary
sykli report --json # Machine-readable report
sykli history # List recent runs
sykli context # Generate .sykli/context.json
sykli cache stats # Show cache statistics
sykli cache clean # Clear cache
sykli daemon start # Start mesh node
sykli daemon start --labels=gpu,docker
sykli daemon stop # Stop mesh node
sykli daemon status # Show mesh status
Timeout Formats
sykli --timeout=0 # No timeout (infinity)
sykli --timeout=300 # Milliseconds
sykli --timeout=10s # Seconds
sykli --timeout=5m # Minutes (default)
sykli --timeout=2h # Hours
sykli --timeout=1d # Days
How It Works
┌─────────────┐ ┌──────────────┐ ┌────────────┐
│ sykli.* │────▶│ JSON Graph │────▶│ Engine │
│ (SDK) │ │ (stdout) │ │ (Elixir) │
└─────────────┘ └──────────────┘ └────────────┘
│
┌──────────────────────────┼──────────────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ lint │ │ test │ │ build │
│ parallel │ │ parallel │ │ depends │
└──────────┘ └──────────┘ └──────────┘
- Detect: Sykli finds
sykli.go,sykli.rs,sykli.ts,sykli.exs, orsykli.pyin the current directory - Emit: Runs your SDK file with
--emitto get a JSON task graph on stdout - Execute: Runs tasks in parallel by dependency level, with caching and retries
- Save: Writes run history to
.sykli/runs/and occurrence context to.sykli/
Why Elixir? The BEAM VM's distribution primitives let the same engine run locally or across a cluster. Your laptop and your CI farm run identical code.
AI Context
Every sykli run generates structured context that AI assistants can read directly — no log parsing needed.
Occurrence Reports
After each run, .sykli/occurrence.json contains a structured occurrence with:
- Error block —
what_failed,why_it_matters,possible_causes,suggested_fix - Reasoning block — root cause analysis with file-level correlation
- History block — per-task steps, durations, and cross-run outcomes
- CI data — git context, task details, dependency graph
sykli explain # Human-readable summary
sykli explain --json # Raw occurrence JSON for tooling
Three-Tier Persistence
Occurrences are stored at three levels for different access patterns:
| Tier | Path | Speed | Consumer |
|---|---|---|---|
| Cold | .sykli/occurrence.json |
Always available | Any tool, cat, AI |
| Warm | .sykli/occurrences/*.etf |
Fast BEAM reload | sykli explain, daemon |
| Hot | ETS (in-memory) | Instant | sykli explain when daemon runs |
When the daemon is running, the occurrence store accumulates history in ETS. This enables cross-run queries like regression detection and recent outcome patterns — without reading files.
Context for AI Assistants
sykli context # Generate .sykli/context.json
The .sykli/ directory is designed as the AI's memory of your project:
.sykli/
├── occurrence.json # Latest run (FALSE Protocol format)
├── occurrences/ # ETF archive (last 50 runs)
│ ├── run_abc123.etf
│ └── run_def456.etf
├── context.json # Pipeline structure + health
└── runs/ # Run history (lean format)
Documentation
- ADR Index — Architectural Decision Records
- SDK API Design — SDK philosophy
- Mesh Networking — Distributed execution
- Node Placement — Label-based routing
Project Status
Current version: v0.5.1
| Component | Status |
|---|---|
| Core Engine | Stable |
| Go SDK | Stable |
| Rust SDK | Stable |
| TypeScript SDK | Stable |
| Elixir SDK | Stable |
| Python SDK | Beta |
| Local Execution | Stable |
| Container Tasks | Stable |
| Mesh Distribution | Beta |
| AI Context (Occurrences) | Stable |
| Cross-platform Verify | Beta |
| K8s Target | Beta |
| Gate Tasks | Beta |
| Capability Dependencies | Beta |
| Remote Cache | Planned |
Contributing
Sykli is open source under the MIT license. Contributions welcome!
cd core && mix test # Run tests (770+ tests)
mix escript.build # Build binary
test/blackbox/run.sh # Run black-box test suite
Naming
Sykli (Finnish: "cycle") — Part of a Finnish tool naming theme for infrastructure tools.
Get Started · GitHub · Issues
Built in Berlin. Powered by BEAM. No YAML was harmed.