Content-addressed evaluator for declared work graphs, with delta selection, caching, and repository-bound…
sykli
以下摘录自该仓库的 README(片段) · 在 GitHub 读完整 README →
sykli — Finnish for cycle
Run your checks. Reuse the work. Explain the result.
Demo ·
Quick start ·
How it works ·
CI ·
Agents ·
Commands
Sykli is one binary that turns your repository's checks into a **declared
graph**. It runs the graph in order, **reuses** any result whose inputs haven't
changed, and writes a **receipt** that ties every outcome to the exact tree it
ran against. It works the same on your laptop, in CI and for a coding agent.
Keep Cargo, npm, Go and your shell scripts. Sykli doesn't replace your tools. It
decides which of them need to run and keeps a verifiable record of what did.
See it in 30 seconds
Two tasks, lint then test, each reading one script. Real output, hashes shortened:
Once the code changes, the old receipt no longer verifies. The whole graph is
below; copy it and try this yourself.
Start in your repository
Install from source with Rust 1.85 or newer:
Then, in an existing Cargo, npm or Go repository:
init creates .sykli/ for local state and adds it to .gitignore. Review the
inputs it declares, especially configuration and fixtures, and declare files you
add later. Task execution needs Git, a POSIX sh and your project's own
toolchain. On Windows, Git for Windows supplies sh.
> [!NOTE]
> This README describes main. For a reproducible install, replace
> --branch main with --rev COMMIT. Tagged downloads will be listed on the
> releases page once
> published, and install.sh verifies their checksums. Installing
> Sykli does not install your build tools.
How it works
It comes down to three things:
| | What it is | Where it lives |
|---|---|---|
| **Contract** | The work you declare: tasks, commands, the files each one reads, and what runs after what. | sykli.json, pinned by sykli.lock |
| **Receipt** | One evaluation: commands, outcomes, output digests, and which results were reused. | .sykli/receipts/ (and wherever you redirect --json) |
| **Verify** | A check that a receipt is consistent with the tree and contract in front of you. | sykli verify |
**Reuse is earned, not assumed.** A task's cache key covers its declaration,
the contents and execute bits of its declared inputs, the runtime fingerprint,
digests of inherited environment values, and the cache keys of every task it
runs after. A downstream task never reuses a pass recorded against upstream
outputs it did not see, and a matching entry must validate before it is used.
In a Cargo graph the runtime fingerprint also covers the Rust toolchain the
task shell resolves (rustc -vV, cargo -V), so a pass recorded under one
compiler is not reused under another.
A graph you can try
In a scratch Git repository:
inputs names the files a task reads. after makes test wait for lint and
binds its cache key to that dependency. Independent tasks run in parallel.
Every path a task declares (inputs, outputs, workdir) is relative to the
repository and stays inside it. Absolute paths and .. are refused when the
contract is validated, before anything runs, so a receipt is always a claim
about the repository it sits in, even when the contract is kept
outside it. sykli validate
checks a contract without running it.
What a task sees when it runs
Tasks run under sh -c with no stdin. They receive PATH, HOME and TMPDIR,
plus declared env values and named inherit variables. Inherited values reach
the task, but only their digests reach the receipt, where they count toward the
task's identity. A declared value may name ${worktree_cache}, a directory of
the worktree's own
(one build directory per worktree). Task
output is captured, so commands are responsible for what they print. Sykli runs
local commands with your permissions.
Ask before you run
plan --explain tells you what a run would do and what the cache can supply,
without running anything:
It reads sykli.json by default; an explicit JSON contract path selects another
graph. It runs no task or Rust emitter, restores no outputs, and writes no cache
entries or receipts.
| Cache state | What it tells you |
|---|---|
| available | Cached evidence and artifacts validate; a run can attempt reuse. |
| missing | No entry exists for the current content key. |
| invalid | An entry exists, but its evidence or artifacts failed validation. |
| deferred | A dependency needs execution, restoration or error resolution first. |
| input_error | A declared input cannot currently be evaluated. |
**Undeclared files are flagged.** Explain warns about changed files that no task
lists as an input, even when every task is already selected. It checks staged,
unstaged and untracked non-ignored files, and --base origin/main adds