@flashyos/bolt
v0.2.1
Published
bolt/1 — one secret, split across an estate. A hunt verified by commitment, in the finder's own browser.
Maintainers
Readme
@flashyos/bolt
One secret, split across an estate. A hunt verified by commitment, in the finder's own browser, with nothing sent anywhere.
npm install @flashyos/boltRead this first
An easter egg is usually a gag with a server behind it: you find the thing, you submit it, and a database somewhere decides whether you won. That is the one shape this estate cannot use. Every other claim these properties make is checkable by a reader without asking us — settlements, charters, tree heads — and an egg that required trusting a backend would be the only thing on the estate you had to take on faith.
So the hunt is verified the way a settlement is.
It proves that a finder holds every shard, because the digest of what they entered equals the digest published before anyone started looking.
It does not prove who they are, when they found it, or that they visited anything. There is no record of the hunt, by design: a finder can produce the proof offline and hand it to anybody.
How it works
Each property serves one shard, revealed to a visitor who finds the trigger. The estate publishes a commitment and nothing else:
commitment = sha256(shards joined by "-", in the register's property order)A digest gives away no shard. That is the whole point of a commitment, and it is what lets the hunt page hold the answer's fingerprint without holding the answer.
import { commit, verify } from '@flashyos/bolt';
const commitment = commit(['LATTICE', 'ASSAY', 'PLUMB']);
verify(['LATTICE', 'ASSAY', 'PLUMB'], commitment); // true
verify(['LATTICE', 'ASSAY', 'WRONG'], commitment); // falseverify runs client-side and offline. View the source of the hunt page and
check the check — that is the intended way to use it.
The document each property carries
.bolt/config.json, at the property's own root:
{
"bolt": "1",
"property": "flashyos.com",
"shard": "LATTICE",
"accent": "#12E29B"
}accent is the property's colour from the estate's brand kit, so the reveal
appears in that property's own ink rather than a generic gold.
Shards match /^[A-Z]{4,12}$/ — long enough to be memorable, short enough to
type from a phone, and cased so there is no question about what was entered.
The trigger
Type flashy anywhere on the page. Not a key sequence to look up: a word
somebody will hit by accident on a site with the word in its name, which is the
difference between an egg people find and an egg people are told about.
Order comes from the register
The shard order is the estate register's property order, filtered to live.
That file already decides which properties exist, so a property going live joins
the hunt in the same one-word edit — and a property that is not live cannot
become a dead end in it.
What is deliberately absent
No server, no analytics, no submission endpoint. The prize is claimed by showing the proof, and the proof is producible offline.
No shard in the hunt page. The page publishes the digest and the property list. It does not know the answer, which is what lets it be checked rather than believed.
Sealing a tier needs a deployed reading — 0.2.0 and later
cut() prints the block a person appends to SEALED, and from 0.2.0 it
refuses to print one at all unless it is handed evidence that every property
in the tier was observed serving its own word, fetched the way a stranger
would, within the last day.
Tier I was sealed over ten properties on 2026-08-31 and was unwinnable a week later: two had never carried a shard on a shipping branch, two more served no egg at all, every structural check passed the whole time, and a tier is permanent by design, so there is no undo. The precondition was written down and remembered rather than enforced.
The tier API lives at the ./tiers subpath — SEALED (the tiers already cut),
open() (the tier forming now), and cut() (which prints the next block):
import { cut, SEALED, open, DEPLOYED_READING_SINCE } from '@flashyos/bolt/tiers';
cut(shards, { playing: ['example.com'], surface: 'deployed', at: new Date().toISOString() });The estate takes the reading and proposes the seal with the tool, so nobody
fetches by hand: node tools/estate-bolt.mjs --fetch --out reading.json (from a
runner with egress — .github/workflows/bolt-reading.yml) then
node tools/estate-bolt.mjs --cut --reading reading.json, which seals over
exactly the properties the reading saw serving and leaves the rest for a later
tier.
surface has one accepted value: a reading of a checkout is not a reading of a
deploy, and this estate's own tooling once reported 24 of 28 properties playing
from working trees while the shipping branches said 9. The package does not
fetch — it runs in a browser, and a package that reaches the network is one
nobody can audit offline — so the evidence is an argument.
A caller written against 0.1.0 breaks here on purpose. Pin ^0.2.0 if you
seal tiers; DEPLOYED_READING_SINCE is exported so the figure is read rather
than remembered.
A shareable "I found all N" proof — bolt-proof/1, 0.2.1 and later
Solving a tier is private by design — the check runs in the finder's browser and
records nothing. bolt-proof/1 is the thing to SHARE afterwards: a token that
says "I completed Tier I" and that another finder can verify, with no server and
no spoiler. It lives at the ./proof subpath:
import { mintProof, verifyProof, encodeProof, decodeProof, BOLT_PROOF_SINCE } from '@flashyos/bolt/proof';
// A finder who holds the set mints a proof bound to a label they choose:
const proof = mintProof(shards, { tier: 'I', commitment, label: 'gord', nonce });
const token = encodeProof(proof); // paste this anywhere
// Another finder — anyone who also holds the set — verifies it offline:
verifyProof(decodeProof(token), theirShards); // true only if the sets matchTwo properties make it honest. It is spoiler-free: the token carries only
{ v, tier, commitment, label, nonce, sig } — never a shard — so sharing it
gives nothing away, and sig = sha256(version ⋅ tier ⋅ commitment ⋅ label ⋅
nonce ⋅ solution) needs the solution to produce, so a copied token cannot be
re-issued under someone else's label. And it is peer-verifiable, not publicly
verifiable: a commitment reveals nothing about its preimage, so only someone
who also holds the set can confirm a proof — the initiated confirm the
initiated. That is what an offline, serverless, spoiler-free construction can
honestly be; it is stated plainly rather than dressed up as universal proof. A
verifier who has not solved the tier is told to solve it first, because there is
nothing for them to check against. BOLT_PROOF_SINCE is exported so the figure
is read rather than remembered.
Licence
Apache-2.0. The spec and the clients are Apache so anyone can embed them.
