Sessions and forks
Every tevm command runs an EVM inside its own short-lived process. Without help, the
second command would know nothing about the first. Sessions are the mechanism that
carries state between them.
The model
A session is a JSON file on disk holding four things:
- the fork RPC URL, if any,
- the pinned fork block, if any,
- the block height,
- a dump of every touched account and storage slot.
tevm <command> --session <name> loads that file before running, and writes it back
afterwards. The effect is a chain that persists across processes without a daemon.
Files live in ~/.tevm/sessions/<name>.json, written with mode 0600 via a temp file
plus an atomic rename. Set TEVM_SESSION_DIR to move them elsewhere.
A local chain
# Create the session.
tevm session counter --local --json
# Fund an account.
tevm set-account \
--address 0x1000000000000000000000000000000000000001 \
--balance 1000000000000000000 \
--session counter --run --json
# Put code at that address.
tevm set-code \
--address 0x1000000000000000000000000000000000000001 \
--bytecode 0x6080604052348015600e575f80fd5b50 \
--session counter --run --json
# Advance the chain.
tevm mine --blocks 3 --session counter --run --json
# Read it all back in a fourth process.
tevm get-account \
--address 0x1000000000000000000000000000000000000001 \
--session counter --run --jsonEach command is a separate process. The balance, the code, and the block height all
survive because they round-trip through ~/.tevm/sessions/counter.json.
A forked chain
tevm session optimism \
--fork https://mainnet.optimism.io \
--fork-block 128000000 \
--jsonReads that miss the local state fall through to the fork URL; writes stay local. Because the fork block is pinned, the same command produces the same answer next month:
tevm get-balance \
--address 0x4200000000000000000000000000000000000006 \
--session optimism --run --jsonOmit --fork-block and each command forks from whatever the chain's head happens to be
at that moment — convenient for exploration, useless for a regression test.
What is not persisted
Transaction receipts and logs are not saved. When a session is reloaded, the recorded
block height is restored by mining that many empty blocks — so tevm get-block-number
stays consistent, but tevm get-transaction will not find a transaction from an earlier
process. If you need history, keep the chain alive with tevm serve
instead.
Sessions in CI
Give every job its own session directory so parallel jobs cannot collide, and delete it at the end:
- name: EVM checks
env:
TEVM_SESSION_DIR: ${{ runner.temp }}/tevm-sessions
TEVM_JSON: 'true'
run: |
npx --yes @tevm/cli@1.0.0-rc.151 session ci --fork "$RPC_URL" --fork-block 128000000
npx --yes @tevm/cli@1.0.0-rc.151 get-block-number --session ci --runTEVM_JSON=true is the environment equivalent of --json, and TEVM_SESSION is the
equivalent of --session, so a job can set them once instead of repeating flags.
Resetting
Deleting the file resets the chain:
rm ~/.tevm/sessions/counter.jsonTo snapshot and restore instead, pair tevm dump-state with
tevm load-state.

