back to blog
Product launch12 min read

Introducing Replay:
Solana mainnet, paused on a frame you can drive.

Reproduce the bug at the slot it happened. Stage a program upgrade against today's mainnet accounts. Decide a protocol change with evidence, not a hunch. Replay puts you inside Solana mainnet at any moment you choose and lets you drive it — advance the chain slot by slot, splice your own transactions, patch any account, deploy any program, and read it all back over full JSON-RPC, WebSocket, and Geyser. The closest thing to a time machine for the Solana state machine, drivable from a terminal or from an AI agent over Model Context Protocol.

published
May 21, 2026
author
k256
category
Product launch
reading time
12 min
[01]the gap nothing else fills

The Solana developer toolchain has good tools for many problems — and one persistent hole: being mainnet at a specific moment, and driving it forward.

solana-test-validatorboots an empty chain. Devnet and testnet are different chains with different state. Forking RPC proxies handle the reads you've implemented but don't actually run a validator — you can't advance the chain, you can't replay a block, you can't splice your own transaction at slot 418,908,420 and watch what happens next. Account-snapshot tools take a few accounts at a moment, but the bank doesn't tick.

An actual mainnet. An actual moment. That you can drive.

That is the piece that was missing. Not a simulator, not a proxy, not a partial fork — your own Solana mainnet, isolated to you, with no public consensus to keep up with and nobody else on it, that you can advance, mutate, and read like the real thing. Because at the protocol layer, it is the real thing.

[02]what it's for

Three jobs, and the hours they used to cost.

Almost every conversation we have lands on one of three jobs. Each used to cost a day and a fragile setup. The shape of the fix is always the same — boot, drive, read — on a fork you can throw away and run again.

Incident response

A program misbehaves at a specific signature. The old workflow: spin up a local validator, hand-craft the surrounding state, fail to reproduce, ask the operator for a database dump, give up.

The Replay workflow: boot the snapshot from before the incident, splice the offending transaction at the next slot, watch the bank state and the log messages. Patch the upstream account that looked suspicious, re-splice, see if the failure flips. No prod risk, no flaky local repros, and the fork is throwaway — you can run the experiment ten times.

Program upgrades

POST /programs/deploy uploads a compiled .soand installs it at any program id. Raw ELFs up to 10 MiB. No on-chain authority dance, no cooldown — it's your fork — so you can stage a candidate against today's mainnet accounts and run your real workloads against it before you ship. The regression surfaces here, not in the post-mortem.

The same request models upgradeable programs (status=deployed), models the post-finalization immutable state (status=finalized), or converts a program from a legacy loader. One endpoint, one body, every error kind dispatchable.

Protocol research

Walk the chain forward through a window of canonical blocks while splicing your proposed transactions in. Read the assembled block back. Splice again with a different parameter, advance again, compare. Decide with evidence — before any of it touches production.

It's the same loop you'd run if you were running mainnet — except you control the slot clock and nobody else sees your work.

[03]what you see when you boot

Pick a frame. Be inside it in seconds.

You pick a frame from the catalog — a rolling window of recent mainnet states across the Solana versions we run. Cached frames skip the network fetch, then still extract and index locally; new ones fetch first. Pick the version, pick streaming on or off, hit Start.

When the dashboard says phase=ready, you are now Solana mainnet at exactly that slot, on an environment that is yours alone. JSON-RPC accepts queries; getAccountInfo on any address returns what the chain actually held at that moment.

k256Replay
connected

replay-us-east

Active

US East · Pro · agave v4.0.1

Validator ready at slot 418,908,412

uptime 48m 16s

Current slot
418,908,412+2

advanced 2 slots since boot

Snapshot slot
418,908,370

boot point of the local fork

Phase
ready

RPC accepting queries

Shred version
50093

JSON-RPC accepting queries

uncached boots fetch; cached boots start at local extraction

/status is the single source of truth. The dashboard polls it every second, and so does every reasonable client.

[04]six verbs

The whole surface, in six moves.

The product surface is small on purpose. Six things you do repeatedly, each documented end-to-end, each reachable from the dashboard, the HTTP API, and the MCP server.

