sloff

module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 12, 2026 License: MIT

README ΒΆ

sloff πŸ¦₯

A fingerprint-aware codegen orchestrator for polyglot monorepos. Skips work when inputs haven't changed β€” and never lies about it.

sloff runs your code generators (proto / SQL / mock / GraphQL / etc.) and fingerprints their outputs in git so devs and CI skip re-generation when nothing has changed. Fingerprint hits are validated by comparing both inputs and the actual output files against the recorded state β€” so even when the fingerprint looks valid, a drifted output triggers re-generation rather than a stale skip.

Features

  • Output-comparison fingerprint hits. A hit requires the recorded input_hash and the on-disk output files to match. Drifted outputs (manual edits, formatter runs, partial checkouts) are re-generated, never silently skipped.
  • OS-portable fingerprints. Fingerprints are deterministic YAML committed to git. A record built on macOS works on Linux CI without rebuilds β€” tool versions are captured as logical strings, never as OS-specific binary hashes.
  • Reads your existing toolchain. No replacement for aqua / mise / nix / pnpm / go.mod. Tool versions come from the runtime binary's --version, lockfiles, or repo source β€” whichever is the actual source of truth.
  • Auto-derived dependencies. Task ordering is computed from inputs / outputs glob intersections. There is no manual depends: field to keep in sync.
  • Single Go binary. No runtime dependencies, no daemon, no language ecosystem to install.
  • Codegen-only by design. Build / test / lint stay in your existing tooling (Make, npm scripts, etc.) β€” sloff does one thing.

Install

go install github.com/izumin5210/sloff/cmd/sloff@latest

Quick start

Place a sloff.yml in any directory containing your codegen inputs:

tools:
  buf:
    exec: ["buf", "--version"]
  protoc-gen-go:
    exec: ["protoc-gen-go", "--version"]
    extract: 'v[0-9]+\.[0-9]+\.[0-9]+'

commands:
  - name: protoc-gen-go
    cmd: buf generate
    inputs: ["**/*.proto", "buf.gen.yaml", "buf.yaml", "buf.lock"]
    outputs: ["**/*.pb.go", "**/*.connect.go"]
    tools: [buf, protoc-gen-go]

Then from anywhere in the repo:

sloff run

sloff run discovers every sloff.yml, builds a DAG from inputs / outputs overlap, and either skips or re-runs each task based on fingerprint lookup.

Tool resolvers

tools: entries dispatch to one of three resolvers based on shape:

script β€” for prebuilt binaries

For anything with a --version command: aqua / mise / nix-distributed CLIs, go tool-managed bins, npm bins via pnpm exec, etc. The runtime binary's stdout is the version source of truth.

tools:
  buf:
    exec: ["buf", "--version"]
  protoc-gen-go:
    exec: ["protoc-gen-go", "--version"]
    extract: 'v[0-9]+\.[0-9]+\.[0-9]+'
go-local β€” for repo-internal Go CLIs

For codegen tools you maintain in this repo as Go cmd/... packages, run via go run:

tools:
  protoc-gen-foo:
    go-local: ./cmd/protoc-gen-foo

Internal .go source files contribute to the task's effective inputs (so source edits invalidate); external Go module versions come from go.sum.

pnpm-local β€” for pnpm workspace internal packages

For codegen tools you maintain as pnpm workspace packages:

tools:
  codegen:
    pnpm-local: "@org/codegen"

commands:
  - name: gen
    cmd: ["sh", "-c", "pnpm --filter @org/codegen build && pnpm exec my-codegen"]
    inputs: ["**/*.proto"]
    outputs: ["**/*.pb.ts"]
    tools: [codegen]

git-tracked files in the workspace package (and transitive workspace deps) contribute to inputs; external npm dep versions come from pnpm-lock.yaml. Build steps stay in the task cmd.

Fingerprint storage

