http-knot#
A Git server powered by the AT Protocol that stores repositories in S3-compatible object storage. Part of the Tangled ecosystem.
http-knot implements the Git smart HTTP protocol for clone, fetch, and push operations, using AT Protocol decentralized identifiers (DIDs) for authentication and authorization.
Features#
- Git smart HTTP protocol — clone, fetch, and push over HTTP with standard Git clients
- AT Protocol authentication — JWT-based auth tied to AT Protocol identities (DIDs)
- S3-backed storage — repositories stored in any S3-compatible object store (AWS S3, Tigris, MinIO, etc.)
- XRPC API — read-only endpoints for browsing repos, commits, trees, diffs, and more
- Role-based access control — server owners, knot members, and collaborators via Casbin policies
- Event streaming — WebSocket endpoint for repository events, plus Jetstream ingestion for AT Protocol events
- Spindle CI — built-in CI/CD runner using Fly.io Machines for ephemeral build VMs
How it works#
Repositories are addressed by DID and name (e.g., did:plc:abc123/my-repo). Git operations go through the smart HTTP protocol endpoints, while the XRPC API provides a structured interface for browsing repository contents.
Authentication uses AT Protocol service auth — Git clients pass a JWT as the Basic Auth password, which is validated against the AT Protocol AppView.
Configuration#
All configuration is via environment variables:
| Variable | Description | Default |
|---|---|---|
KNOT_SERVER_HOSTNAME |
did:web hostname (required) | — |
KNOT_SERVER_OWNER |
Server owner DID (required) | — |
KNOT_SERVER_LISTEN_ADDR |
HTTP listen address | 0.0.0.0:5555 |
KNOT_SERVER_DB_PATH |
SQLite database path | knotserver.db |
KNOT_REPO_MAIN_BRANCH |
Default branch for new repos | main |
KNOT_SERVER_PLC_URL |
PLC directory URL | https://plc.directory |
KNOT_SERVER_JETSTREAM_ENDPOINT |
Bluesky Jetstream endpoint | wss://jetstream1.us-west.bsky.network/subscribe |
S3 storage#
| Variable | Description | Fallback |
|---|---|---|
KNOT_S3_ENDPOINT |
S3 endpoint URL | AWS_ENDPOINT_URL_S3 |
KNOT_S3_BUCKET |
Bucket name | BUCKET_NAME |
KNOT_S3_ACCESS_KEY |
Access key ID | AWS_ACCESS_KEY_ID |
KNOT_S3_SECRET_KEY |
Secret access key | AWS_SECRET_ACCESS_KEY |
KNOT_S3_REGION |
AWS region | AWS_REGION |
KNOT_S3_USE_SSL |
Use SSL for S3 | true |
API#
Git HTTP endpoints#
GET /{did}/{name}/info/refs # ref discovery
POST /{did}/{name}/git-upload-pack # clone/fetch
POST /{did}/{name}/git-receive-pack # push (auth required)
XRPC query endpoints#
sh.tangled.repo.tree— browse file treesh.tangled.repo.log— commit historysh.tangled.repo.blob— file contentssh.tangled.repo.branches— list branchessh.tangled.repo.tags— list tagssh.tangled.repo.diff— view diffssh.tangled.repo.languages— language statisticssh.tangled.repo.getDefaultBranch— default branchsh.tangled.owner— server owner identitycom.atproto.repo.create— create repository (auth required)
Events#
GET /events # WebSocket stream of repository events
Deployment#
http-knot is designed to run on Fly.io with Tigris for S3 storage. The fly.toml defines two processes:
- knot — the main HTTP server (port 5555)
- spindle — CI/CD runner using Fly Machines (port 6555)
fly deploy
Development#
Requires Go 1.24+.
go build -o http-knot ./cmd/knot
go build -o spindle ./cmd/spindle
License#
See LICENSE for details.