A vault that listens for your heartbeat.
Locket wraps a crypto asset in a small encrypted file you can hand to the people you trust today. They hold it, but they can't touch it. If your heartbeat ever goes missing for longer than a window you chose (a day to 180 days), the file opens for them. Until then, and always, your own key opens it. Change your mind later and you can take a locket back for good.
Built on Unicity, where an asset is a self-contained file and the rules for spending it live inside the file itself. Background reading: the Unicity whitepaper and the developer portal.
created with love by @0XM0RA
Testnet preview. Do not seal real funds. Every network call targets the Unicity testnet, and the badge in the app never comes off.
npm install
npm run dev # http://localhost:3000
npm test # 145 unit tests: crypto, envelope, .locket format, predicate, anchor, guardian, connect, DM, relay pulses, revocation, identity derivation, backup, notify, calendar, amounts
npm run build # production buildNo environment variables, no secrets, no backend. Deploy notes for someone who has never used a terminal live in DEPLOY.md.
| Piece | Today | Notes |
|---|---|---|
| Identity and keys | live testnet | BIP39 + secp256k1 via the Sphere SDK, created in the browser |
| Test coins (UCT) | live testnet | self-minted on the v2 token engine; there is no faucet |
| Heartbeat | live testnet | each beat lands as a certified state transition on the aggregation layer (delegated anchor key, deed-pinned) and publishes to the relays; signed local fallback |
| Heartbeat identity | live | derived from a wallet signature, so any device holding the wallet rebuilds the same one; older identities keep beating, and re-importing your own file rescues its clock |
| Vault backup | live | one passphrase-sealed file carries the vault list, received files, and heartbeat keys to a new device, merged on restore |
Deed signatures in .locket files |
live | real wallet-key signatures, verifiable offline |
| Encryption | live | a random content key under AES-256-GCM, wrapped to every wallet key named in the deed (ephemeral ECDH); key-only by default, with an opt-in passphrase door (PBKDF2 310k) for recipients without a Locket wallet |
| Handover over Sphere DMs | live testnet | the sealed file rides an end to end encrypted message to a @nametag |
| Sphere Connect | live testnet | Connect protocol 2.1: extension, embedding frame, or the hosted wallet's own popup host; sign/mint/DM as wallet-approved intents. A wallet lock keeps the session alive and says so; only a disconnect stands it down |
| The silence clock | live testnet | recipients verify anchored beats with BFT inclusion proofs and relay events with the owner key, and the clock fails closed when the network doesn't answer |
| The window's enforcement | preview | who-may-claim is still client-checked; time predicates aren't public yet |
| Taking a locket back | preview | an owner-signed revocation rides the relays and the aggregation layer; Locket clients refuse a retired file for everyone but the maker, and a device never forgets one it verified |
| Staged release | live | one seal can make two lockets: words on the shorter window, coins waiting behind a longer one |
| Claim settlement | preview | nothing moves at sealing; claiming mints the amount to the named recipient (or the owner); moving the original tokens under a network-enforced predicate is the roadmap |
| Guardian | live testnet | delegated heartbeat-only key; --relay mode publishes verified beats to the relay and lands them on the aggregation layer, and imported beat files (script or Astrid capsule) reach both the moment they verify |
The longer, honest version lives at /docs in the app.
lib/crypto/vault.ts WebCrypto: PBKDF2 (310k) + AES-256-GCM envelopes
lib/crypto/envelope.ts the key layer: content keys wrapped to wallet
keys (ephemeral ECDH + HKDF + AES-GCM)
lib/sphere/ Sphere SDK wiring; wallet state is encrypted
before it ever touches IndexedDB
lib/sphere/pulse-anchor.ts heartbeats as certified state transitions on
the aggregation layer, verified with BFT
inclusion proofs; the fail-closed epoch scan
lib/sphere/pulse-relay.ts heartbeats as signed relay events, one round
per relay, reachability reported honestly;
revocations ride the same wire
lib/sphere/pulse-identity.ts the wallet-derived pulse identity: same
wallet, same identity, on any device
lib/locket/backup.ts the whole device state as one passphrase-
sealed file, merged on restore
lib/locket/predicate.ts the SilencePredicate interface and both
implementations (Unicity + faithful local preview)
lib/locket/file.ts the .locket format v2: LCKT magic, envelope
header (key wraps + optional passphrase door),
AES-256-GCM
lib/locket/guardian.ts heartbeat-only key delegation and verification
lib/sphere/dm.ts sealed lockets over encrypted Sphere DMs
lib/sphere/connect.ts Sphere Connect (bring-your-own-wallet handshake)
public/guardian.mjs the downloadable Guardian agent
capsules/locket-guardian the same Guardian as an Astrid OS wasm capsule
app/ landing page, vault, seal, receive, guardian, docs
- A tap in the app (or a browser reminder at 80% of the window).
guardian.mjs, a dependency-free Node script with a delegated heartbeat-only key.- An Astrid OS capsule: the same agent as a sandboxed wasm32-wasip2 component, built with the published Astrid toolchain. Campaign details in SUBMISSION.md.