By default sloff persists records to .sloff/fingerprints/ under the repo root and commits them to git (ADR-0003). For monorepos where git-noise / clone-size pressure starts mattering, switch to the DynamoDB backend via .sloff/config.yml:

# .sloff/config.yml
fingerprint:
  backend: dynamodb
  dynamodb:
    table: sloff-fingerprints # required
    region: us-east-1         # optional; falls back to AWS_REGION / shared config
    # endpoint: ""            # optional; emulator URL
    # expires_after_days: 0   # optional; >0 enables DynamoDB TTL-based GC

Credentials are resolved through the aws-sdk-go-v2 default chain (env vars / ~/.aws/credentials / IRSA / IMDS), so the config file carries no secrets and is safe to commit. The DynamoDB backend is fronted by a transparent $XDG_CACHE_HOME-rooted disk cache so warm lookups stay local; see Storage: DynamoDB for the full design (schema, caching, consistency, cost).

sloff does not auto-create the DynamoDB table β€” provision it once with your IaC of choice.

Table provisioning (AWS CLI / Terraform)
aws dynamodb create-table \
  --table-name sloff-fingerprints \
  --attribute-definitions \
      AttributeName=pk,AttributeType=S \
      AttributeName=sk,AttributeType=S \
  --key-schema \
      AttributeName=pk,KeyType=HASH \
      AttributeName=sk,KeyType=RANGE \
  --billing-mode PAY_PER_REQUEST
resource "aws_dynamodb_table" "sloff_fingerprints" {
  name         = "sloff-fingerprints"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "pk"
  range_key    = "sk"

  attribute { name = "pk"; type = "S" }
  attribute { name = "sk"; type = "S" }

  # Required only when expires_after_days > 0 in .sloff/config.yml.
  ttl {
    attribute_name = "expires_at"
    enabled        = true
  }
}
Required IAM actions
{
  "Effect": "Allow",
  "Action": [
    "dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:DeleteItem",
    "dynamodb:Query", "dynamodb:Scan",
    "dynamodb:BatchGetItem", "dynamodb:BatchWriteItem",
    "dynamodb:DescribeTable"
  ],
  "Resource": "arn:aws:dynamodb:<region>:<account>:table/sloff-fingerprints"
}

When to use sloff (vs alternatives)

sloff is well-suited when:

  • You have a polyglot codegen pipeline (Go + JS/TS + external prebuilt binaries) and want shared fingerprint store across devs and CI.
  • You want to keep your existing toolchain (aqua / mise / nix / pnpm / go.mod) instead of migrating to a new build system.
  • You're OK with outputs being committed to git (no separate artifact cache infrastructure).

You probably want a different tool when:

Need Better fit
Cache compile artifacts and binaries (not just codegen outputs) Bazel / Buck2
Hermetic build with full toolchain isolation Bazel / Buck2
General task runner (build / test / lint / dev server / formatter) moonrepo / Nx
JS/TS-only monorepo Turborepo / Nx
File-grained dependency inference Pants
Battle-tested at massive scale Any of the above

sloff is intentionally narrow β€” codegen orchestration with honest fingerprints, nothing else.

Documentation

License

MIT

Directories ΒΆ

