ETHOnline 2026 · Hedera · Ledger · Bazantic

Tuesday's key doesn't exist
until Tuesday.

Give an autonomous agent a budget — or any secret: an API key, a credential, a token — on a schedule, where each period's key is encrypted to the future and cannot be used, leaked, or coerced open before its time. Not by the agent. Not by you.

Try the live demo How it works
drand beacon · round · +1 every 3s
agent · in period 1, reaching for period 3
$ agent.unlock(period=3)
Error: NOT_YET — key for period 3 does not exist until round 1234567
# not a permission check. the decryption key has not been
# published by drand yet. it exists for no one.

$ # …the clock reaches period 3's round…
$ agent.unlock(period=3)
✓ key unlocked · paying x402 service on Hedera · settled ✓

In plain English

Like an advent calendar — for money.

An advent calendar has little doors, one per day. You can't open tomorrow's door today — the date simply hasn't arrived. Notyet does exactly that with an AI assistant's spending money.

1

You set it once

Hand your assistant a sealed budget for each day — say $20 a day for a month — and walk away. You don't keep a copy of any key.

2

It spends on schedule

Each day's envelope opens by itself, on time, unlocked by a public clock that ticks for everyone. The assistant pays for what it needs — no passwords, no company holding your keys.

3

Nothing can be rushed

If the assistant is tricked or hacked, it can only ever touch today's envelope — never the whole month. Tomorrow's simply doesn't exist yet.

That's the whole idea. Everything below is how we make it true with cryptography instead of trust.

The problem

Every agent scheduler is a server holding every future key.

Autonomous agents need authority on a schedule — daily budgets, per-shift credentials, windowed signing. Today there are two ways to give it, both broken:

Approach A

Hand it everything up front

A compromised or prompt-injected agent burns the whole month in an hour. One bad instruction, total loss.

Approach B

A server releases keys just-in-time

Cron, a secrets manager — something holds every future key. It's the honeypot, the single point of failure, and the coercion target.

Session keys solve expiry — authority can end. Nothing solves start. Authority always exists the moment it's issued. So we deleted the server.

How it works

One vault. Keys that unlock themselves on time.

The owner deposits into a single PeriodVault contract on Hedera and commits a schedule: for each period the vault stores the spend key's address, a budget, a [start, end] window, and a per-transaction ceiling. Each spend key is timelock-encrypted (tlock) to a future round of the drand beacon — a threshold network publishing a signature every 3 seconds. That signature is the decryption key, and it does not exist until the round happens. The owner walks away holding nothing usable; the agent holds only ciphertexts. No standing wallets, no key server.

🔒
drand / tlock

The lock itself

Keys are born on schedule. Try to unlock a period early and it throws NOT_YET — the decryption key hasn't been published, so it exists for no one, the owner included.

🔑
Ledger

Three authorities, device-only

The issuer key lives on the device (Ledger Device Management Kit, headless on Speculos) and does three things only it can: signs the schedule (root of trust), co-signs any withdrawal over the per-tx ceiling (proven on-chain — big spends need a human tap), and holds the audit view keys (the agent seals receipts it can never reopen; only a device tap opens the books). The agent holds none of them.

Hedera · PeriodVault

One contract, not N wallets

To spend, the agent calls withdraw(i, amt) with the unlocked key. The contract enforces, on-chain: the window (a key is useless before and after its period), identity (ecrecover must match the committed key), and the budget cap. Funds release → a real x402 pay-per-call settles via Blocky402; encrypted receipts land on HCS.

🔗
MCP · Bazantic

Any agent can call it

The whole capability is exposed as MCP tools, so other agents pay through Notyet — agent-to-agent payments that inherit the one-period blast-radius bound.

STEP 1
Deposit & commit
Owner funds the vault (Ledger-approved) and commits each period: key address, budget, window, ceiling.
STEP 2
Timelock
Each spend key is sealed to its drand round and wiped. The agent holds only ciphertexts.
STEP 3
NOT_YET
Try a future period early → the key can't be decrypted → the vault won't release.
STEP 4
Unlock
On its round, drand's signature decrypts the key.
STEP 5
Withdraw → x402
Signed withdraw passes window + budget + ceiling on-chain; funds pay the x402 service.
STEP 6
Audit / reclaim
Scoped view key opens one period's receipts. Owner reclaims unspent funds — only after a period ends.

One chain, no bridge: the vault holds the money, the policy the agent must satisfy, and (via HCS) the audit log — there's nothing to bridge. A compromised agent can still spend at most one period's budget, and never a period whose window is closed.

How Notyet improves on Hedera's scheduled transactions. A scheduled transaction (HIP-423) is already a strong primitive — post a transfer pending and let it execute on time — and Notyet builds on it: in one settlement mode it posts exactly such a pending transfer. But on its own the pending transaction still waits on a signature that already exists, so the authority to spend is sitting there ahead of time. Notyet closes that gap by locking the key, not just the transaction: the pending transfer needs a signature whose key doesn't exist until its drand round. Same on-time execution — with nothing to trigger, leak, or coerce early in the meantime.

Why it matters

Every one of these was a key that existed before it was needed.

Real, reported incidents. Notyet's keys don't exist before their time — so there's nothing to drain, leak, or coerce early.

Who it's for

Pre-commit the schedule. Walk away. Nothing can be pulled forward.

Anywhere an autonomous agent spends money on a cadence, the same rule holds: a bad day costs one period, never the whole plan.

DAO / fund → trading bot

Daily budget it can't front-run

The bot trades within today's allowance. Hacked on day 3 → it loses one day, not the treasury.

Company → procurement agent

Finance signs once, then leaves

The month is pre-signed on Ledger and posted to Hedera. No standing key for anyone to steal or subpoena.

Research fleet → paid APIs

One x402 key per shift

Each shift unlocks its own key; a leaked one dies at shift end. Every call logged to HCS for audit.

You → personal assistant

A daily allowance for tools

Your agent gets, say, $10/day for data and APIs. Prompt-inject it and the blast radius is one day.

Creator → autonomous ops

A week of tipping or ad spend

Pre-fund a week of promos or tips. The agent can't blow the quarter on one bad prompt.

Treasury → streamed grants

Tranches that unlock on time

Grant tranches decrypt on their date. No multisig ceremony can release next month's early.

Live demo · Hedera testnet

Issue a schedule. Watch a key refuse to exist.

Real, on Hedera testnet — no slideshow. One click runs the whole loop: issue a schedule, hit a real NOT_YET, wait for the drand round, then unlock and pay — with a HashScan link at every step. Same window + budget policy, enforced on-chain by the PeriodVault — see Proof.

Or explore by use case — a real budget an agent could run, then issue it yourself
Use case
periods

No schedule yet — pick a use case, then click Issue and try a locked period.

How it compares to a plain scheduled transfer — the primitive NotYet builds on, and hardens
HIP-423 · hardened

A Hedera scheduled transaction (HIP-423) is posted pending and fires on time — a solid primitive. But it sits ready and only waits on the clock. NotYet adds the missing lock: it timelocks the key the transfer needs, so nothing can fire early. Post one below, then try to execute it before its round — it can't.

execute in send ℏ → merchant
Audit — one period's view key decrypts only that period's receipts, nothing else
period

↑ This hosted demo derives the audit view key server-side and keeps withdrawals under the ceiling — Railway has no hardware. The device-born path (audit keys reconstructed from a Ledger tap; over-ceiling withdrawals that halt for on-device approval) runs in full-demo.ts — that's what the demo video shows. Both enforce the same scoping and on-chain policy; only who holds the key differs. Each browser gets its own private schedules; they reset when the demo redeploys — the on-chain vault and every HashScan link above persist regardless.

Recent settlements — real x402 payments already settled by this demo, live from Hedera
merchant account ↗

loading recent settlements…

Proof, not promises

Nothing here is a slide.

Every claim on this page points at a live testnet artifact you can open right now — the signed schedule on Hedera, the on-device issuer signature, and a real settled payment.

Built for three tracks — each load-bearing

⚡ Hedera

The payment rail

A real x402 settlement through Blocky402, the PeriodVault that gates every spend by time + budget on-chain, and the HCS audit log — money, policy and receipts on one chain.

🔑 Ledger

The root of trust

The device signs the schedule, co-signs any over-ceiling spend, and holds the audit view keys. The agent never holds authority it could leak or be coerced into using.

🔗 Bazantic

The reach

The whole capability is an MCP tool + hosted gateway, so any agent adopts time-gated spend in one line and inherits the one-period blast radius — no custom code.

🔑 The device does three things only it can

1 · Signs

The schedule

One on-device tap signs the whole plan — the trust anchor. Tamper with the rules and the agent refuses to act.

2 · Co-signs

Over-cap spends

Small spends are autonomous; anything over the per-tx ceiling reverts on-chain until the device approves. gate:vault:ledger — 3/3.

Ledger device screen: sign message notyet:approve withdraw over per-tx cap real device prompt · Ledger (Speculos)
3 · Holds

The audit keys

The agent seals receipts to a key it can never reopen. Only a device tap reconstructs it to open one period's books.

Ledger device screen: sign message notyet:view:0 real device prompt · Ledger (Speculos)
MCP · Bazantic

Any agent can call it

The capability is an MCP server (notyet_status, notyet_pay): other agents pay through Notyet and inherit the timelock — they can only ever spend the one period whose key exists.

