`gitTally` is the name of another product in the git space, so the rename is a precaution; nothing about what the build system does changes. The name follows one rule: `Werkator` where it is prose, capitalized where it is a Kotlin type and its file, lowercase everywhere a machine reads it — the command, packages, paths, configuration keys and values, the Gitea check context. Environment variables keep their convention and are uppercase throughout. Every configuration file is still found under its pre-rename name (`ConfigFiles`): `.gittally.yml` at the repository root, in a build worktree and as committed on a branch, `.git/gittally/.gittally.yml` for the machine layer. The current name wins where both exist, and the old file is then ignored rather than merged — two files side by side are a half-done rename, not a layering. Without the fallback an installation that updated without renaming would not fail: a configuration that is not found leaves every setting at its default, so it would come up looking healthy while having forgotten its credentials and its builds. `docs/werkator-migrationsplan.md` lists what the fallback does not cover and has to be moved by hand — above all the state directory `.git/werkator/`, which holds the build history, the control token and the worktrees, and has no fallback of its own. `docs/migration-from-legacy.md` is deleted with this: it mapped the legacy script's environment variables, and every host it addressed has long since moved to the YAML configuration. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
4.1 KiB
Self-Contained Runtime Bundle Distribution
Status:
- proposed: 2026-08-10
- accepted: 2026-08-10
- rejected: -
- superseded: -
Decision [accepted]: Werkator is distributed for hosts without a Java runtime as a self-contained runtime bundle — a jlink-trimmed JRE plus werkator.jar plus a launcher script in one tarball, built by ./gradlew runtimeBundle.
The JAR stays the primary artifact; a GraalVM native image and a containerized Werkator runtime were rejected.
Context and Problem Statement
Werkator must run on Hostsharing container servers (the primary target, see ADR 0005).
These hosts provide git, Docker, make, and systemd user sessions, but no Java runtime, and nothing may be installed system-wide.
docs/bootstrapping.md sketched a containerized Werkator runtime as the future answer; that sketch was never validated against the operational details.
Considered Options
- jlink runtime bundle (trimmed JRE + jar + launcher, one tarball)
- GraalVM native image (single executable)
- Containerized Werkator runtime (the original
docs/bootstrapping.mdsketch)
jlink Runtime Bundle
A jlink-generated JRE with the pinned module list, the boot jar, and a bin/werkator launcher script, packed as werkator-runtime-linux-x64.tar.gz (~66 MB) and unpacked to ~/opt/werkator/ on the target host.
Good:
- No production-code changes and plain JVM semantics — no new failure modes.
- git and docker CLIs are used from the host; build worktree paths stay host paths.
init --systemdworks unchanged:java.homeand the running-jar path resolve into the bundle, so the generated unit points at<bundle>/jre/bin/javaand<bundle>/lib/werkator.jar(verified).- Every JDK 21 ships jlink — no new build-toolchain requirement.
Bad:
- A directory tree, not a single file (still one tarball to copy).
- JVM startup (~1-2 s) instead of native-image startup — irrelevant for a long-running server.
- The jlink image links glibc dynamically, so it is bound to an architecture and a minimum glibc.
Corrected on 2026-08-11: that minimum is not the build machine's glibc, as originally assumed here.
jlinkcompiles nothing — it copies the JDK vendor's prebuilt binaries out of the jmods, so the floor is the vendor's build environment. Measured over all 33 ELF files of the bundle produced by the Temurin 21 toolchain, the highest required symbol version isGLIBC_2.15, which every supported distribution exceeds. The build machine's glibc only matters if the toolchain resolves to a distribution-packaged JDK instead of Temurin.
GraalVM Native Image
Rejected because Spring AOT evaluates bean conditions at build time, and Werkator's dual-mode wiring cannot be represented in a single AOT arrangement:
the CLI context runs without web and with @Profile("!server") CliRunner, while the server subcommand starts a second SpringApplication with WebApplicationType.SERVLET and the server profile gating the watcher/metrics/nginx lifecycles.
Whichever profile and web type the AOT processing fixes, the other mode's beans are missing from the binary.
Supporting both would require replacing the profile wiring with runtime guards and collapsing the two context shapes — an invasive rewrite with regression risk for the JVM path, on top of the usual native-image reflection work (Jackson-bound config and persistence classes, picocli).
Containerized Werkator Runtime
Rejected for operational complexity: the image must bundle git and docker CLIs; the container needs a same-path $HOME mount plus a docker-socket mount and uid/gid mapping so that DockerBuildRunner's --volume $workspace:$workspace sibling mounts keep working; and the systemd unit must be hand-edited to a docker run invocation.
This remains the documented fallback if the runtime bundle ever becomes unworkable.
Consequences
docs/deployment.mddocuments the bundle path; the "Future: Docker-based Deployment" section indocs/bootstrapping.mdis replaced.- The pinned JDK module list in
build.gradle.ktsmust be re-checked (via the documented jdeps command) when dependencies change. - Deployment and migration for vm4006 follow plan step 15.