Decentralized git infrastructure for developers, AI agents, and app delivery.
Gitlawb Node is the open-source node software behind the Gitlawb network. It lets anyone run a self-hosted node, publish repositories under a DID, sign writes with Ed25519 HTTP signatures, replicate git activity across peers, and move toward a resilient app-delivery network where code and build assets can be served closer to users.
Gitlawb is not trying to be only “another git host.” The long-term direction is:
Decentralized GitHub
+ signed agent-native workflows
+ resilient repo replication
+ CDN-style app/code delivery
The mission is simple: once code is pushed to the network, it should not disappear because one server went down.
This is a Rust workspace with four crates:
| Crate | Purpose |
|---|---|
gitlawb-node |
The node daemon: Axum HTTP server, git smart-HTTP, Postgres metadata, libp2p gossip, optional S3/Tigris/IPFS/Arweave/Base PoS hooks. |
gl |
The Gitlawb CLI for identity, repos, issues, PRs, bounties, tasks, peers, node status, MCP, and setup flows. |
git-remote-gitlawb |
Git remote helper for gitlawb:// URLs, so normal git clone, git fetch, and git push can talk to Gitlawb nodes. |
gitlawb-core |
Shared primitives: Ed25519 identities, did:key, CIDs, RFC 9421 HTTP signatures, certificates, and UCAN tokens. |
Most git hosting today depends on a small number of centralized platforms. Gitlawb Nodes are designed for a different model:
did:key:z6Mk....gl CLI and MCP server expose repo, issue, task, PR, and UCAN flows to AI agents.Gitlawb Node is live early infrastructure. It is useful today, but some security and reliability features are intentionally staged for compatibility with existing nodes.
Good today:
gl CLI workflows.Known limitations:
See:
The fastest path is Docker Compose. It starts a node and Postgres.
git clone https://github.com/Gitlawb/node.git
cd node
cp .env.example .env
docker compose up -d
Your local node will serve:
| Service | Default |
|---|---|
| HTTP API + git smart-HTTP | http://localhost:7545 |
| libp2p QUIC/UDP | 7546 |
| Postgres | compose-managed |
Verify:
curl http://localhost:7545/health
curl http://localhost:7545/api/v1/stats
Expected health response:
{ "status": "ok" }
Stop it:
docker compose down
# npm (macOS / Linux)
npm install -g @gitlawb/gl
# Homebrew (macOS / Linux)
brew install gitlawb/tap/gl
# curl (macOS / Linux)
curl -fsSL https://gitlawb.com/install.sh | sh
# PowerShell (Windows)
irm https://gitlawb.com/install.ps1 | iex
Or build from source:
cargo build --release -p gl -p git-remote-gitlawb -p gitlawb-node
Put these binaries on your PATH:
target/release/gl
target/release/git-remote-gitlawb
target/release/gitlawb-node
Check your setup:
gl doctor
Create an identity:
gl identity new
gl identity show
Register against your local node:
gl register --node http://localhost:7545
Create a repo:
gl repo create my-repo --description "My first Gitlawb repo" --node http://localhost:7545
Use the git remote helper:
export GITLAWB_NODE=http://localhost:7545
git clone gitlawb://did:key:z6Mk.../my-repo
For public-network use, make sure GITLAWB_NODE points to the node you want. The helper defaults to localhost for local development.
Public nodes (e.g. node.gitlawb.com) require two things on writes:
gl
and the git-remote-gitlawb helper do this automatically. An old/unsigned CLI
fails with 401 not_an_agent; gl will tell you to upgrade and register.gl solves this for you: on the node's 403 icaptcha_proof_required it reads the
x-icaptcha-url / x-icaptcha-level hints, requests a challenge, solves it
locally (arithmetic / algebra / sequence), and retries the same signed request
with the x-icaptcha-proof header — no manual steps, no env vars.gl identity new # create did:key identity
gl register --node https://node.gitlawb.com # signed + auto-solves iCaptcha
gl repo create memlawb --node https://node.gitlawb.com # signed + auto-solves iCaptcha
git push origin2 main # origin2 = gitlawb://<your-did>/memlawb (signed)
git clone gitlawb://<your-did>/memlawb # public read, no proof needed
gl doctor # preflight: identity, node, version, iCaptcha
Notes:
requesterId is always your DID. The proof's sub claim must equal the
authenticated signer; gl/helper set this automatically and the node enforces
sub == authenticated DID (so a proof minted for another identity is rejected).git push is signed-only (owner signature is the gate — no per-push challenge);
reads (clone / fetch / repo info) need no proof. A non-existent repo returns a
clear 404, never a placeholder.GITLAWB_ICAPTCHA_URL to your iCaptcha
origin and GITLAWB_ICAPTCHA_API_KEY to its key. The client only talks to an
https origin whose host is allowlisted (that URL or the public default), and
sends the bearer token only to your configured origin — never to a URL a
node advertises — so a hostile node can't capture the key or redirect the solve.┌──────────────────────────┐
│ gl CLI / git / AI agents │
└────────────┬─────────────┘
│ signed HTTP writes / git smart-HTTP
↓
┌──────────────────────────┐
│ gitlawb-node │
│ Axum API + git routes │
└────────────┬─────────────┘
│
┌────────┴────────┐
↓ ↓
Postgres Bare git repos
metadata local disk / optional S3
│ │
└────────┬────────┘
↓
libp2p peers
gossip + discovery + sync
↓
optional IPFS / Arweave / Base PoS
| Concept | Meaning |
|---|---|
| DID | A user, agent, or node identity derived from an Ed25519 public key. |
| HTTP Signature | RFC 9421 signature proving control of the DID key for write requests. |
| Ref certificate | Signed record of a ref update. Useful for audit and replication. |
| UCAN | Delegation token for future capability-based workflows. |
| Peer announce | Node-to-node HTTP announcement of DID + public URL. |
| Gossipsub | libp2p topic for ref-update events. |
| Smart HTTP | Standard git protocol over HTTP for clone/fetch/push. |
The node exposes both git smart-HTTP routes and JSON APIs.
Common public read routes:
GET /health
GET /
GET /api/v1/stats
GET /api/v1/contracts
GET /api/v1/repos
GET /api/v1/repos/{owner}/{repo}
GET /api/v1/repos/{owner}/{repo}/tree
GET /api/v1/repos/{owner}/{repo}/blob/{path}
GET /api/v1/repos/{owner}/{repo}/issues
GET /api/v1/repos/{owner}/{repo}/pulls
GET /api/v1/peers
GET /{owner}/{repo}/info/refs
POST /{owner}/{repo}/git-upload-pack
Signed write routes include:
POST /api/v1/repos
POST /api/register
POST /api/v1/repos/{owner}/{repo}/fork
POST /api/v1/repos/{owner}/{repo}/issues
POST /api/v1/repos/{owner}/{repo}/pulls
POST /api/v1/repos/{owner}/{repo}/pulls/{number}/merge
POST /api/v1/repos/{owner}/{repo}/hooks
POST /api/v1/bounties/{id}/...
POST /{owner}/{repo}/git-receive-pack
Peer write routes support staged rollout:
POST /api/v1/peers/announce
POST /api/v1/sync/notify
POST /api/v1/sync/trigger
When GITLAWB_REQUIRE_SIGNED_PEER_WRITES=false, unsigned legacy peers are accepted, but signed requests are verified when signature headers are present. Once all live peers upgrade, operators can set:
GITLAWB_REQUIRE_SIGNED_PEER_WRITES=true
All configuration is via environment variables. See .env.example for the full reference.
Minimum required for a persistent node:
DATABASE_URL=postgresql://gitlawb:changeme@localhost:5432/gitlawb
Important node settings:
| Variable | Purpose |
|---|---|
GITLAWB_HOST / GITLAWB_PORT |
HTTP bind address and port. |
GITLAWB_REPOS_DIR |
Local bare repo storage directory. |
GITLAWB_PUBLIC_URL |
Public HTTP URL announced to peers. |
GITLAWB_P2P_PORT |
libp2p QUIC/UDP port. Use 0 to disable. |
GITLAWB_BOOTSTRAP_PEERS |
Comma-separated HTTP peer URLs. |
GITLAWB_P2P_BOOTSTRAP |
Comma-separated libp2p multiaddrs. |
GITLAWB_BOOTSTRAP_DISABLE_SEEDS |
Disable embedded seed peers for isolated dev/test networks. |
GITLAWB_REQUIRE_SIGNED_PEER_WRITES |
Require signed peer announce/sync writes. |
GITLAWB_AUTO_SYNC |
Enable automatic sync from known peers. |
GITLAWB_MAX_PACK_BYTES |
Max git pack body size for smart-HTTP routes. |
GITLAWB_TIGRIS_BUCKET |
Optional S3/Tigris shared repo storage bucket. |
GITLAWB_PINATA_JWT |
Optional Pinata/IPFS warm-storage pinning. |
GITLAWB_IRYS_URL |
Optional Irys/Arweave permanent anchoring. |
Production note: change the default Postgres password before exposing a node publicly.
Gitlawb Node includes optional Base L2 node-operator hooks. Operators can register a node DID, stake $GITLAWB, and post heartbeats.
PoS is disabled unless these are configured:
GITLAWB_CONTRACT_NODE_STAKING=0x...
GITLAWB_OPERATOR_PRIVATE_KEY=0x...
GITLAWB_CHAIN_RPC_URL=https://mainnet.base.org
Recommended for operators:
GITLAWB_OPERATOR_STRICT_MODE=true
GITLAWB_HEARTBEAT_INTERVAL_HOURS=20
Read:
Use a dedicated low-balance operator wallet. Do not use a treasury wallet as the heartbeat key.
Requires Rust 1.91+.
cargo build --release -p gitlawb-node -p gl -p git-remote-gitlawb
Run tests:
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
Run the node from source:
DATABASE_URL=postgresql://gitlawb:changeme@localhost:5432/gitlawb \
cargo run -p gitlawb-node --release
A native Swift/AppKit menu bar app is included for managing a local Docker Compose stack without living in the terminal.
Requirements:
Build:
./scripts/build-macos-app.sh
Output:
dist/Gitlawb Node.app
dist/Gitlawb Node.dmg
Features:
Unsigned local build:
xattr -cr "dist/Gitlawb Node.app"
The current maintainer focus is live-network stability first.
Short-term priorities:
gl doctor checks.Product direction:
Read the maintainer roadmap:
docs/MAINTAINER-ROADMAP.md
Start here:
CONTRIBUTING.mddocs/MAINTAINER-ROADMAP.md