Boot — pick the frame

POST /boot with the snapshot you picked from the catalog. Returns 202 immediately; uncached boots walk through downloading → extracting → indexing → ready; cached boots skip the network fetch and still decompress locally before indexing. Integrity is checked on the way in — anything off, the environment stays dead and tells you what failed.

A fresh boot resets the local fork — every advance and mutation since the last boot is dropped. That's the only knob that clears mutation.dirty, and it's deliberate: rebooting is cheap, so the operational story is "boot a clean canonical mainnet, do your work, throw it away."

k256Replay
Replay/replay-us-east/Console

replay-us-eastActive

US East · Pro · agave v4.0.1

API explorerconnected Stop validator

Boot

Pick a snapshot and start the local replay validator.

Validator ready at slot 418,908,412

uptime 48m 16s

Current slot
418,908,412+2

advanced 2 slots since boot

Snapshot slot
418,908,370

boot point of the local fork

Phase
ready

RPC accepting queries

Shred version
50093

JSON-RPC accepting queries

Boot From Snapshot

Select a snapshot slot to boot the replay validator

Refresh
Search by slot number…
Bootable slots · 5
  • 418,908,370

    27s ago · 84.2 GB

    Cached
  • 418,876,800

    9m ago · 84.1 GB

    Cached
  • 418,832,500

    32m ago · 83.9 GB

    Cached
  • 418,791,200

    1h ago · 83.7 GB

    Stream
  • 418,733,400

    2h ago · 83.5 GB

    Stream
Advanced: Custom Slot

Geyser plugin

Optional. Loads a Solana Geyser plugin alongside the validator for this boot. Pick a bundled preset, upload your own .so + config.json, or leave off for a vanilla validator.

Noneactive

vanilla validator, JSON-RPC + WebSocket only

Yellowstone gRPC

bundled preset · gRPC endpoint after boot

Custom upload

your .so + config.json · endpoint shown after boot

Validator is currently running

Booting will stop the current validator and rebuild replay state from the selected snapshot.

Reboot validator

Accounts — read and mutate the bank

The Accounts tab is your production address book. Quick-add chips for the programs you always reach for; a paste input for the ones you don't. The detail panel reads the bank: owner, balance, data size, rent epoch, raw bytes.

POST /accounts/patchwrites one or more accounts straight into the local fork. Merge (keep the fields you don't set) or replace (overwrite the whole account). The moment a patch lands, mutation.dirty=trueand the UI flips a label to remind you you're on a labeled local fork. Reboot to return to canonical mainnet.

bash
curl -s -X POST \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "content-type: application/json" \
  -d '{
    "patches": [
      { "pubkey": "<YOUR_PUBKEY>", "mode": "merge", "lamports": "1000000000" }
    ],
    "confirm_dangerous": true
  }' \
  https://api.k256.xyz/v1/replay/servers/<SERVER_ID>/accounts/patch

Topping up a wallet's lamports is the trivial case. Patching a token mint to model an upgrade, overwriting a stale price oracle, or replacing an entire program account before staging a deploy — that's where this earns its keep.

k256Replay
Replay/replay-us-east/Console

replay-us-eastActive

US East · Pro · agave v4.0.1

API explorerconnected Stop validator

Accounts

Inspect, mutate, and deploy programs to accounts on the local fork.

Validator ready at slot 418,908,412

uptime 48m 16s

Current slot
418,908,412+2

advanced 2 slots since boot

Snapshot slot
418,908,370

boot point of the local fork

Phase
ready

RPC accepting queries

Shred version
50093

JSON-RPC accepting queries

Deploy programNewDev-only

Tokenkeg…623VQ5DA

Program

TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA

RefreshExplorer

Owner

BPF Loader (v2)recognized program

BPFLoader2111111111111111111111111111111111

Balance
5.6782 SOL

5,678,237,313 lamports

Data size
130.94 KB

134,080 bytes

Rent epoch
Rent-exempt

u64::MAX sentinel — never charged

Account Data

134,080 bytes

