Skip to main content

Your AI agent’s new best friend

curl -fsS https://cli.dflow.net | sh
Give your AI agent a Solana wallet and let it trade. Spot swaps, structured JSON output, keys that never leave your machine.
  • One binary, zero dependencies: install and go.
  • Agent-native: every command returns JSON; every error includes a machine-readable code and a recovery suggestion.
  • Your keys, your machine: private keys live in an encrypted local vault, never uploaded anywhere.

Getting started

The dflow CLI is a single self-contained binary that runs on macOS and Linux.
Then run setup:
setup prompts for: The Solana RPC is the only optional setting. All DFlow fields are required; setup will not proceed until each is entered. Config is saved to ~/.config/dflow/config.json. Re-run dflow setup anytime; existing wallets are left untouched. At the end of the install script, you’ll be prompted to install the DFlow Skills library, a set of Claude Code Skills that teach agents how to drive the CLI. This is optional, but highly recommended and can be installed later with dflow skills install. On macOS, the CLI stores your vault password in the system keychain so your agent can sign transactions without a password prompt blocking execution. The first time it does this, you’ll see a dialog asking permission to access dflow-ows, choose Always Allow, not just Allow. The dialog asks for your Mac login keychain password, which is separate from your DFlow vault password.
After installing an updated dflow binary, macOS treats it as a new app and will prompt for keychain access again. Run a small test transaction to prime the CLI before turning it over to your agent.

Command reference

Global flags (apply to subcommands that need config):

Setup, identity, balances

Skills

dflow skills update updates every skill the skills CLI manages, not only DFlow’s. The underlying CLI updates by skill name, not by repo.

Wallet

Trading

Transfers and funding

Guardrails

See Guardrails for the full list of available keys and examples.
Atomic units: Amounts are integers in the smallest token unit (e.g. 500000 = 0.50 USDC with 6 decimals; 10000000 lamports = 0.01 SOL).

Key management

Each wallet is an encrypted JSON file under ~/.ows/wallets/, following the Open Wallet Standard (OWS) format (powered by ows-lib v1.4.2). Private keys never exist on disk in plaintext. All cryptographic operations (decrypt, sign, zeroize) are handled by the ows-lib crate. The CLI binary itself never touches raw key material. When a command needs to sign, the CLI resolves the vault password by trying these sources in order:
  1. OS keychain (if saved via dflow setup or wallet keychain-sync)
  2. DFLOW_PASSPHRASE env var (read once, then cleared from the environment)
  3. Password prompt
The resolved password is cached for the duration of the process so back-to-back operations (e.g. guardrail check → sign → broadcast) only resolve it once. Guardrails changes (set / remove / reset) always require the password typed in the terminal. The keychain and env var are intentionally bypassed so a human must be present to change policy.
The vault uses a key derivation function (KDF) to turn the password into a decryption key. This is intentionally slow to make brute-force guessing expensive.

What is stored where

Permissions: ~/.ows directories 700, wallet files 600. If permissions are too open, commands fail with VAULT_INSECURE.
If someone has both your wallet files and your password, they can move funds. Use a strong password, lock down file permissions, and treat the machine like any workstation that signs crypto transactions.

Creating and importing keys

  • Create: dflow setup with a new wallet name generates a 24-word BIP-39 mnemonic and encrypts it into the vault.
  • Import keypair: dflow wallet import --name <n> --keypair <path> encrypts an existing Solana JSON keypair (from solana-keygen) into the vault.
  • Import mnemonic: dflow wallet import --name <n> --mnemonic "word1 word2 ..." restores a BIP-39 wallet (12 or 24 words). Use this to move a wallet created on another machine.
  • Export: dflow wallet export --name <n> --out <path> decrypts the recovery phrase (mnemonic) or keypair and writes it to <path> with 0600 permissions. The secret is never printed to the terminal (so it can’t leak into scrollback or recordings), --out is required, and a symlink at the destination is refused. Requires a typed vault password. Highly sensitive: use for backup or migration only. The confirmation includes wordCount and import instructions when the wallet is a BIP-39 mnemonic. When importing into Phantom or another wallet, make sure to select the matching word count (24).

Multiple wallets

