anvilsign in

collin/anvil

RenderedSource

anvil

A minimal, self-hosted git forge in Rust, built on gix (gitoxide).

Design rules

  • Pure gitoxide — never the git binary. The product (server, CI broker, mirroring, deploy image) must not invoke or depend on a git executable. When gix lacks a capability, implement the protocol on gix plumbing instead of shelling out — e.g. gix can't push yet, so anvil-git/src/push.rs speaks the send-pack wire format itself (with gitserver-core covering the server side). Tests may use the git CLI, but only as a fixture/interop check, never on the code path under test.

Dev setup: git config core.hooksPath .githooks — the pre-commit hook runs cargo +nightly fmt (nightly, for the unstable options in rustfmt.toml), cargo sort-derives (cargo install cargo-sort-derives), and cargo clippy --workspace --all-targets -- -D warnings.

Viewing attachments referenced in tasks

TODO items and tickets may embed an uploaded image as ![...](/{owner}/{repo}/-/attachments/{hash}). These bytes live outside git history, so to actually see one, get the bytes and Read the file. Two ways:

Preferred — over git, no credentials. anvil mirrors every attachment into refs/anvil/attachments (a flat tree of <hash> → blob, off the branch namespace so a default pull never drags it down). From a clone, opt in once:

git fetch origin '+refs/anvil/attachments:refs/anvil/attachments'
git cat-file -p "refs/anvil/attachments:<hash>" > /tmp/att && # then Read /tmp/att

This uses the clone's existing git auth — no PAT — and works offline afterward.

Fallback — HTTP with a PAT (no clone, or the ref isn't fetched). Credentials live in the git-ignored .anvil-credentials at the repo root (ANVIL_BASE_URL + a read-only ANVIL_TOKEN); source it, then:

curl -fsS -H "Authorization: Bearer $ANVIL_TOKEN" \
  "$ANVIL_BASE_URL/{owner}/{repo}/-/attachments/{hash}" -o /tmp/att && # Read it

The PAT is read-only (GET/HEAD only), safe to hold. If neither the ref nor .anvil-credentials is available, ask the user rather than guessing.

Current status, resume notes, the agreed next steps (a/b/c), and the roadmap live in the TODO. Read it first:

@TODO.md