HEXASCIIRAW ADD IDL
00000000  7f 45 4c 46 02 01 01 00  00 00 00 00 00 00 00 00   .ELF........
00000010  03 00 f7 00 01 00 00 00  d8 f9 00 00 00 00 00 00   ............
00000020  40 00 00 00 00 00 00 00  80 09 02 00 00 00 00 00   @...........
00000030  00 00 00 00 40 00 38 00  04 00 40 00 09 00 08 00   ....@.8...@..
00000040  01 00 00 00 05 00 00 00  20 01 00 00 00 00 00 00   ............
00000050  20 01 00 00 00 00 00 00  20 01 00 00 00 00 00 00   ............
00000060  60 b9 01 00 00 00 00 00  60 b9 01 00 00 00 00 00   '.......'.....
00000070  00 10 00 00 00 00 00 00  01 00 00 00 06 00 00 00   ............

…133,568 more bytes (download for full data)

Actions

Mutations are applied directly to the local fork — they bypass normal Solana authority. Re-boot the snapshot to revert.

Set lamports Transfer Modify data Close account

Advance — splice transactions in

POST /advance walks the fork forward to a target slot, optionally splicing your transactions into specific slots along the way. Replay replays canonical mainnet blocks and weaves your transactions in where you ask — eight anchors, one queue: block_start, block_end, before_index, after_index, before_signature, after_signature, replace_index, at_index_clamped.

It walks forward block by block — canonical, then yours, then canonical again — in exactly the order the bank applies them. getBlock over JSON-RPC returns the assembled block, with your splice at the index you put it. You can cancel any advance mid-flight; blocks already rooted stay applied. There is no rollback.

k256Replay
Replay/replay-us-east/Console

replay-us-eastActive

US East · Pro · agave v4.0.1

API explorerconnected Stop validator

Advance

Replay mainnet blocks into the local validator, or send a custom transaction.

Validator ready at slot 418,908,412

uptime 48m 16s

Current slot
418,908,412+2

advanced 2 slots since boot

Snapshot slot
418,908,370

boot point of the local fork

Phase
ready

RPC accepting queries

Shred version
50093

JSON-RPC accepting queries

Advance Validator

Move the replay validator forward, with optional custom splices.

Send txAdvance

Current Slot

418,908,412

Shred Version

50093

Target Slot

418,908,500+88 slots
+1+2+5+10+50+100
Advanced Settings

Inject operator-supplied VersionedTransactions into upstream blocks at chosen anchor points. Each splice targets a single slot in (current, target].

Append at end of blockslot 418,908,420

block_end

signed by WALLET · JUP6Lk…NyVTaV4

ours
Inject after Raydium swapslot 418,908,447

after_signature · 5fH8wK…XzQ7P

replace LP token amount · 3pNa6w…rTzYk

ours
Replace tx at slot index 14slot 418,908,478

replace_index · ix #14

modified signer + amount · 8mRkLp…wQz3D

modified
Add splice
Advance Validator

Blocks — your replay chain

The Blocks tab is the canonical block explorer for the chain you just built. Walk forward from your boot point. Click any row for decoded instructions, log messages, pre/post balances. Filter by signature or any pubkey in the tx.

The list reflects your replay chain, not upstream mainnet, so the transaction you spliced in at slot 418,908,420 sits exactly where you put it. 1,446 canonical txs in a block, your splice at index 10, the fee at 1,005,000 lamports — visible, decoded, indexable.

k256Replay
Replay/replay-us-east/Console

replay-us-eastActive

US East · Pro · agave v4.0.1

API explorerconnected Stop validator

Blocks

Browse confirmed blocks and inspect transactions on the local validator.

Validator ready at slot 418,908,412

uptime 48m 16s

Current slot
418,908,412+2

advanced 2 slots since boot

Snapshot slot
418,908,370

boot point of the local fork

Phase
ready

RPC accepting queries

Shred version
50093

JSON-RPC accepting queries

Slot

418908420
Load slot

Find by transaction signature

base58 signature…
Find tx
jump to current slot (418,908,412) refresh·workbench2,553 fixtures · 5 slots·140 MB / 5 GB·clear

Slot

418,908,420

Parent slot

418,908,419

Block height

397,000,050

Transactions

1,255 + 191 err / 1,446

Blockhash

# FykHTQkha8t7eHDAdLYxCKpEqPAwCuHr18wuek16GFX8

block time: 5/17/2026, 6:14:02 PM

filter by sig or pubkey…
page 1 / 29
  • 0PMXyVcmpdT34Z9YfbvTUJ5JW5YAKvyCGNNjqZrDEnTKUF6DR4vxefWDQzLVdAJBHNW2VS4v1bEzMX4ftDDxzYYgL
  • 15cBbxrnkszXXoZy8pvCkmxhNHJ9CzJuYzibJLQcscFwn6r2aCUQ7ztnoZHTNhiiu72EZ4dqso4koa6CioT2JbHnS
  • 2RGTr4gD1dPRX2MzRZMTytFZuy8XVXm8Gcc4DgdpLWe9rwAV9D6kdksbKzUv38gsad9rvP7c1KVXimGMeHXRpE5y
  • 34Lc5tED7tKtn7wkqPRP4i4RaG9ArzRCafq1skc2r96GC42ZEpRajqmM3HUbD5R5K5rgazLMBqUAiUZc4MZSqxds8S
  • 45TceA34JWotUCEeSAx9ewELmo5pAqTinCWwCjLAqYNR9s4YpKwdGHQ2DWTNTV3fzXBmfnz1gAdD347fui6JRFf3g
  • 53XapaApeV8qTa1CYVfKj6DMseGXubjnPm4AzUwY17XYxSWdYjVxd57Tmuj6EK3UH9ShNngiaWeGv36VLjwc2g5Du
  • 62HWPNAH1ijDweyB8aNs1LEwdqA2QqGoFbWMW3ZhxsFdQ6lZfL4a1xE7uLzHQYgLWSUM6xBhRuxSExbPCuMmp61aFW
  • 77PYeKVVBBTvWyWEsHLi1hBe9wNRm85Z91dKkYZaPsQamTad1f1At3FzGLgA9A9mkGgT2zXNKZ145HiAmerxUvYC
  • 82Yqf3xZBbCgX9p4z5UNyMR1vGQK2tPwL8aH7eXjK3mNzBdT6cRY1uV4sP9tQrLnA8mEhKjF2WxBpDcZ4NHsTqVRy
  • 96KqRpA8WHbMyL2zXg3vN1eFt5cBdQ7uPrJ9oS4iH8eWxKj2nM3sV1aB7tY5cZqL4wRhUfPxN6yE9oDmCb3JsKtVe
  • 104ApAhJaV1AiHziFgPHXxgzN7AP8omaWBFfL9E6hUPz8h2im6Wz1MFpzrvJAT9SUzkaMyscS1N5EcJmq75UboiDDXours

RPC — point your existing tools at it

There is nothing to rewrite. Your environment speaks the standard Solana JSON-RPC surface, WebSocket PubSub, and — if you booted with streaming on — gRPC. @solana/web3.js, anchor, solana-cli, your indexer, your bots, your dashboards — reveal the direct endpoint when you need it, copy it, and treat that URL like an operational secret.

Block height does not advance unless you call /advance, so anything that loops on onSlotChangeblocks until you ask it to. That's the contract — and the LLM operator quickstart spells it out so agents don't write busy-waits.

bash
# Standard Solana JSON-RPC uses the endpoint revealed and copied from the app.
REPLAY_RPC_ENDPOINT="<copied replay RPC endpoint>"

curl -s -X POST \
  -H "content-type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"getSlot"}' \
  "$REPLAY_RPC_ENDPOINT"
k256Replay
Replay/replay-us-east/Console

replay-us-eastActive

US East · Pro · agave v4.0.1

API explorerconnected Stop validator

RPC

Copy endpoint snippets and run common validator RPC checks.

Validator ready at slot 418,908,412

uptime 48m 16s

Current slot
418,908,412+2

advanced 2 slots since boot