The vault supports an unlimited number of named wallets. Each is a separate encrypted file with its own keypair and password. Pass --wallet <name> to target a specific wallet:

Headless environments

If there’s no terminal for a password prompt (e.g. a background process or Docker container), export the vault password as an environment variable:
The CLI unsets DFLOW_PASSPHRASE from its own process environment at startup, so any subprocesses it spawns will not see it. The value still persists in the parent shell and, on Linux, in the read-only /proc/<pid>/environ snapshot for the life of the process. The OS keychain is the most secure option.

Output format

Success (most commands):
Classified error (most failures):
details is present when there is additional structured context. Its shape varies by error category: API errors include httpStatus and the parsed response body; onchain errors include rawLogs or programErrorDecimal; others may include raw or inputMint. Simple error (edge cases such as cancelled prompts or misconfiguration):
Exception: dflow whoami prints only the pubkey string on success.

Token resolution

Symbols resolve to mints (built-in list includes SOL, USDC, USDT, CASH, BONK, JUP, WIF, PYTH, JTO, RAY, ORCA, MNDE, MSOL, JITOSOL, BSOL, RENDER). Any other asset: pass the mint address (base58).

Guardrails

Guardrails are optional client-side safety limits. An agent can read them freely (guardrails show requires no password), but only a human can change them. set, remove, and reset require the vault password typed in the terminal. USD estimates use the same route as the trade itself, including SOL-to-USDC conversion when needed.

Funding

Use fund to buy crypto with fiat through the MoonPay CLI. It supports USDC and SOL. The MoonPay CLI is not bundled with dflow. Install it separately only if you need the fund command:
The <amount> is in your local fiat currency, auto-detected by MoonPay based on your locale. For example, dflow fund 50 USDC in the US buys USD 50 of USDC; in Thailand it buys THB 50 of USDC.
When dflow fund runs, it fetches the wallet address, calls MoonPay to generate a checkout URL, opens it in the browser for KYC and payment, then polls the wallet balance until a deposit lands (10-second intervals, 10-minute timeout).
This command requires a browser and is intended for wallet funding by a human operator, not for autonomous agent use.

Spot trading

Swap any supported token pair. Amounts are always in atomic units of the input token (e.g. 500000 = 0.50 USDC).

Get a quote

The CLI calls the DFlow Trade API /order endpoint and returns the route, expected output amount, and price impact, without executing anything.

Execute a trade

The CLI uses standard /order execution: it fetches a route, signs the transaction locally, and submits it to the network. The response status is "submitted". Add --confirm to poll the RPC until the transaction reaches confirmed commitment before returning:

Slippage

Slippage is specified in basis points (bps). If --slippage is omitted, the backend selects a tolerance automatically. If the price moves beyond the tolerance between quote and execution, the transaction reverts.

Response verification

The CLI can cryptographically verify that Trade API responses came from DFlow and were not altered in transit, using RFC 9421 HTTP Message Signatures (ed25519). This is opt-in and off by default. Enable it by setting an environment variable (truthy values: 1, true, yes):
When enabled, every Trade API request asks DFlow to sign its response, and the CLI checks the response before using it:
  • the ed25519 signature validates against DFlow’s pinned public key (baked into the binary, so a swapped key can’t be substituted);
  • the content-digest matches the response body (integrity);
  • the echoed x-request-id matches the per-request id the CLI sent (anti-replay);
  • the signed component set actually covers content-digest and x-request-id (no downgrade).
If any check fails, the CLI returns a RESPONSE_SIGNATURE_INVALID error and discards the response without acting on it.
This defends against a tampered network path (TLS MitM with a mis-issued certificate, BGP hijack, or a compromised intermediary between you and DFlow’s edge). It does not attempt to defend against DFlow’s own backend, which is the entity producing the signature.

Observability

Every outbound API request includes three headers that identify the caller: Self-reporting: Set DFLOW_AGENT=<name> to explicitly identify a custom agent. This takes precedence over automatic detection:
Agent model prompt: When an agent calls quote or trade and no model has been registered (or the registration has expired), the success response includes an additional _hint key:

Logging

The CLI writes two log files under ~/.ows/logs/: The debug log is useful for verifying that agent detection is working correctly in a new environment:

Troubleshooting