Skip to main content
geodesics is gasless, self-custodial cross-chain swaps as one command. The agent holds only the token it wants to swap; gas and fees come out of the input, funds never leave the agent’s own wallet, and settlement is typically 5-15 seconds, including cross-chain. It works in both directions across Base, Ethereum, Arbitrum, Optimism, Polygon, BNB, Robinhood Chain, and Solana. The package doubles as an agent skill: a packaged SKILL.md for agent runtimes such as Claude Code and Cursor, so an agent can drive these commands unattended. This page is the command reference. New here? The Quickstart walks a fresh agent to its first swap in about 5 minutes.

Install

Requires Node.js 20+ and a Geodesics API key, created self-service in the console.

Configure

geodesics init walks through everything below interactively: it first asks which wallet the agent swaps with (create or import its own keys, or plug in a Virtuals ACP agent wallet), validates each value, stores wallet keys in the OS keychain, saves the rest to a .env in the current project, or to ~/.geodesics/.env for all your projects if you choose, and finishes by installing the agent skill for your AI tools. The keychain is macOS Keychain, Windows Credential Manager, or Secret Service on Linux, and entries are encrypted at rest, so no key sits in a plaintext file. On a system without a keychain, such as a headless server, init asks before saving a key to the .env as plain text; pass --allow-plaintext-key to pre-approve that in scripted setups. The wallet profile is chosen by the credentials you set, no mode flag anywhere. The agent’s own wallet: a raw EVM key with no AGENT_WALLET_ID; the address is derived from the key, and the wallet onboards itself during its first swap from each chain, gasless. A Virtuals ACP agent wallet: setting AGENT_WALLET_ID selects it, and the signer key is then the base64 MIG… authorization key from the dashboard. A key that does not match its profile is rejected with a message that says exactly which variable to change. Load order: a working-directory .env wins, then ~/.geodesics/.env, and real shell env vars override both. Wallet keys specifically resolve as a shell env var first, then the keychain, then a .env value. Setup is a one-time user action; how agents behave around it is covered on the Agent skill page. On-chain reads, such as balances and sweep amounts, use public RPCs with automatic fallback across several providers. To pin a dedicated endpoint, set the chain’s env var: ETH_RPC_URL, BASE_RPC_URL, ARBITRUM_RPC_URL, OPTIMISM_RPC_URL, POLYGON_RPC_URL, BNB_RPC_URL, ROBINHOOD_RPC_URL, or SOLANA_RPC_URL; it is tried first, with the public endpoints kept as fallback.

Commands

All commands support --json for a single machine-readable object on stdout and --verbose to log HTTP calls to stderr; the Agent skill page covers --json output and what an agent should do on each error code.

Swap

  • --token-in / --token-out: a token alias like usdc, virtual, weth, eth, pol, matic, bnb, usdt, usdg, or sol, or a raw token address on that chain. Which alias resolves on which chain is in the alias reference; usdt resolves only on Solana.
  • --chain-in / --chain-out: a chain alias like base, ethereum, arbitrum or arb, optimism or op, polygon, bnb or bsc, robinhood or rh, or solana, or a numeric chain id.
  • Chain notes: on BNB, usdc is the Binance-Peg token with 18 decimals, handled automatically. Robinhood Chain has no USDC; its stable is usdg and its gas token alias is eth. Both directions are live: the first Robinhood-origin swap runs the usual one-time activation, carried by USDG.
  • --amount-in takes human units for aliased tokens. For a raw token address, pass --amount-raw in the token’s base units instead; decimals are not known for arbitrary tokens.
  • --max sweeps the entire input-token balance: an EVM token, or an SPL token on Solana origin. A native gas token like ETH or SOL cannot be swept, and --max cannot be combined with --amount-in or --amount-raw.
  • --recipient overrides the delivery address, which defaults to the agent’s own wallet on the destination chain.
  • --slippage-bps overrides max slippage. The per-route default is tight for stables and wider for volatile tokens.
  • --dry-run prices the swap and returns the quote without signing or submitting anything.
  • One command does the whole route, including cross-chain. Never chain two swaps yourself unless an error tells you to.