Snapshot slot
418,908,370

boot point of the local fork

Phase
ready

RPC accepting queries

Shred version
50093

JSON-RPC accepting queries

Validator endpoints

Show endpoints
HTTP<copied replay RPC endpoint>
WS<copied replay PubSub endpoint>
gRPC<copied replay Geyser endpoint>

Yellowstone does not expose gRPC reflection on this endpoint. Use a Yellowstone client/protobuf example instead of grpcurl list. Streams are quiet while the fork is idle; run an advance to produce slot, transaction, block, or account updates.

Standard Solana JSON-RPC. Point any client (web3.js, Anchor, solana-cli) at this URL — read methods return state from the local replay fork (snapshot + your /advances + patches + materializations).

Direct endpoint URLs stay hidden by default for screenshots and are outside the workspace bearer once copied.

Six things to know before pointing a client at these endpoints

Account

shared across the account-bearing calls

EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
USDC mintwSOL mintSystem ProgramToken Program

getSlot

Return the validator's current slot.

curl Run
curl -s "$REPLAY_RPC_ENDPOINT" \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment":"processed"}]}' | jq

getAccountInfo

Look up the account above at the replay slot. Returns null if it doesn't exist.

curl Run
curl -s "$REPLAY_RPC_ENDPOINT" \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",{"encoding":"jsonParsed"}]}' | jq

getBalance

Return the lamport balance of the account above.

curl Run
curl -s "$REPLAY_RPC_ENDPOINT" \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"getBalance","params":["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",{"commitment":"processed"}]}' | jq

History — every advance, recorded

Start slot, target slot, duration, status. Twenty most recent jobs, in memory. Expand a row for the exit code, the finality choice, and the full job ID. The signal you want when you're iterating on a splice plan and need to know which run produced which state.

The same audit log carries every patch, splice, and program deploy — GET /accounts/patch/history returns up to 2,000 records (newest first), spanning every mutation kind, with the before/after state hashes for each. Pipe it to jq if you want the diff.

k256Replay
Replay/replay-us-east/Console

replay-us-eastActive

US East · Pro · agave v4.0.1

API explorerconnected Stop validator

History

Advance jobs, local mutations, and durable audit rows for this environment.

Validator ready at slot 418,908,412

uptime 48m 16s

Current slot
418,908,412+2

advanced 2 slots since boot

Snapshot slot
418,908,370

boot point of the local fork

Phase
ready

RPC accepting queries

Shred version
50093

JSON-RPC accepting queries

History

Advance jobs, local mutations, and durable audit rows for this environment

Refresh
Showing
8

8 loaded

Advance
2

slot jobs

Mutations
3

patches + splices

Audit
3

durable environment rows

Filters

Search loaded history

Account, program, signature, slot, status...

Event type

All events

Filters apply to the rows already loaded by the console. Use Copy JSON for the exact route payload behind an event.

Advance jobs2 / 2

Recent slot advances for this runtime session.

  1. Slots

    418,908,412 → 418,908,500

    Duration

    4.1s

    Status

    Done

    req a34f9c
  2. Slots

    418,908,370 → 418,908,412

    Duration

    1.9s

    Status

    Done

    req 7b10e2

Local mutations3 / 3

Account patches, transaction splices, and program deploys recorded by the fork.

Transaction splice

slot 418,908,420

2w38yYfzXVLduAqEFLJBQPtKS2joCJykC9XrbGyU...

Time

just now

Duration

182ms

Request ID

req c8e441

append_at_endindex 10signature indexed

Account patch

slot 418,908,412

5Zzguz4NsSRFxGkHfM4FmsFpGZiCDtY72zH2jzMcqkJx

Time

2m ago

Duration

41ms

Request ID

req 0fd2b7

lamportsdata bytesowner unchanged

Durable audit trail3 / 3

Gateway audit rows scoped to this environment. Restore rewinds fork state; these rows remain.

Checkpoint saved

accepted

before-experiment

Actor

workspace

Time

2m ago

Request ID

req 4f2db1

checkpoint_saverestore_slot 418,908,412

Checkpoint restored

