Protocol
How Odyssey turns first-person sensor data into a dataset AI labs can trust: signed at the sensor, anchored on-chain, verified by staked validators, and paid out to the people who captured it.
Overview
The next generation of models, especially robots and embodied agents, needs real-world, first-person data: what a person sees, hears, looks at and does. Odyssey is a network of capture devices, gateways and validators that produces that data with a provenance proof per sample.
| Problem | Odyssey's answer |
|---|---|
| Faked or synthetic uploads | Every clip is signed by a hardware key inside the device at capture time. |
| One person running many devices | One human, one device: each device is linked to a verified, anonymous human. |
| Datasets edited after the fact | Batch Merkle roots on-chain: changing any sample breaks its proof. |
| Checking everything doesn't scale | Optimistic acceptance plus random, staked spot-checks of 1 to 5 %. |
| Contributors aren't paid | Every license pays the contributors whose clips are in it. |
What's live today
The first slice runs end to end on testnets: devices sign samples, a gateway verifies and encrypts them, and every sample becomes an entity on Arkiv (Rabdi testnet). Labs sign in with a wallet, pay the OdsySubscriptions contract in test 0G on 0G Galileo, and get per-sample keys to decrypt what their subscription covers. 70 % of every payment goes to the contributors behind the dataset.
Metadata is public on Arkiv so anyone can search it and check signatures. Payloads and sensor readings are ciphertext; only admins and subscribers get the keys.
| Pipeline step | Vision | Today |
|---|---|---|
| Capture and sign | Secure element signs hash, time and witnesses | Device key signs content hash, kind, mime, time, lat/lon and sensors hash. Location is pinned to Bandra until GPS lands. |
| One human, one device | World ID per device | Registry on Arkiv binds a device key to a World ID nullifier, one device per human. /enroll verifies the proof, whose signal is the device address, and makes the signed-in wallet the payout address. |
| Filter | TEE gateway: blur, dedupe, quality | Signature, registration, ban and duplicate checks. A clip replayed from another human is a strike. No blurring or quality scoring yet. |
| Store | Encrypted batches on 0G | Encrypted per sample: inline on Arkiv up to 96 KiB, 0G Storage above that. |
| Anchor | One Merkle root per batch on-chain | Each sample is a readonly Arkiv entity. Batch roots on a long-lived chain are still to come. |
| Verify | Staked VRF committee | ConsensusRegistry is deployed on Galileo: allowlisted validators vote on each hex tile and two provable strikes ban a World ID. No staking or VRF yet; the consensus map under /mockups shows the design. |
| Pay | Rewards root per epoch | Labs pay the subscriptions contract in 0G. 70 % is split pro rata by samples to each device's payout wallet, published as a Merkle root per epoch, and claimed on-chain. |
Each sample on Arkiv
{
"device": "0x2466…8D8E", // recovered from the device signature
"worldId": "0x0235…200d", // nullifier bound at registration
"deviceType": "esp32-cam-glasses",
"mac": "24:0A:C4:00:00:01",
"kind": "sensor", // image · video · audio · text · sensor
"capturedAt": 1793918858,
"lat": "19.0596", "lon": "72.8295",
"geohash": "te7u3m8y4", // precision 9, powers radius search
"contentHash": "0x28d9…9571", // sha256 of the plaintext payload
"sensorsHash": "0x5c1e…a0f3", // sha256 of the plaintext sensors JSON
"storage": "inline", // or "0g" with "ogRoot"
"enc": "aes-256-gcm-v1",
"signature": "0x9b0e…41c",
"data": "<ciphertext>", // inline payloads only
"sensors": "<ciphertext>"
}Searchable and checkable by anyone, readable by subscribers
Anyone can re-check a sample's device signature, because it covers contentHash and sensorsHash. Checking the payload itself needs its key. Arkiv keeps an entity for about six months; a daily job extends what the retention policy keeps, and labs copy what they buy into their own storage.
Tracks
How the project maps to the sponsor tracks it targets: what is built, where, and where it stands.
Arkiv · the data layer
| What we built | Where | Status |
|---|---|---|
| Every sample is a readonly Arkiv entity: metadata, geohash, signature, encrypted payload up to 96 KiB | lib/schema.ts | Live-tested |
| Device registry, datasets, paid periods and reward epochs as gateway-owned entities | app/api/* | Registry and datasets live-tested; rewards not yet run live |
| Geo search on a geohash index | lib/query.ts | Live-tested |
| Retention job: extend what is worth keeping, let the rest and banned data expire | app/api/cron/extend | Built, not scheduled yet |
0G · payments, contracts and storage
| What we built | Where | Status |
|---|---|---|
| OdsySubscriptions on Galileo: 30-day dataset access paid in 0G, 70 % to contributors, Merkle reward claims | contracts/src/OdsySubscriptions.sol | Deployed, 14 tests; subscribe and claim not yet confirmed end to end |
| ConsensusRegistry on Galileo: validator median per hex tile, two-strike ban | contracts/src/ConsensusRegistry.sol | Deployed, 10 tests, hand-run live |
| 0G Storage for payloads over 96 KiB | lib/og.ts | Built, not yet confirmed with a large payload |
World ID · one human, one device
| What we built | Where | Status |
|---|---|---|
| A device key bound to a World ID nullifier, one device per human; the proof's signal is the device address | app/api/enroll | Built (World ID v4); not yet live-tested by us |
| Every sample carries the World ID that captured it | Samples.worldId | Live |
| Two provable strikes ban a World ID: no uploads, no new device, data unreadable | lib/consensus.ts | Contract run live; gateway path not yet end to end |
How enrollment works
On /enroll a signed-in wallet enters the glasses' address and MAC and approves in World App. The server checks the proof with World's developer portal and that its signal is that device address, so one human's proof cannot enroll another device. POST /api/devices is for an external registrar that verified World ID itself. The screen under /mockups is only a demo.
Deployed contracts (0G Galileo testnet)
| Contract | Address |
|---|---|
| OdsySubscriptions | 0xc3a946516f2f0CE3fc2065543cb0a8E9b105A54e |
| ConsensusRegistry | 0x83bea227e5D2C72f8F0F73E63175759D4E6055DC |
Access and payments
- Datasets are saved filters (area, kind, device model, time range) with a price in 0G per 30 days. New captures that match are included automatically.
- Payments go to the
OdsySubscriptionscontract, which enforces the exact price and recordspaidUntilin the same transaction. Renewals stack, up to 150 days ahead. - Contributors get 70 % of each payment (never less than 50 %). Each epoch the gateway splits it pro rata by samples to each device's payout wallet and publishes a Merkle root; contributors claim from Transactions. The treasury can never withdraw contributor funds.
- Keys are released per sample and only while a subscription covers it. Admins can read everything.
- The app asks for a wallet sign-in before Datasets, Explore, the dataset map and Transactions. Signing a message costs no gas; signing out also disconnects the site in the wallet.
- Lab ingest (
npm run lab:ingest) pulls subscribed datasets into the lab's own storage, re-checking every sample, with an option to keep only the samples the retention policy keeps.
Use it from an LLM (MCP)
Subscribers can search and read their datasets from Claude, Cursor or any other MCP client. It is retrieval only: the model you connect writes the answer, and it only sees what your wallet has paid for.
- Sign in on Datasets and click Create token in the “Use your datasets in an AI tool” card.
- Pick your client (Claude Code, Cursor, Claude Desktop or other) and paste the setup it shows. The server is hosted, so there is nothing to install or clone, and Claude Code works without its command-line tool through a project
.mcp.jsonand anODYSSEY_TOKENenvironment variable. The token lasts 7 days. - Ask your model things like “list my datasets” or “find samples that mention mangoes in the Bandra dataset”.
| Tool | What it does |
|---|---|
list_datasets | Your active subscriptions and when access ends |
search_samples | Keyword search over the text and sensor samples of one dataset, best matches first, with a snippet, place, time and content hash |
get_sample | One sample in full, decrypted, if a subscription covers it |
claude mcp add --transport http odyssey https://<your-host>/api/mcp \ --header "Authorization: Bearer <token>"
Limits of this first version
Keyword search only (no embeddings), over the newest 100 text and sensor samples per query. Images, audio, video and 0G-stored payloads are not returned. Tokens expire after 7 days and cannot be revoked earlier. There is no OAuth, so ChatGPT's connector screen cannot use it; the OpenAI API can, through an MCP tool with a header.
The pipeline
The full design. The table above shows which parts are live.
Data never goes on-chain. Encrypted clips live in decentralized storage; the chain holds one Merkle root per batch, the stakes, the challenges and the reward roots.
- Capture. The wearer double-taps; the glasses record a short clip and show REC to bystanders.
- Sign. The clip hash, timestamp and any witness co-signatures from nearby devices are signed inside the secure element.
- Filter. A gateway in a TEE checks the signature, drops duplicates (perceptual hash), blur and silence, and blurs faces and plates.
- Store and anchor. Clips are encrypted per batch and stored; one Merkle root per batch is anchored on-chain.
- Verify. A challenge window opens and a random, staked committee scores a sample of the batch.
- Pay. At the end of each epoch, a rewards root is published; contributors claim with a proof.
What a sample proves
Every sample a lab licenses comes with a record it can check on its own, without trusting Odyssey.
{
"clip": "0x3fa1…c09e", // sha256 of the encrypted clip
"device": "glasses-7c21e0", // device public key, linked to one verified human
"capturedAt": "2026-11-02T08:14:03Z",
"witnesses": ["glasses-a91f02", "glasses-55d0b3"],
"signature": "0x9b0e…41c", // secure-element signature over all of the above
"batch": "0x77d2…e810", // Merkle root anchored on-chain
"proof": ["0x…", "0x…", "0x…"], // Merkle path from clip to batch root
"score": 0.91, // validator committee score
"license": "Commercial"
}Tamper-proof, not truth-proof
The chain proves a sample hasn't changed since it was anchored. It cannot prove the scene was real; that comes from signing at the sensor, one-human-per-device, witnesses and validation. Each layer makes faking more expensive than capturing.
Validation
- Random committees. A verifiable random function picks validators and samples, so nobody can predict what will be checked.
- Commit, then reveal. Validators commit to hashed scores before seeing anyone else's, so they can't copy votes.
- Honeypots. Known-answer samples are mixed in; validators who get them wrong lose reputation, then stake.
- Challenges. Anyone can post a bond to challenge a batch during the window; a proven challenge slashes the gateway and pays the challenger.
Checking a neighbourhood
The map is cut into hexagons. For each hexagon and each day, we check a small random handful of the clips, the way a teacher spot-checks homework instead of reading every page.
- Too few clips or too few different devices in a hexagon? It waits. Nothing is decided yet.
- Otherwise the contract works out how many clips to check, and checkers (validators) look at them.
- Each validator says how many of the checked clips passed. The middle answer wins.
- If at least two thirds passed, the hexagon is accepted. If not, it is rejected. Payouts are meant to follow accepted hexagons, but today they are not connected: rewards come from subscriptions.
Two strikes and you're out
If a device is caught with provable bad data twice (a faked signature, a copied clip, an impossible location), its World ID is banned. Its data from the first strike onwards is left out, and it can't register another device. A wrongly banned person can be un-banned by the admins. Being outvoted is never a strike.
| Setting | Plain meaning | Starting value |
|---|---|---|
| Hexagon size | How big a neighbourhood is (set per dataset) | about a street, res 8 |
| Time bucket | How long one check covers | 1 day |
| Minimum clips / devices | Below this the hexagon waits | 20 clips, 3 devices |
| Check rate | Share of clips that get checked | 3%, never below 1% or 3 clips |
| Pass mark | Score a clip needs to count as good | 70 out of 100 |
| Needed to pass | Share of checked clips that must pass | two thirds |
| Validators per hexagon | Votes needed to finish | 5 |
| Strikes | Provable alerts before a ban | 2 |
Where the numbers live
The contract is contracts/src/ConsensusRegistry.sol. The shared settings are set once at deploy from contracts/.env.example; each dataset picks its own hexagon size, check rate and pass mark within them.
It is live on 0G Galileo at 0x83be…55DC. The gateway checks it on every upload, registration and read, so a banned World ID can't upload, register a new device or have its data decrypted. It is a testnet deploy with three throwaway validators and has not been audited.
Stake and slash
| Role | Stakes | Slashed for |
|---|---|---|
| Contributor | Nothing: one-human-per-device and the device key are the spam filter | Never slashed; rewards withheld and the device banned |
| Gateway | Medium | Anchoring a batch that hides bad or duplicate data |
| Validator | Medium | Failed honeypots, missed reveals, losing a challenge |
| Challenger | Bond per challenge | Frivolous challenges |
Slash on evidence, never on opinion
Stake is only taken on objective evidence: a bad signature, a duplicate, a failed honeypot, or a sample proven fake. “The majority disagreed” is never enough. Voting weight per validator is capped to blunt whales and collusion.
Rewards and cash flow
Labs pay for datasets in 0G on Galileo. The contract splits every payment on the spot, and contributors collect their share by epoch with a Merkle proof.
One payment, split on-chain. Gas is paid by whoever sends each transaction, and the gateway wallet pays Arkiv and 0G Storage from its own funds, not from this revenue.
| Step | Who | Money moves |
|---|---|---|
| Subscribe | Lab | Pays exactly the dataset price plus gas. Access lasts 30 days; renewals stack, up to 150 days prepaid |
| Split | Contract | 70 % to the contributor pool, the rest to the treasury. The owner can change the share for future payments, never below 50 % |
| Publish an epoch | Owner | Splits the pool across payout wallets pro rata by each device's sample count and publishes one Merkle root. The contract refuses a total above the pool |
| Claim | Payout wallet, or anyone for it | Pays the account its share. The claimer pays gas, and a root can never pay out more than its published total |
| Withdraw | Owner | Moves the treasury balance only |
See your own numbers
The /analytics page shows them live, in 0G: a contributor wallet's earnings per reward epoch and what is claimable, a lab wallet's spend per month and dataset, and for admins the revenue split between contributors and the treasury. There are no dollar figures on a testnet.
Worked example
A lab pays 0.01 0G. 0.007 goes to the contributor pool and 0.003 to the treasury. The dataset has samples from three devices: A has 60, B has 30 and C has 10 but no payout wallet. At the next epoch A's wallet gets 0.0042 and B's gets 0.0021; C's 0.0007 stays in the pool for a later epoch.
reward = base × quality score × rarity # rarity rewards under-covered places, activities and languages # today: pro rata by sample count, no quality score or rarity yet
Track guide
One track at a time: what to open or run to see it, and what is not confirmed yet. The full step list is TESTING.md in the repo.
Arkiv · the data layer
- Run
npm run simulate -- 5to send five signed samples. - Open
/exploreand search 19.0596, 72.8295 with a 1 km radius. The samples appear on the map, straight from Arkiv. - As an admin,
/activitylists the recent Arkiv writes with transaction links (the RPC only serves about the last 25 minutes).
0G · payments, contracts and storage
The money is Figures 2 and 5, and consensus is Figure 4. To see it:
- As admin, create a dataset on
/datasets. Listing it sets its price on the contract. - As a lab wallet, subscribe with 0.01 0G. Payloads unlock and
/activityshows 0.007 0G to contributors. - Run
npm run rewards:publish, then sign in as the payout wallet and press Claim on/activity. A second claim reverts withAlreadyClaimed. /analyticsshows the same money as earnings per epoch and spend per dataset.- Consensus has no screen yet: drive it by hand with
cast(TESTING.md part 3).
World ID · one human, one device
- Set the World ID variables (a staging app works with
simulator.worldcoin.org), then open/enroll. - Enter a device address and MAC and approve in World App or the simulator. The device appears on
/capturewith your wallet as its payout. - Enroll the same device again (
409 already registered), or use the same human for a second device (409 already has a device). - After a ban (TESTING.md part 3c), enrolling returns
403. Two provable strikes ban a World ID; being outvoted never counts.
Not confirmed end to end yet
Subscribe and claim, a payload over 96 KiB on 0G Storage, and World ID enrollment are built but not yet confirmed on testnet. Validators are unstaked and tile verdicts do not gate payouts: rewards follow subscriptions only.
Why it scales
- On-chain cost is flat: one root per batch, not one transaction per sample.
- Verification grows with the sample, not the dataset: 1 to 5 % is checked, at random.
- No real-time coordination: gateways and validators scale out independently.
- An existing chain: Odyssey is a data protocol on an L2, not a new blockchain.
Privacy and consent
- The glasses show REC while capturing, so bystanders know.
- Gateways blur faces and number plates before anything is stored.
- Each sample has its own encryption key, derived from one gateway secret. Destroying that secret forgets every sample at once (
crypto-shredding); per-batch keys will make it selective. - Today, metadata (time, place, device, MAC, World ID nullifier) is public on Arkiv so it can be searched. Hashing the MAC and blurring faces at the gateway are next.
- Contributors stay anonymous: the network knows a device belongs to a verified human, not which one.
Roadmap
Phase 1 · Prove it
Device signing, uploads, batch roots on-chain, test-token rewards. The team does the spot-checks.
Done: signed uploads, device registry, encrypted storage on Arkiv and 0G, geo search, dataset subscriptions on a contract with a contributor split, and lab ingest. Next: batch roots on a long-lived chain, real hardware with GPS.
Phase 2 · Stake it
Permissioned staked validators, honeypots, challenge window and slashing.
Done: the consensus contract on Galileo (validator median per tile, two-strike ban) and its enforcement in the gateway. Next: staking and slashing, commit-reveal, honeypots and a challenge window.
Phase 3 · Open it
Permissionless validators, TEE gateways, rarity rewards and the lab marketplace with licensing.
Phase 4 · Value it
Reward data by how much it actually improves a model.