Path Synopsis
cmd
sloff command
Command sloff is the fingerprint-aware codegen orchestrator CLI.
Command sloff is the fingerprint-aware codegen orchestrator CLI.
internal
sloff/depgraph
Package depgraph derives a task DAG from each task's inputs/outputs and emits a stable topological order.
Package depgraph derives a task DAG from each task's inputs/outputs and emits a stable topological order.
sloff/explain
Package explain projects depgraph tasks into the auto-detected edges and the file-overlap evidence that justified each edge.
Package explain projects depgraph tasks into the auto-detected edges and the file-overlap evidence that justified each edge.
sloff/fingerprint
Package fingerprint defines the storage interface and serialization helpers for sloff's on-disk fingerprints.
Package fingerprint defines the storage interface and serialization helpers for sloff's on-disk fingerprints.
sloff/fingerprint/cached
Package cached is a fingerprint.Storage decorator that mirrors records to a host-local directory under XDG_CACHE_HOME.
Package cached is a fingerprint.Storage decorator that mirrors records to a host-local directory under XDG_CACHE_HOME.
sloff/fingerprint/dynamodb
Package dynamodb is a fingerprint.Storage backend that persists records as individual items in an Amazon DynamoDB table.
Package dynamodb is a fingerprint.Storage backend that persists records as individual items in an Amazon DynamoDB table.
sloff/fingerprint/local
Package local is the default Storage backend that persists records as protobuf binary files on the local filesystem under <repoRoot>/.sloff/fingerprints/.
Package local is the default Storage backend that persists records as protobuf binary files on the local filesystem under <repoRoot>/.sloff/fingerprints/.
sloff/glob
Package glob expands inputs/outputs patterns declared in a sloff.yml.
Package glob expands inputs/outputs patterns declared in a sloff.yml.
sloff/hash
Package hash computes the deterministic hash inputs that drive sloff's fingerprint lookup.
Package hash computes the deterministic hash inputs that drive sloff's fingerprint lookup.
sloff/preflight
Package preflight verifies that build artefacts and source state are mutually consistent before the runner trusts the fingerprint.
Package preflight verifies that build artefacts and source state are mutually consistent before the runner trusts the fingerprint.
sloff/preflight/pnpmlocal
Package pnpmlocal implements the preflight Checker that protects pnpm-local from running against a stale node_modules.
Package pnpmlocal implements the preflight Checker that protects pnpm-local from running against a stale node_modules.
sloff/runner
Package runner orchestrates spec discovery, preflight, dependency-graph derivation and per-task fingerprint lookup/execute/write.
Package runner orchestrates spec discovery, preflight, dependency-graph derivation and per-task fingerprint lookup/execute/write.
sloff/spec
Package spec provides parsers for sloff.yml task specs and the repository-wide tool registry that named tools[] references resolve against (ADR-0008).
Package spec provides parsers for sloff.yml task specs and the repository-wide tool registry that named tools[] references resolve against (ADR-0008).
sloff/toolresolver
Package toolresolver dispatches tool version resolution to per-channel resolvers (script for prebuilt binaries β€” including external npm / Go OSS packages, see ADR-0007 β€” and go-local / pnpm-local for internal sources) and produces the OS-neutral logical version strings that feed the fingerprint's resolved_versions_hash component, plus the ExtraInputs that feed the runner's depgraph derivation.
Package toolresolver dispatches tool version resolution to per-channel resolvers (script for prebuilt binaries β€” including external npm / Go OSS packages, see ADR-0007 β€” and go-local / pnpm-local for internal sources) and produces the OS-neutral logical version strings that feed the fingerprint's resolved_versions_hash component, plus the ExtraInputs that feed the runner's depgraph derivation.
sloff/toolresolver/golocal
Package golocal implements toolresolver.Resolver for repo-local Go tools.
Package golocal implements toolresolver.Resolver for repo-local Go tools.
sloff/toolresolver/lister
Package lister enumerates the source contributions that feed the go-local resolver's hash.
Package lister enumerates the source contributions that feed the go-local resolver's hash.
sloff/toolresolver/pnpmlocal
Package pnpmlocal implements toolresolver.Resolver for pnpm workspace-local tools.
Package pnpmlocal implements toolresolver.Resolver for pnpm workspace-local tools.
sloff/toolresolver/script
Package script implements toolresolver.Resolver for the prebuilt-binary channel: it runs a user-declared command (typically <bin> --version), captures stdout, optionally applies an extract regex, and returns the resulting string as the OS-neutral logical version.
Package script implements toolresolver.Resolver for the prebuilt-binary channel: it runs a user-declared command (typically <bin> --version), captures stdout, optionally applies an extract regex, and returns the resulting string as the OS-neutral logical version.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL