repolith-engine 0.0.4

Declarative orchestrator for Rust toolchains spread across multiple sibling git repositories.
Documentation

repolith

Declarative orchestrator for Rust toolchains spread across multiple sibling git repositories.

โšก Parallel ยท ๐Ÿ›‘ Cancellation-aware ยท ๐Ÿ’พ Cache-first

CI License Rust Version PRs welcome

repolith reads one repolith.toml describing remote repositories and the actions to run against them โ€” git clone, cargo install, more in M2 โ€” then executes the plan in parallel layers, with content-addressed caching so untouched work never re-runs and a shared CancellationToken so Ctrl-C cleanly aborts every in-flight subprocess.

What it looks like

Given a manifest:

[orchestrator]
schema_version = "0.1"
name = "my-stack"

[[node]]
id = "shared-types"
git = "https://github.com/example-org/shared-types"
path = "../libs/shared-types"
  [[node.action]]
  kind = "git-clone"

[[node]]
id = "migration-tool"
git = "https://github.com/example-org/migration-tool"
path = "../tools/migration-tool"
  [[node.action]]
  kind = "git-clone"
  [[node.action]]
  kind = "cargo-install"
  crate = "migrate"
  install_to = "~/.local/bin"

You preview, then sync:

$ repolith status
+-------------------------------+--------+---------------+
| Action                        | Status | Reason        |
+===============================+========+===============+
| shared-types::git-clone::0    | stale  | NoCachedBuild |
| migration-tool::git-clone::0  | stale  | NoCachedBuild |
| migration-tool::cargo-install | stale  | NoCachedBuild |
+-------------------------------+--------+---------------+

$ repolith sync --dry-run --explain
โ€ข shared-types::git-clone::0: NoCachedBuild
โ€ข migration-tool::git-clone::0: NoCachedBuild
โ€ข migration-tool::cargo-install::1: NoCachedBuild
dry-run: 3 action(s) would run

$ repolith sync
OK   shared-types::git-clone::0 (55 ms)
OK   migration-tool::git-clone::0 (188 ms)
OK   migration-tool::cargo-install::1 (4.2 s)

$ repolith sync
up to date โ€” 0 stale actions

The second sync is a no-op โ€” the SQLite cache holds last-run input hashes per action, so nothing re-runs unless an upstream HEAD or a cargo feature actually changed.

Why use it

  • One declarative file. Everything your stack needs to bootstrap, in repolith.toml. No bash glue, no per-machine README dance.
  • Parallel by default. tokio::FuturesUnordered + Semaphore cap concurrency at --jobs N (default = num_cpus). Layer N+1 starts only when layer N settles โ€” typed dependencies, no race conditions.
  • Cancels cleanly. A shared CancellationToken plumbed through every action's Ctx. First failure in --fail-fast (default) cancels in-flight peers; --keep-going lets the layer settle then halts. On Unix the subprocess process group is signalled (SIGTERM โ†’ grace โ†’ SIGKILL) so cargo's rustc / linker grandchildren get reaped too.
  • Cache-first. Every successful build writes a BuildEvent to a SQLite store (WAL) keyed by content-addressed input hashes. Re-runs are near-instant when nothing changed.
  • Hardened argv. URLs validated against a scheme allowlist with nested-userinfo / host / path-segment leading-dash checks; -- argv separator before every user URL as defense in depth; crate names + feature flags rejected if they could break cargo's --features list.

What it is NOT

The negative scope is fixed and will not evolve:

  • Not a CI runner โ€” no distributed execution, no remote workers.
  • Not a toolchain manager โ€” rustup is fine.
  • Not a package manager โ€” cargo is fine.
  • Not a process supervisor โ€” systemd / launchd / docker compose are fine; repolith reads heartbeats, doesn't write them.
  • Not a monorepo tool โ€” cargo workspaces already covers single-repo workspace publishing.
  • Not a hermetic build system โ€” hermeticity is opt-in per action, not the default.

Quick start

# 1. Clone repolith
git clone https://github.com/anatta-rs/repolith && cd repolith

# 2. Build the binary
cargo build --release
cp target/release/repolith ~/.local/bin/   # or any dir on $PATH

# 3. Drop the example into your stack root, then edit it
mkdir -p ../my-stack && cd ../my-stack
cp ../repolith/repolith.toml.example ./repolith.toml
$EDITOR repolith.toml

# 4. Preview what would happen
repolith sync --dry-run --explain

# 5. Go
repolith sync

repolith status prints a cache hit/miss table without running anything. repolith sync -k keeps a layer running after a failure (useful for surfacing every failure of a layer in one pass).

See repolith.toml.example for a full annotated manifest.

Architecture

5 crates, layered execution with FuturesUnordered + CancellationToken + Semaphore. Full diagram + the FailFast / KeepGoing sequence diagrams

Crate Purpose
repolith-core Types, traits (Action, Cache), manifest parser, layered Plan.
repolith-cache SqliteCache (rusqlite, bundled, WAL).
repolith-engine Async Orchestrator with cancellation + semaphore.
repolith-actions GitClone (feature git), CargoInstall (feature cargo).
repolith-cli repolith sync / status โ€” the binary you run.

Status

v0.0.4 shipped. 5 crates, 2 builtin actions, parallel layered execution with cancellation, SQLite cache (WAL), URL-injection hardening, process-group cancel propagation, node-id path-traversal validator. Full test suite under cargo test --workspace --all-features (80+ tests at last count). See CHANGELOG.md for the per-release breakdown (three pre-public audit cycles between v0.0.1 and v0.0.4 closed every must-fix item surfaced).

CI status. GitHub Actions runs are temporarily paused while the upstream Actions billing is being sorted out โ€” the workflow in .github/workflows/ci.yml is the canonical gate (cargo fmt --check, cargo clippy --workspace --all-targets --all-features -- -D warnings, cargo test --workspace --all-features, cargo doc with RUSTDOCFLAGS=-D warnings). Run it locally before opening a PR.

Roadmap

  • M2 โ€” federation kind = "repolith" (orchestrator-of-orchestrators), Neo4j cache backend, docker action.
  • M3 โ€” watch mode (re-plan on file change), template_apply action driving AttachedEntry::Outbound.

Security

See SECURITY.md for the threat model, the env-allowlist policy, and the GitHub Security Advisories private-reporting form for vulnerability disclosure.

Contributing

PRs welcome. See CONTRIBUTING.md for the dev setup, local CI gates, and worked recipes for adding a new action or a new cache backend.

License

Dual-licensed under either of:

at your option.