Docs

Run the Evane daemon on your machine, fund a burner sub-account, and point your agents at it like any OpenAI-compatible endpoint.

Overview

Evane sits between your AI agents and the model providers they call. It has three parts.

  • evane-clientd, a daemon on your machine. Agents call it like the OpenAI API. It applies each agent’s policy and daily cap, removes personal data, and signs every request with the key of a burner sub-account.
  • The gateway. It checks the signature and the sub-account’s escrow on-chain, strips metadata that identifies you, and calls the provider with its own credentials. In production it runs inside a hardware enclave (AWS Nitro Enclaves or Intel TDX).
  • EscrowVault, a contract that holds each sub-account’s budget. The gateway settles what you used in batches, and never more than your daemon signed for.

Preview status

The preview runs on the Ethereum Sepolia testnet (chain ID 11155111). Testnet ETH has no monetary value.

  • Gateway: https://gateway.evane.dev. It runs with a development attestation: it is not yet inside an enclave, so its operator could read request contents. Send test data only.
  • EscrowVault: 0x7B9D941929512A5ab6FAEf13bD49D93AAa4B6757 (opens in a new tab)
  • Model prices on the preview gateway are placeholders, not provider list prices.

Live checks are on the status page.

Install

Download evane-clientd 0.1.0 for your platform. Each archive holds the program, a README and an example configuration. The Linux builds are static, so they run on any distribution.

evane-clientd downloads
PlatformDownloadSize
Windows (x64)evane-clientd-0.1.0-windows-x64.zip5.3 MB
Linux (x64)evane-clientd-0.1.0-linux-x64.tar.gz5.4 MB
Linux (arm64)evane-clientd-0.1.0-linux-arm64.tar.gz5.0 MB

There is no macOS build yet. The Windows build is not code-signed yet, so Windows may warn before running it: check its checksum first.

Check the download

The SHA-256 of each archive, also published as SHA256SUMS:

SHA256SUMS
f07e4ec7108006b1d6e416336f3511fa3fce9f208f164174dd5806f873724af9  evane-clientd-0.1.0-windows-x64.zip
a38f35fe3f2dc4afd6b856c840c549e3c939bdc175a37d336cc3ae84f0c74b85  evane-clientd-0.1.0-linux-x64.tar.gz
bf10b126c013410e6ca010c788901aa928572686c7328eccf4baf3e5ad73f36e  evane-clientd-0.1.0-linux-arm64.tar.gz
Linux
sha256sum --ignore-missing -c SHA256SUMS
Windows PowerShell
(Get-FileHash .\evane-clientd-0.1.0-windows-x64.zip -Algorithm SHA256).Hash

Put it on your path

Linux
tar -xzf evane-clientd-0.1.0-linux-x64.tar.gz
sudo install -m 755 evane-clientd-0.1.0-linux-x64/evane-clientd /usr/local/bin/
evane-clientd --version

On ARM, use the linux-arm64 archive the same way.

Windows PowerShell
Expand-Archive .\evane-clientd-0.1.0-windows-x64.zip -DestinationPath $HOME\evane
cd $HOME\evane\evane-clientd-0.1.0-windows-x64
Unblock-File .\evane-clientd.exe
.\evane-clientd.exe --version

Quickstart

  1. Install evane-clientd.
  2. Choose Connect Wallet at the top of this page, connect a browser wallet on Sepolia, set a budget and choose Fund account. When the account is funded, download session.key and clientd.toml. Faucets (opens in a new tab) give testnet ETH for free.
  3. Move both files into the .evane folder in your home directory.
    Linux
    mkdir -p ~/.evane
    mv ~/Downloads/session.key ~/Downloads/clientd.toml ~/.evane/
    chmod 600 ~/.evane/session.key
    Windows PowerShell
    New-Item -ItemType Directory -Force $HOME\.evane | Out-Null
    Move-Item $HOME\Downloads\session.key, $HOME\Downloads\clientd.toml $HOME\.evane\
  4. Start the daemon.
    evane-clientd
  5. Point any OpenAI SDK at it. The API key is ignored unless it matches an agent’s token.
    Python
    from openai import OpenAI
    
    client = OpenAI(base_url="http://127.0.0.1:9090/v1", api_key="unused")
    reply = client.chat.completions.create(
        model="claude-sonnet-5-5",
        messages=[{"role": "user", "content": "Hello"}],
    )
    print(reply.choices[0].message.content)
    TypeScript
    import OpenAI from "openai";
    
    const client = new OpenAI({ baseURL: "http://127.0.0.1:9090/v1", apiKey: "unused" });
    const reply = await client.chat.completions.create({
      model: "claude-sonnet-5-5",
      messages: [{ role: "user", content: "Hello" }],
    });
    console.log(reply.choices[0].message.content);
  6. Check what the agent has spent today.
    curl http://127.0.0.1:9090/v1/agent/status
  7. When you are done, open Connect Wallet again. Revoke the account, reclaim what is left once its settlement window closes, and withdraw it to your wallet.

