Self-hosting

Running a gateway of your own, from a clone. This is the development setup; for a real host, the operator's runbook in deploy/RUNBOOK.md covers provisioning, backups, replication and delivery.

What you need

Start PostgreSQL and the object store

cp .env.example .env
make up

make up waits until both containers are healthy. The binaries read .env from the directory you run them in, so run them from the checkout root — or point OTISK_ENV_FILE at the file. Anything already set in the environment takes precedence, which is how the compose stack configures them.

PostgreSQL holds metadata only — accounts, keys, repository records, the ref mirror — and never git object data.

Build

make build

This produces bin/git-gateway and bin/otisk.

Create the first account

./bin/git-gateway bootstrap -handle yuritomanek -key ~/.ssh/id_ed25519.pub

This is the only command that needs access to the host, and it has to be: authenticating over SSH requires a key that is already registered. Everything after this happens over SSH.

Run the gateway

From the checkout root, so it finds .env:

./bin/git-gateway serve

It applies any pending migrations on start and listens on :2222 by default.

Use it

otisk host set git@localhost:2222
otisk whoami

From here, getting started applies as written, with git@localhost:2222 wherever it says a host.

Development

make lint     # gofmt and go vet, no tools to install
make test     # the full suite, with the race detector
make verify   # the same, refusing a run that skipped more than expected
make build    # binaries into ./bin
make up       # start PostgreSQL and the object store
make down     # stop them, keeping volumes

Tests need the stack running: they create an isolated database and bucket per test and drop them afterwards. Without it they skip rather than fail — which is why make verify exists, and why it refuses a run where more tests skipped than expected.

Stock git is kept available as a correctness oracle — internal/oracle compares otisk's view of a repository against git cat-file, object by object. That matters most for work not yet done: serving objects by parsing packfiles directly is exactly the kind of change that can silently return wrong bytes.

Planning artifacts live in openspec/.