collin / anvil
My Git Forge
git clone git@anvil.richardscollin.com:collin/anvil.gitCopied!· commits
Todo2 open
- ability to link to deployed / live site
- agent view, we have list of repos what about list of agents
Backlog14 open
finish the CI pipeline move to TOML: rename
.anvil/ci.ymlto.anvil/ci.toml(and convert it) in every repo on the instance, then deleteci::LEGACY_PIPELINE_PATHand the legacy branch ofload_pipeline/enqueue_ci_for_push. Until then a stale.anvil/ci.ymlstill enqueues a run, which fails telling you to rename the file — the point being that CI going quiet is louder than CI going missing.agent sessions, next milestones (docs/agent-sessions.md):
- a real checkout: the container clones from anvil's smart-HTTP endpoint and
pushes
agent/<id>back. Needs a session-scoped push credential, which does not exist (tokens are read-only, Bearer only on GET/HEAD) - ref-scope that credential to
refs/heads/agent/*— needs a ref filter in receive-pack. Until it lands a session credential could writemain - trigger surfaces: a start button on a TODO item, an issue, a red CI run
- rate limiting, so automated pushes can't queue sessions endlessly once
triggers exist (
max_concurrentbounds concurrency, not churn) - a finished session's transcript rendered on its page (it is already on
disk under
sessions/<id>.log; nothing reads it back yet)
- a real checkout: the container clones from anvil's smart-HTTP endpoint and
pushes
- pull requests (gix merge)
pull mirror (maybe): a repo that virtually mirrors a GitHub repo
- just displays it here — periodically fetched, read-only on the anvil side
richer file editing: a real markdown editor with a live render preview
(reuse
render_markdown) before committing- +9 more
anvil
A git forge built using gitoxide.
Architecture
A Cargo workspace. The keystone is anvil-git: gix is a client library
with no server-side protocol, so anvil supplies its own transport-agnostic
upload-pack/receive-pack (smart-HTTP and SSH share one implementation).
| Crate | Responsibility |
|---|---|
anvil-core | Domain model, SQLite persistence, on-disk bare-repo storage |
anvil-git | Server-side git wire protocol on gix (upstream-candidate) |
anvil-web | axum HTTP server: web UI + smart-HTTP git endpoints |
anvil-ssh | git-over-SSH (russh) |
anvil-cli | anvild daemon + admin CLI |
Quick start
cargo run -- migrate # create data/ + database
cargo run -- user create alice --password secret # create a user
cargo run -- repo create alice/hello # create a bare repo on disk
cargo run -- serve # start the server
Configuration is optional; see anvil.example.toml.
PORT/HOST and ANVIL_BASE_URL (or PORTLESS_URL) override the listen
address and public URL, so a proxy can place anvil without a config file.
To run it in Docker the way it runs in production, compose.override.yaml
layers local settings over the deployment file and compose merges it
automatically:
docker compose up -d --build # then http://127.0.0.1:20640
docker compose logs -f
docker compose down
The override swaps in deploy/anvil.dev.toml (so agent sessions are on and the
SSO issuer is https://login.localhost), publishes to loopback instead of the
droplet's public IP, uses the anvil-dev-data volume, and mounts the Docker
socket that agent sessions need. hag passes -f compose.yaml explicitly, so
none of it reaches the host.
./deploy/dev.sh is the fuller path and still there: it also generates the
deploy/dev-ca.crt bundle the override mounts, waits for /-/healthz, and
points portless at the container for
https://anvil.localhost.
Deploying
compose.yaml describes the deployment; hag, the shared deploy tool for
every project on hagrid, runs it there. docker/Dockerfile compiles anvild out
of the build context, so there is nothing to stage first:
hag deploy # build, push, then pull and recreate on the host
hag deploy -n # dry run: print every step, change nothing
hag status # what the host is running
hag logs -f # its logs
Full details, including first-run setup and the CD webhook, are in DEPLOY.md.
Docs
- CI artifacts
- Remote runners — dial-out runners so CI executes off-box; design, not yet built
- Single sign-on — OIDC sign-in, alongside passwords
- Repository secrets — encrypted to your ssh keys in the browser; anvil stores ciphertext it cannot open
- Threat model for untrusted users