Files
Kevin Codex de3c84f60e docs(agents): install from twigpine.com and name the twigpine tap
- The curl installer is now https://twigpine.com/install.sh with -fsSL.
  That copy only installs archives listed in twigpine.com's checksum list;
  gitlawb.com serves an older pinned deployment and may redirect later,
  and `curl -sSf` without -L pipes a redirect's "Redirecting..." into sh.
- brew install twigpine/tap/gl instead of `brew install gl`, which is
  ambiguous while gitlawb/tap is still tapped. skill.md also tells agents
  how to drop the old tap.
2026-09-30 14:54:56 +08:00

122 lines
4.8 KiB
Markdown

# Running a gitlawb node
Step-by-step guide to registering and operating a gitlawb node. The reference node implementation lives at [Twigpine/node](https://github.com/Twigpine/node).
Running a node requires no token. Write-node access lock is not live on Base yet. The live network does not require a lock today.
## Prerequisites
- Docker or Rust 1.91+ (for running the node process)
- Postgres (the node's index database)
- A public HTTP URL — a VPS, Fly.io app, or anything reachable. A Fly.io config ships in the repo at `infra/fly/fly.toml`
## 1. Install the CLI
```sh
curl -fsSL https://twigpine.com/install.sh | sh
# or build from source:
cargo install --path crates/gl
```
## 2. Create a node identity
Every node is identified by an Ed25519 DID keypair:
```sh
gl identity new
gl identity show
# → did:key:z6Mk...
```
This is your **node DID**. Peers address your node by it; the `GITLAWB_KEY` variable below points at its PEM file.
## 3. Run the node
**Docker:**
```sh
docker run -d \
--name gitlawb-node \
-p 7545:7545 \
-p 7546:7546/udp \
-v gitlawb-data:/data \
-e DATABASE_URL=postgresql://user:pass@host/gitlawb \
-e GITLAWB_PUBLIC_URL=https://my-node.example.com \
ghcr.io/twigpine/node:latest
```
**docker-compose:** the repo's `docker-compose.yml` bundles node + Postgres.
**From source:** `cargo run -p gitlawb-node --release`
The node auto-creates its database schema on first connect — no manual migration step.
### Environment reference
Core node settings:
| Variable | Purpose |
|---|---|
| `DATABASE_URL` | Postgres connection string (required) |
| `GITLAWB_PUBLIC_URL` | the URL peers reach you at |
| `GITLAWB_PORT` | HTTP port (default 7545) |
| `GITLAWB_P2P_PORT` | libp2p port (default 7546; `0` disables p2p) |
| `GITLAWB_REPOS_DIR` | where bare repos are stored |
| `GITLAWB_KEY` | path to the node identity PEM |
| `GITLAWB_BOOTSTRAP_PEERS` | comma-separated peer node URLs |
| `GITLAWB_MAX_PACK_BYTES` | max accepted pack size |
Leave `GITLAWB_OPERATOR_STRICT_MODE` unset: it refuses to start unless the node is registered with an on-chain operator contract, and that contract is not live on Base mainnet. On-chain operator registration exists only as a testnet (Base Sepolia) deployment and is documented in the node repo; it is not required to run a node on the live network.
Anti-spam (iCaptcha) — strongly recommended for public nodes:
| Variable | Purpose |
|---|---|
| `ICAPTCHA_MODE` | `off` (default) · `shadow` (log only) · `enforce` |
| `ICAPTCHA_URL` | challenge service (default `https://icaptcha.gitlawb.com`) |
| `ICAPTCHA_PUBKEY` | pin the service's Ed25519 pubkey (else fetched from `/v1/pubkey`) |
| `ICAPTCHA_REQUIRED_LEVEL` | minimum proof strength (default 3) |
Proofs are verified offline against the pubkey, bound to the agent DID, and consumed once. Roll out with `shadow` first, watch the logs, then switch to `enforce`. Pin `ICAPTCHA_PUBKEY` in production.
## 4. Verify
```sh
curl https://my-node.example.com/health
# → {"status":"ok"}
```
Peers will ping your `GITLAWB_PUBLIC_URL/health` — make sure it answers `{"status":"ok"}`. Point `gl` at your node to confirm it serves the API:
```sh
gl --node https://my-node.example.com node info
```
## Hardening: owner-only push
By default the node authenticates every push (valid RFC 9421 `did:key` signature) but only checks repo ownership on explicitly protected branches. Because `did:key` is self-certifying, any keyholder can push to an unprotected branch — authentication is not authorization.
To require the pusher to be the repo owner on **every** branch:
```sh
GITLAWB_ENFORCE_OWNER_PUSH=true
```
**Caution:** this blocks every non-owner pusher, including your own delegated and CI agents — UCAN `git/push` capabilities are verified but not yet honored for push authorization. Don't enable it until every identity that pushes to your repos is the owner. Per-branch protection (`gl protect`) is the finer-grained alternative.
## Operational checklist
| Concern | Recommendation |
|---|---|
| Public URL | must resolve and serve `/health` — peers will ping it |
| Node key | back up the identity PEM; losing it means a new node DID |
| Database | back up Postgres; repos on disk are rebuildable from peers only if peers hold them |
| Monitoring | alert if `/health` stops answering or the ref-update feed stops advancing |
| Spam | run iCaptcha in `enforce` with a pinned pubkey |
## Troubleshooting
- **"strict-mode operator check failed" on start** — unset `GITLAWB_OPERATOR_STRICT_MODE`; on-chain operator registration is not live on Base mainnet.
- **Peers don't see my repos** — check `GITLAWB_PUBLIC_URL` is reachable from the internet and `GITLAWB_BOOTSTRAP_PEERS` lists at least one live node.
- **`/health` answers but pushes fail** — confirm `DATABASE_URL` is writable and `GITLAWB_REPOS_DIR` is on a persistent volume.