The command blocks until the swap settles, usually 5-15 seconds, and prints the result with originTxHash / deliveryTxHash. Pass --timeout-s to wait longer. First swaps are onboarded automatically, and the two wallet profiles behave differently:
  • The agent’s own wallet needs no preparation, ever. Its first swap FROM a chain carries a one-time signed authorization inside the swap itself, gasless, and delivery INTO any chain just works: whatever lands there can always swap back out, because the wallet onboards itself whenever it first swaps out of that chain.
  • A Virtuals wallet swapping FROM a new chain runs a one-time ~15 second activation first, paid from the wallet’s stable on that chain. Swapping INTO an EVM chain it has never used runs a one-time activation flow first: ~1 unit of the origin chain’s stable is piped over, the chain is activated, and the remainder returns to the origin. Adds about a minute and a few cents, once per chain, and guarantees the delivered assets can always swap back out. Keep ~1 USDC or USDG spare on the origin chain for this. If the swap itself delivers the chain’s stable (usdc/usdg), there is no pipe: the chain is activated right after settlement instead.
  • Swapping INTO Solana needs nothing from the Solana wallet: delivery works with zero SOL, and cross-chain swaps back out are gasless. Only a same-chain Solana swap later needs ~0.005 SOL; that swap fails fast with NEEDS_SOL_TOPUP, and --confirm-pipe on the retry funds it automatically.

Withdraw

Moves the chain’s canonical USD stable, USDC or its per-chain equivalent, from the agent wallet to another wallet, gasless, through the same signed-intent pipeline as a swap. The token is chosen automatically, so there is no --token flag, and at the start of the flow the CLI prints your stable balance on the origin chain. Same-chain it is a plain transfer; add --chain-out to deliver on another chain instead.
  • The withdrawn token is always the chain’s canonical stable: usdc on every chain, or usdg on Robinhood Chain where that is the canonical USD token. To move any other token, swap it to USDC first with geodesics swap.
  • --chain / --chain-out: a chain alias like base, ethereum, arbitrum or arb, optimism or op, polygon, bnb or bsc, robinhood or rh, or solana, or a numeric chain id.
  • --amount takes human units; --amount-raw gives the amount in the stable’s base units instead.
  • --max sweeps the entire stable balance on the origin chain, and cannot be combined with --amount or --amount-raw.
  • --to is the recipient address, always required. For a same-chain withdrawal it must differ from the agent wallet itself.
  • Cross-chain withdrawals deliver the destination chain’s canonical stable. A withdrawal from a USDC chain to Robinhood Chain delivers USDG, and slippage can apply as on any bridge.
  • --dry-run, --slippage-bps, --confirm-pipe, and --timeout-s behave exactly as they do for swap. Slippage only matters cross-chain; a same-chain transfer cannot slip.
The recipient is treated as an external wallet: it is never onboarded or activated, it just receives the funds.

Status

Balance

Reads one token’s balance on one chain over public RPCs; needs no API key and no signer. --chain takes a chain alias, --token a token alias valid on that chain or a raw token address/mint, --wallet overrides the agent wallet for that chain family. --json returns { chainId, chain, wallet, token, symbol?, raw, formatted? } where raw is a base-unit decimal string and formatted is human units; formatted is absent when a raw address’s decimals are unknown. If every RPC endpoint fails the command exits 1 with an error. Retry; it does not mean a zero balance.

Delegation check / manual activation

Rarely needed; swap does this automatically.
With the agent’s own wallet, activate is a no-op by design: there is nothing to activate manually, because the first swap from each chain onboards the wallet inside the swap itself. delegation reports the wallet’s per-chain state for either profile, including a wallet that is delegated to another provider; Geodesics never replaces an existing delegation, so such a wallet cannot originate swaps on that chain.

Slippage

The server picks a per-route default, about 3% for volatile outputs and 0.5% for stables, so most swaps need nothing. Override for one swap with --slippage-bps <bps>, or set a persistent default:
--slippage-bps beats config set slippage, which beats the server default. When a non-default slippage is in effect the swap prints a slippage: <bps> line. Setting 1000 bps or higher needs interactive confirmation, or --yes in a script. Raising slippage is the usual fix for a refunded swap: the price moved past tolerance, common on volatile or small cross-chain swaps.

Errors

Every error comes back with a code and a plain-language message. Exit codes: 0 is success; 1 is an error, with the reason in JSON error.code; 2 means the swap ended failed or refunded, with the input returned to the origin wallet. The full code table with the action to take on each lives on the Agent skill page.

Safety notes

  • Swaps move real funds. Use --dry-run to price a swap without executing it.
  • An interrupted command does NOT cancel a submitted swap. Re-running the command gets a fresh quote and can create a second swap, so check geodesics status first to find out what the interrupted run did.

Building a server-side integration instead?

The same engine ships as a typed library: see the TypeScript SDK, or the REST API for the raw wire.