Ledger
What Freeweights costs, who pays, how anyone can check that the ledger was not edited, and what each funding goal unlocks.
The ledger lists every dollar in and out of Freeweights. It is a public file you can read and check.
How the ledger works#
The source is one CSV file per month in the public repository. Each row is one money movement, or one service on a free tier. A free tier is recorded as a row with 0.00, because that is a real fact.
- Money in is recorded by type: support, sponsor, Allternit share, credit or in-kind.
- Money out is backed by an invoice or receipt reference: hosting, storage, email, code or other.
- In-kind capacity (for example a sponsor's disk) is logged at the value the sponsor states, with consent.
- Names of supporters appear only with their consent.
- Never a credential, token or account secret.
The first rows are zeros: Cloudflare Pages, Workers, D1 and R2, GitHub, and Cloudflare Email Routing, all on free plans at Stage 0.
Why it is tamper-evident#
There is no blockchain and no token. We use a hash chain, the same idea Git uses.
Each row becomes an entry with a sequence number. Each entry holds the hash of the entry before it, and its own hash covers all its fields. Change one amount in an old row and its hash changes. The next entry no longer matches, and so on to the end. The newest hash is written in a small head file, and that file is signed with the Freeweights signing key. Anyone with the public key can check the signature.
This does not stop us from adding rows, and it does not prove a row is true. It proves that the history you see is the history we signed. If we ever rewrite the past, a copy someone saved earlier will not match. Details are in the ledger chain doc.
| Seq | Date | Item | Amount | prev_hash | entry_hash |
|---|---|---|---|---|---|
| 1 | 2026-11-14 | Cloudflare Pages Free plan (Stage 0) out · hosting | 0 USD | 00000000…0000 | 335f37a1…df78 |
| 2 | 2026-11-14 | Cloudflare Workers Free plan (Stage 0 read API and redirects) out · hosting | 0 USD | 335f37a1…df78 | d0861693…bed0 |
| 3 | 2026-11-14 | Cloudflare D1 Free plan (Stage 0 database) out · storage | 0 USD | d0861693…bed0 | a53a61d0…a1b8 |
| 4 | 2026-11-14 | Cloudflare R2 Free tier 10 GB (Stage 0) out · storage | 0 USD | a53a61d0…a1b8 | b70295d3…7562 |
| 5 | 2026-11-14 | GitHub Public repository (free) out · hosting | 0 USD | b70295d3…7562 | 1b691c81…2641 |
| 6 | 2026-11-14 | Cloudflare Email Routing Free email routes (Stage 0) out · email | 0 USD | 1b691c81…2641 | 6c8154c7…e0b6 |
Verify it yourself#
From the public repository:
python3 scripts/verify_ledger.pyIt prints PASS or FAIL. On FAIL it names the first entry that does not match. It needs Python 3 and the minisign program. The public key is spec/keys/freeweights-v0.pub (key id 2DC28CC7B26A283B).
You can also do it by hand: the head file is ledger/head.json, its signature is ledger/head.json.minisig, and the check is minisign -Vm ledger/head.json -p spec/keys/freeweights-v0.pub. The chain is ledger/chain.jsonl, one JSON entry per line.
Verify it yourself, from this site
$ curl -O https://freeweights.allternit.com/ledger/chain.jsonl -O https://freeweights.allternit.com/ledger/head.json -O https://freeweights.allternit.com/ledger/head.json.minisig
$ minisign -Vm head.json -P RWQ7KGqyx4zCLXtUFOqvfv8L3g+8fpKJ1FsuxPyOYMF+4KufbUxKq1Oq
$ python3 - <<'PY'
import json, hashlib
prev = "0" * 64
for line in open("chain.jsonl"):
e = json.loads(line); h = e.pop("entry_hash")
body = json.dumps(e, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode()
assert e["prev_hash"] == prev and hashlib.sha256(body).hexdigest() == h, e["seq"]
prev = h
print("chain ok, last entry_hash", prev)
print("head says", json.load(open("head.json"))["entry_hash"])
PYThe last two lines must print the same hash, and minisign must say the signature is valid for key 2DC28CC7B26A283B.
Catalog snapshots and takedowns#
A second hash chain, ledger/registry.jsonl, records what the catalog lists and what was removed. It is kept apart from the money chain so the money totals stay exact.
- Snapshot. Each signed catalog build takes the sha256 of every published manifest, sorts the pairs (entry id, hash) by id, writes one line
<id> <hash>per pair, and hashes those lines into one root. When the root changes, the build adds a snapshot entry to the chain and signsledger/snapshot.json, which lists every pair. If a manifest is changed or removed later, the root no longer matches the signed one. - Takedown. Every removal adds one entry: the date, the entry id and a reason class (for example copyright). No names, no addresses, no report text.
The head of this chain is signed like the money chain: ledger/registry-head.json and its .minisig.
- Latest snapshot
- 3908851ee7c82dca3371bd117679cbbac2d9a3ca025b0a1a425472a6c5f3fe8e
- Manifests
- 6362
- Recorded
- 2026-11-15 08:04 UTC, registry seq 4
- Signatures
- snapshot valid, registry head valid (key 2DC28CC7B26A283B)
- Registry chain
- 4 entries: 4 snapshots, 0 takedowns; links and hashes ok
- Files
- snapshot.json · .minisig · registry.jsonl · registry-head.json · .minisig
Check a snapshot yourself
$ curl -O https://freeweights.allternit.com/ledger/snapshot.json -O https://freeweights.allternit.com/ledger/snapshot.json.minisig
$ minisign -Vm snapshot.json -P RWQ7KGqyx4zCLXtUFOqvfv8L3g+8fpKJ1FsuxPyOYMF+4KufbUxKq1Oq
$ python3 scripts/verify_ledger.py --snapshot-against https://freeweights.allternit.comThe last command, run from the public repository, downloads every manifest the snapshot names, recomputes the root and checks it, the signatures and the chain.
Costs by stage#
These are plan figures for what each stage can cost per month. They are estimates, not invoices.
| Stage | What is added | Cost a month |
|---|---|---|
| 0 | Coordinator only: Pages, one Worker, a database, 10 GB object store, public repo | 0 USD |
| 1 | Tracker, hub server, up to 1 TB | 0 to 15 USD |
| 2 | 6 TB web-seed origin | 42 to 90 USD |
| 3 | 50 TB | 350 to 750 USD |
| 4 | 500 TB on donated mirrors | 0 if donated, or 3,500 to 7,500 USD if paid |
Funding goals#
A stage starts when three months are prepaid or pledged in writing. The raised amounts below are the real figures in ledger/goals.json. At this version they are all 0.
| Goal | Unlocks | Amount | Raised |
|---|---|---|---|
| 1: Tracker and hub (Stage 1) | Our tracker, hub server, seeds; up to 1 TB hosted. A free VM or a seedbox with written clearance can do this too. | 45 USD (3 months at 15) | 0 USD |
| 2: Origin (Stage 2) | A web-seed origin on Backblaze B2 behind Cloudflare, about 6 TB. Permissive models move to Hosted. Uploads open. | 126 to 270 USD, prepaid | 0 USD |
| 3: Storage server (Stage 3) | One storage server or object storage, 50 TB. Community repos and more quants. | 1,050 to 2,250 USD, prepaid, or a sponsor or credits | 0 USD |
Hosting is prepaid before December 31 so that money in and the costs it covers land in the same year.
Support#
Support is not open yet. There is no payment link. It opens after a separate bank account, the support terms page, an accountant's written view and a Minnesota charitable-solicitation check are done.
When it opens, this line goes with every support link: Support goes to Allternit LLC. It is not a charitable gift and is not tax-deductible.
Support is applied first to the running costs in this ledger. It buys no badge, ranking, placement, access or early features. You may ask for a refund within 30 days.