accepted

clean-boot

Actor

workspace

Time

14m ago

Request ID

req a90df8

checkpoint_restoreenvironment row
[05]two transports, one bearer

Drive Replay from your terminal. Or from your agent.

Same surface, same bearer, two ways to talk to it. HTTP at api.k256.xyz for cURL, runtime SDKs, and anything that already speaks REST. MCP at api.k256.xyz/mcp for AI agents that speak Model Context Protocol — Cursor, Claude (Code and Desktop), Codex CLI, VS Code Copilot.

Tool names mirror the HTTP verbs as replay_<verb> replay_status, replay_boot, replay_advance, replay_patch_accounts. An agent that learns one learns the other. Same wire contract, same error kinds.

Cursor

~/.cursor/mcp.json

Claude

claude mcp add ...

Codex CLI

codex mcp add ...

VS Code

.vscode/mcp.json
[06]three-minute quickstart

If you have a key in hand, this is the loop.

Boot, wait until ready, read the current slot, advance one slot, splice a transaction, read the assembled block back. Every Replay verb is documented in full at /replay/llm-docs.md.

bash
export KEY="<YOUR_API_KEY>"
export GW="https://api.k256.xyz/v1/replay/servers/<SERVER_ID>"

# 1. Wait until the environment is ready
until curl -fsS -H "Authorization: Bearer $KEY" \
  $GW/status | jq -e '.phase == "ready"' >/dev/null; do
  sleep 2
done

# 2. Read the current slot
SLOT=$(curl -s -H "Authorization: Bearer $KEY" $GW/status | jq -r .current_slot)

# 3. Advance one slot
curl -s -X POST \
  -H "Authorization: Bearer $KEY" \
  -H "content-type: application/json" \
  -d "{\"target_slot\": $((SLOT + 1)), \"root\": true}" \
  $GW/advance | jq

# 4. Splice a transaction at the end of a future block
curl -s -X POST \
  -H "Authorization: Bearer $KEY" \
  -H "content-type: application/json" \
  -d '{
    "target_slot": '$((SLOT + 2))',
    "splices": [
      { "slot": '$((SLOT + 1))', "position": "block_end",
        "transactions_base64": ["AQAB..."] }
    ]
  }' \
  $GW/advance | jq

The snippets above hit the gateway with curl. Once your fork is advancing, you'll usually want to read its state from a real Solana client. The Replay examples repo shows the wire shape of every standard transport:

github

k256-xyz/replay-examples

Three tiny Rust programs — one-shot JSON-RPC, PubSub subscription, Yellowstone gRPC stream. Read it, lift the parts you need, point your real client at the same URLs.

Open repo
[07]errors you can dispatch on

Stable. Finite. Documented.

Every non-200 response carries a JSON body with { "error": "<kind>", "message": "..." }, and the error kind is in the docs. Build dispatch tables, not regex parsers — and an agent that reads the docs will route around the error states without you catching them by hand.

  • 409
    boot_in_flight

    another boot is still running

  • 409
    advance_in_flight

    an advance is still running

  • 409
    phase_not_ready

    the environment is not in ready

  • 400
    target_in_past

    advance target is behind current slot

  • 413
    elf_too_large

    .so exceeds 10 MiB

  • 401
    unauthenticated

    missing or invalid bearer

[08]what ships next

A short, deliberately conservative list.

  • Snapshot retention windows on demand for customers who want reproducible state past the rolling window.
  • More streaming presets beyond Yellowstone, driven by what customers want to ingest.
  • Multi-region replicas of the same boot point for teams coordinating across geographies.

We'll write about each one as it ships. None of them are blockers for the workflows above — Replay is useful today, exactly as it stands.

product launch · live

Stop rebuilding mainnet by hand.

Sign up, pick a region, pick a Solana version, and you're inside a paused mainnet in minutes.

pricing

$1,599/ month

Dedicated environment. One region. One operator.

  • Solana version of your choice
  • Snapshots cached
  • Full RPC + WS + Geyser
  • Public IP, your DNS
  • Unlimited splices and patches
Want to talk first?