Index

zipx generates GitHub Actions from your sbt build. You keep writing build.sbt. zipx writes the workflow, so you do not maintain a second copy in YAML.

Day one is Aggregate: parallel Verify (test, fmt, workflow-check, advisories) and a publish job on a version tag. Add the plugin, run zipxWorkflowGenerate, commit, open a PR. zipxWorkflowCheck fails the PR if you forgot to regenerate. Versions live in a ZipxVersions catalog you extend (Lib / Plugin / Pin / Action inbound vals, no second list); drop MyVersions.settings in build.sbt. Multi-artifact repos add outbound Ship / ShipGroup rows (Independent versions); zipx-the-product stays lockstep on dynver-ci.

Later pages cover extra jobs (Graph, docker, deploy), packs (Central, Pages, AWS), and the local bump loop. Skip them until you need them. Extending Versions is for sbt plugins that sit on zipx (splice, a company catalog). If you already maintain painful CI YAML, Why zipx is the recovery story.

Guide: Why zipx → Quick start → Versions → Independent versions → Extending Versions → Execution modes → Matrix collapse → Capabilities → Custom capabilities → Composing sbt commands → Shell and steps → Verify → Affected → Caching → Remote cache for teams → From Bazel → Action pins → Dependency updates → Pin feeds → Docker and deploy → Job conditions → Validation → Packs → Settings.

Install

// project/plugins.sbt
addSbtPlugin("rocks.earlyeffect" % "sbt-zipx" % "0.11.0")

Generate & check

sbt zipxWorkflowGenerate
git add .github/workflows/ci.yml .github/actions/
sbt zipxWorkflowCheck   # fails CI when the committed YAML drifts

Versions catalog

// project/ZipxVersions.scala
import zipx.*
object MyVersions extends ZipxVersions:
  val sbt   = SbtVersion("2.1.0-M1")
  val scala = ScalaVersion("3.9.0")
  val zio   = Lib("dev.zio", "zio", "2.1.26")
  val slf4j = Lib("org.slf4j", "slf4j-simple", "2.0.18").java
  def libraries = library(zio)
  def service   = library(zio, slf4j)

// build.sbt
MyVersions.settings
lazy val lib     = project.settings(MyVersions.libraries)
lazy val service = project.settings(MyVersions.service)

Action pins (optional)

# Action vals in ZipxVersions; see Action pins docs
sbt "zipxActionUpdate yes"
sbt reload
sbt zipxWorkflowGenerate

Documentation

Continue with: