Introducing narwal

2026-08-21

Narwal is an experimental Git host. It speaks Smart HTTP to a stock git client, stores every push as an entry in a write-ahead log in S3, and treats the repositories on its own disks as a cache it is free to throw away.

The design copies the storage idea from Cursor's Git at any scale. It does not copy the rest of that system, and it is not a GitHub: there is no web UI for code, no pull requests, and no SSH.

The log is the repository

A push is not acknowledged until its pack and its metadata are in S3 and a compare-and-swap on one index object has landed. That CAS is the commit point. Before it, nothing happened; after it, the push is durable on every node, whether or not any particular node has noticed yet.

Local bare repositories are ordinary git repositories on local disk, built by replaying the log. A node can lose one at any time — the next request rebuilds it from S3. There is no routing database, no primary election, and no RDS.

You claim a name by pushing to it

There is no signup. You generate a token yourself — it is nwl_ followed by 64 hex characters, so openssl rand -hex 32 is a complete generator — and push:

git -c http.extraHeader="Authorization: Bearer $NARWAL_TOKEN" \
    push https://gitwal.io/my-project.git main

The first valid push to an unclaimed name takes it, and the sha256 of that token becomes the first entry on the repository's push ACL. The server stores only the hash; it never sees a token it could leak back to you. Repositories start private.

Names are flat — one segment, no owner/name — and validation happens before the claim, so a malformed or oversized push cannot reserve a name it was never entitled to.

Every repository can explain itself

Each repository has a monitor page at /{name}/monitor: the S3 index etag against this node's cache etag, the refs, the WAL entries with their sizes and digests, and which nodes are currently holding a warm cache. It is one self-contained HTML document with no scripts and no client-side fetches, so it still tells the truth on a host that has lost its network.

It reports only what the host can actually observe. It does not call the EC2 or load balancer APIs to guess at fleet health, because that is not health it owns.

Where it is going

It works, and it is slow in places we can name. Push cost currently scales with how much history a repository already holds rather than with the size of the push, and the monitor reads every WAL entry serially before it renders. Both are written down in the backlog with the measurements behind them, alongside the parts of the Continuity design that are still missing — compaction, checkpoints, and a real answer for how many pushes per second this thing can take.

Updates will land here.


remote:

blog · gitwal · AGENTS.md