/\_/\ ( o.o ) > ^ <
self-hosted git forge · single binary each side
rits is a headless git server. Clone, push, browse history, enroll build machines, and run CI — everything over one SSH port, driven from a terminal UI instead of a web app.
launching soon
rits is nearing its first public release. Want in? Send a one-line hello and you'll get one reply when the binaries drop — nothing else, ever.
a human reads this inbox · no list, no tracking
history Commits @ main Branches Jobs ✓ 8216de0 2026-08-19 remus │ commit 8216de0a3bfc4d8a33d46 ✓ e34cfe0 2026-08-18 remus │ Author: remus ✗ 50cbe45 2026-08-18 ada │ Date: 2026-08-19 10:27 ✓ 12a27bf 2026-08-18 ada │ ✓ Dockerfile.push@main j85c9ea87 ● 91ee5f9 2026-08-18 remus │ ✗ Dockerfile.tag@v* jb6ad7a77 fc289bf 2026-08-18 ada │ 1bf42a3 2026-08-18 ada │ ci: enable release checks 450 of 103,412 commits loaded • ↑/↓ select • b branches • esc back
one protocol
Other platforms bolt a web application onto git.
rits goes the other way: the git wire protocol is the whole
interface. Humans authenticate as git with their
public keys, build machines as runner — and every feature,
from creating a repo to streaming a build log, is an SSH command on
port 2222.
ci without yaml
Drop Dockerfile.push@main into
.hooks/ and every push to main builds it. The build
is the job: its exit code is the verdict, its output
is the log, its image is the artifact. No pipeline DSL to learn —
you already know this file format.
.hooks/Dockerfile.push@main
FROM golang:1.25 AS build LABEL rits.runner="docker" WORKDIR /src COPY . . RUN go vet ./... && go test ./... RUN CGO_ENABLED=0 go build -o /out/app . FROM alpine:3.22 COPY --from=build /out/app /usr/local/bin/app
what a push sets in motion
$ git push origin main j85c9ea87 ✓ success push main push@main jb6ad7a77 ✗ failed tag v2.0 tag@v* j76d6ef0c ● running push main push@main j9c1330a2 ○ queued push feat… push@feature* artifact: rits/demo/push-main:8216de0 4 jobs • enter view log • r refresh
The runner ships the pushed commit as the build context with
git archive — jobs never clone, so no key or token
ever enters a build container.
Verdicts are written as git notes under
refs/notes/rits-ci — the ✓/✗ next to each commit
travels with the repo and works offline in plain
git log.
LABEL rits.runner routes jobs to matching machines.
No runner online? The job waits. A runner dies mid-build? The job
is requeued, up to three attempts.
roadmap
Working today, verified end to end.
.hooks/Dockerfile.<event>[@glob]; branch and tag triggers; builds as sibling containers, never DinD.rits/repo/hook:sha, newest three kept, older pruned.Directions under consideration, in rough order.
.deb, a binary, a coverage report — pushed to the rits server for persistent storage and fetched back over SSH..sh deploy script that runs after a successful build, entirely in your hands: push the image to a registry, restart pods on staging, rsync to a server..sh hooks beside the Dockerfiles, same filename triggers, for runners without docker.Ready to use — self-hosting only. You bring the box, the keys, and the runners. There is no hosted offering, no account system, no telemetry — your repositories never leave hardware you control.