recipe ↗  ·  mcp-server ↗

Ledger · owner mode

The device can own the vault

Beyond approving, the Ledger can be the vault's on-chain owner: deploy and commitPeriod are signed on the device and submitted through the Hedera JSON-RPC relay. We deployed a vault whose owner() and approver() are both the device — one identity, no separate operator key.

0xDad7…6D8D   gate:vault:relay ↗

Hedera · x402

A real settled payment

An unlocked period key paid the x402 service through the keyless Blocky402 facilitator — a SUCCESS crypto-transfer on Hedera testnet, no API key, no subscription.

settlement on HashScan ↗

Hedera · account

Where the money lands

The merchant account that receives every settlement. The vault releases at most one period's budget per withdrawal — a hacked agent can spend today's allowance, never the treasury.

0.0.10436969   account ↗

Hedera · PeriodVault

The policy is a live contract

One vault gates spending by time, not by wallets: each period commits address(k_i), a budget, a [start,end] window and a per-tx ceiling. Withdrawals enforce all four on-chain — future, expired, over-budget and over-limit all revert. This is the live demo's money path; gate passes 5/5.

0.0.10471808   contract ↗

drand · quicknet

The clock nobody controls

A public threshold beacon, one signature every 3 seconds. That signature is the only thing that decrypts a period's key — and it does not exist until the round arrives.

52db9ba7…   beacon info ↗

Source

Run it yourself

Every primitive above, plus gate scripts that prove them: npm run gate does a tlock roundtrip and a live Hedera settlement before anything else.

GitHub ↗  ·  architecture ↗

Testnet throughout — no real money. Honest scope in LIMITS.md.

For builders

Two ways in: call it, or build on it.

Most agents don't need our code at all — they reach NotYet as an MCP tool and inherit the one-period blast radius for free. If you're building the agent itself, the SDK is a few lines.

MCP — one line, no code 🔗 Bazantic — any agent integrates easily

Any agent adopts NotYet

Add one MCP server and any agent — Claude, Cursor, a LangChain bot — gets time-gated spend authority. Three of the four tools are read-only and need no config. A hacked caller can still spend only the one period whose time has come.

add-notyet.sh
// add the NotYet MCP server (one line)
claude mcp add notyet -- npx tsx bazantic/mcp-server.ts

// then any agent calls these tools:
notyet_explain()              // what it is + how to integrate
notyet_status("0.0.123456")     // locked | ready per period
notyet_verify(topicId, issuer) // signed by who I trust?
notyet_spend(topicId, issuer, 0) // unlock → pay (NOT_YET if early)

// also hosted over HTTP via the Bazantic gateway (its own toolset)
SDK 📦 publicly usable · on npm

Or drive it yourself

Building the agent loop directly? Import the SDK: read the schedule, verify the Ledger signature, unlock on time, and settle — the same primitives the MCP server wraps.

agent/loop.ts
// npm i @keccak002/notyet
import { resolveSchedule, decryptCiphertext,
  signWithdraw, withdraw, payX402, isNotYet } from "@keccak002/notyet"

// 1 · read the rules from Hedera (HCS) + verify the issuer
const schedule = await resolveSchedule(topicId, trustedIssuer)
const p = schedule.periods[now]

try {
  // 2 · unlock the key (does not exist before its round)
  const k = (await decryptCiphertext(p.ciphertext)).toString()

  // 3 · withdraw from the vault (window+budget on-chain)…
  const sig = await signWithdraw(k, { i: p.vaultIndex, ... })
  await withdraw(client, p.vaultContractId, { i: p.vaultIndex, ..., agent: sig })

  // 4 · …then pay the x402 service, settled on Hedera
  const { hashscan } = await payX402(serviceUrl, agentCreds)
} catch (e) {
  if (isNotYet(e)) return // NOT_YET — retry on its round
  throw e
}
Beyond payments 🔑 same lock, any secret

A spend key is just one thing you can seal to a time

The same timelock hides any secret — an API key, a database credential, an OAuth token. Hand the agent the ciphertext up front; it gets nothing until the moment you scheduled. No secrets server to breach or coerce — a leaked ciphertext is useless before its time. Run it end to end with npm run secret-demo.

timed-secret.ts
// npm i @keccak002/notyet
import { sealSecret, openSecret } from "@keccak002/notyet"

// seal an API key to Monday 09:00 — give the ciphertext to the agent now
const sealed = await sealSecret(process.env.OPENAI_KEY, Date.parse("2026-09-15T09:00:00Z"), "openai")

// before 09:00 → throws NOT_YET · after 09:00 → returns the key
const key = await openSecret(sealed)

Bazantic recipe ↗  ·  mcp-server.ts ↗  ·  SDK in 10 lines ↗  ·  timed secret release ↗