Keep the key out of the browser

The panel can fund a key that evane-clientd made instead. Run keys new, choose From evane-clientd in the panel, and paste the session key it prints. The secret never leaves the daemon’s key file.

evane-clientd keys new --master <your wallet address>

Or skip the site: write ~/.evane/clientd.toml yourself and fund the sub-account from any wallet that can call depositAndSpawn. Foundry’s cast is shown.

# ~/.evane/clientd.toml
listen = "127.0.0.1:9090"
gateway_url = "https://gateway.evane.dev"
chain_id = 11155111
vault = "0x7B9D941929512A5ab6FAEf13bD49D93AAa4B6757"
master = "<your wallet address>"

[agents.default]
daily_cap_usd = "10.00"   # resets at 00:00 UTC
cast send 0x7B9D941929512A5ab6FAEf13bD49D93AAa4B6757 "depositAndSpawn(bytes32,uint256)" \
  <session key> 86400 --value 0.01ether \
  --rpc-url https://ethereum-sepolia-rpc.publicnode.com --account <your keystore>

How a request flows

  1. Your agent calls the daemon on 127.0.0.1. Requests that carry an Origin header, as browsers send, and requests for unexpected host names are refused, so web pages cannot reach it.
  2. The daemon identifies the agent, runs its policy, and removes personal data from the message text.
  3. It holds the request’s maximum cost against the agent’s daily cap, then signs the request and a receipt, the running total it agrees it owes, with the sub-account’s Ed25519 key.
  4. The gateway checks the timestamp, the nonce, the sub-account on-chain, both signatures, the receipt and the escrow balance. A request that fails any check never reaches a provider.
  5. It removes user, metadata, safety_identifier, prompt_cache_key and any user location, builds a fresh request with its own provider key, and relays it. Nothing from your connection is forwarded.
  6. It charges the price of the usage the provider reports, never more than the reservation. The daemon checks each charge against the published price table before acknowledging it in its next receipt.
  7. Every 100 requests or 5 minutes, the gateway settles each sub-account on-chain for the lower of its latest receipt and what it charged.

Configuration

The daemon reads ~/.evane/clientd.toml, or the file named by --config. Relative paths resolve against the file’s directory.

evane-clientd settings
SettingDefaultMeaning
listen127.0.0.1:9090Where agents connect. Other machines need allow_remote.
gateway_urlRequiredThe gateway. HTTPS is required except for localhost.
chain_idRequired11155111 for Sepolia.
vaultRequiredThe EscrowVault address.
masterRequiredThe wallet that owns the sub-account.
key_filesession.keyThe session key, created by keys new.
state_filestate.jsonReceipts and today’s spending.
proxyNoneA proxy for the gateway connection, such as socks5h://127.0.0.1:9050 for Tor.
allow_remotefalseAccept connections from other machines.
allowed_hosts[]Extra host names to accept.
require_teefalseRefuse to start unless the gateway proves it runs one of the enclave images in tee_pcr0.
tee_pcr0[]Accepted AWS Nitro enclave images (PCR0, 96 hex characters each). Required with require_tee.
idle_receipt_seconds30Send the latest receipt on its own after this idle time.
redaction.enabledtrueRemove personal data from message text.
redaction.customNoneExtra patterns, each with a name and a regular expression.

Agents, caps and policies

Each request belongs to an agent: the one whose token matches the bearer API key, or the one named in X-Evane-Agent if it has no token, or else default. An agent with a token can only be used with that token, so one local process cannot spend another’s allowance.

[agents.research]
token_env = "EVANE_RESEARCH_TOKEN"   # the agent sends it as its API key
daily_cap_usd = "5.00"
hard_cap = true
policy = "policies/research.wasm"

Daily caps

Caps are in US dollars and reset at 00:00 UTC. A hard cap refuses a request whose maximum cost could cross it, counting requests still in flight. A soft cap, hard_cap = false, refuses requests only once the cap is reached. The maximum cost of a request is the price of ceil(body bytes / 3) input tokens plus its output limit: the larger of max_tokens and max_completion_tokens, or 4096 if neither is set, times n.

Policies

A policy is a WebAssembly module that exports memory, alloc(len) -> ptr and check(ptr, len) -> i32, and imports nothing, so it has no access to files or the network. The daemon writes {"agent": ..., "request": ...} as JSON, before redaction, and calls check: 0 allows the request and anything else denies it. Each check runs in a fresh instance with 50 million units of fuel and 32 MiB of memory. A trap or an exhausted budget denies.

policy.wat
(module
  (memory (export "memory") 1)
  (func (export "alloc") (param i32) (result i32) i32.const 0)
  ;; Deny any request larger than 64 KiB.
  (func (export "check") (param $ptr i32) (param $len i32) (result i32)
    local.get $len
    i32.const 65536
    i32.gt_u))

Redaction

Before a request is signed, the daemon replaces personal data in message text, in this order:

Redaction patterns
DataReplaced withMatched
Email addresses[email]Standard address syntax.
IP addresses[ip]IPv4 and IPv6, except loopback and unspecified addresses.
Payment cards[card]13 to 19 digits that pass the Luhn check.
Phone numbers[phone]7 to 15 digits with a +, parentheses or separators. Dates, decimals and version numbers are left alone.
Custom patterns[name]Regular expressions from the configuration.
Before: Summarize the invoice from priya@example.com and call +1 555 0142 if it's over $5k.
After:  Summarize the invoice from [email] and call [phone] if it's over $5k.

Fields such as user and metadata are removed by the gateway, so they never reach the provider either.

API reference

Daemon, on http://127.0.0.1:9090

Daemon endpoints
EndpointPurpose
POST /v1/chat/completionsOpenAI chat completions, including streaming. Responses carry X-Evane-Charge-Wei and X-Evane-Cumulative-Wei.
GET /v1/modelsThe models the gateway serves.
GET /v1/agent/statusThe calling agent’s spending today, its cap, the sub-account and the gateway’s attestation.
GET /healthzLiveness.

Gateway

Gateway endpoints
EndpointPurpose
POST /v1/chat/completionsA signed completion request.
POST /v1/receiptsA signed receipt with the body {}: acknowledges a total without calling a model.
GET /v1/pricingPrices in micro-USD per million tokens and the USD per ETH rate used for wei.
GET /v1/attestation?nonce=…In an AWS Nitro enclave, a document signed by the Nitro hypervisor that binds the nonce, the enclave image (PCR0), the deployment and the enclave’s TLS key. The daemon verifies it, then talks only to that key. 501 when the gateway has no attestation.
POST /v1/settlement/cosignValidators co-sign each other’s settlement batches.
GET /healthzLiveness.

Signed request headers

Signed request headers
HeaderValue
X-Evane-Sub-AccountThe sub-account address.
X-Evane-TimestampUnix seconds. Rejected if more than 60 seconds off.
X-Evane-Nonce16 random bytes as hex. Rejected if reused within 120 seconds.
X-Evane-ReceiptThe cumulative wei the client agrees it owes.
X-Evane-Receipt-SignatureEd25519 signature over the receipt.
X-Evane-SignatureEd25519 signature over the chain, vault, sub-account, method, path, timestamp, nonce, receipt and body hash.

Errors

Errors use the OpenAI error shape, so SDKs surface them as usual.

{"error": {"message": "the sub-account's escrow cannot cover this request", "type": "evane_error", "code": "budget_exhausted"}}
Error codes
CodeStatusMeaning
invalid_signature401Missing, malformed or wrong signature headers.
stale_request401The timestamp is more than 60 seconds off.
replayed_request401The nonce was already used.
sub_account_inactive403The sub-account does not exist, has expired or was revoked.
receipt_behind402The receipt does not cover past charges. The daemon catches up and retries automatically.
budget_exhausted402The escrow cannot cover the request’s maximum cost.
daily_cap_reached429The agent’s daily cap would be crossed.
policy_denied403The agent’s policy denied the request, or failed.
forbidden403A browser request, an unknown agent, or a missing agent token.
model_not_found400The gateway does not serve that model.
invalid_request400The body is not a valid chat completion request.
payload_too_large413The body is over 16 MiB.
upstream_rate_limited429The provider is rate limiting the gateway. Retry shortly.
upstream_error502The provider failed or could not be reached. Nothing was charged.
gateway_unavailable502The daemon cannot reach the gateway, or the gateway cannot read the chain.
charge_mismatch502The gateway claimed more than the daemon can verify, so the daemon refused to acknowledge it.
attestation_unavailable501The gateway has no enclave attestation.

Escrow and settlement

EscrowVault holds budgets in ETH. Your wallet is the master owner of every sub-account it opens; the sub-account address is derived from your wallet and the session key, so nobody else can claim it. The Connect Wallet panel calls sub-accounts just accounts.

EscrowVault functions
FunctionWhat it does
depositAdds ETH to your master balance.
withdrawReturns unused master balance to your wallet.
depositAndSpawnDeposits and opens a sub-account with the whole deposit as its budget, in one transaction.
spawnSubAccountOpens a sub-account from your master balance. Validity is 60 seconds to 30 days.
topUpMoves more of your master balance into a live sub-account.
revokeSubAccountEnds a sub-account now. The gateway keeps a grace period to settle what was already used.
reclaimAfter expiry and the grace period, returns the remaining budget to your master balance. Anyone can call it.

Validators sign settlement batches with EIP-712, and the vault accepts a batch only with enough validator signatures. Each item moves at most what the escrow holds, and settling the same total twice changes nothing. The gateway settles the lower of your latest receipt and what it charged: never more than your daemon signed for.