Your AI agent’s new best friend
curl -fsS https://cli.dflow.net | sh- 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
Thedflow CLI is a single self-contained binary that runs on macOS and Linux.
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
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:
- OS keychain (if saved via
dflow setuporwallet keychain-sync) DFLOW_PASSPHRASEenv var (read once, then cleared from the environment)- Password prompt
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.
Creating and importing keys
- Create:
dflow setupwith 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 (fromsolana-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>with0600permissions. The secret is never printed to the terminal (so it can’t leak into scrollback or recordings),--outis required, and a symlink at the destination is refused. Requires a typed vault password. Highly sensitive: use for backup or migration only. The confirmation includeswordCountand 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: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):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):
dflow whoami prints only the pubkey string on success.
Token resolution
Symbols resolve to mints (built-in list includesSOL, 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
Usefund 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:
<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.
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
/order endpoint and returns the route, expected output amount, and price impact, without executing anything.
Execute a trade
/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):
- the ed25519
signaturevalidates against DFlow’s pinned public key (baked into the binary, so a swapped key can’t be substituted); - the
content-digestmatches the response body (integrity); - the echoed
x-request-idmatches the per-request id the CLI sent (anti-replay); - the signed component set actually covers
content-digestandx-request-id(no downgrade).
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:
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: