@doma-protocol/cli
v0.7.3
Published
CLI tool for Doma Protocol
Keywords
Readme
Doma CLI
Command-line tool for interacting with the Doma Protocol: token trading, secondary-market buying and selling, ERC20 approvals, domain and DNS management, cross-chain bridging, and an agentic wallet for hands-off signing. Designed for both AI agents and developers.
Installation
npm install -g @doma-protocol/cliRequires Node.js >= 22.
Authentication
doma-cli signs transactions two ways. Use either, or keep both and let walletMode choose:
- Private key: set it once with
doma config set privateKey <key>(stored in the macOS Keychain when available, or pass--plaintextto keep it in config.json). Good for local and dev use. - Agentic wallet: run
doma auth loginto authorize the CLI to trade with your Doma wallet through a browser-approved spending cap, with no raw key on disk. See docs/agentic-wallet.md.
The active signer is chosen by walletMode (default auto: use an agent session if one exists, otherwise the private key; also agent or private-key). Read-only commands (token, domain, quote, balance, dns list) need neither.
Configuration
Configure with doma config set <key> <value>:
doma config set privateKey "your-private-key"
doma config set apiKey "your-api-key"Or edit ~/.doma/config.json directly:
{
"privateKey": "your-private-key",
"apiKey": "your-api-key"
}A private key is required for transaction commands (swap, bridge, dns set, nameservers set, etc.). Read-only commands like token, domain, and dns list work without one.
On macOS, doma config set privateKey stores the key in Keychain instead of the config file. Use --plaintext to store in config.json instead. On other platforms, config.json is used automatically.
Environment variables can also be used and take precedence over the config file:
| Config Key | Environment Variable | Description | Default |
| --------------- | ---------------------- | ---------------------------------------------- | ------- |
| privateKey | DOMA_PRIVATE_KEY | Wallet private key (required for transactions) | |
| apiKey | DOMA_API_KEY | API key for Doma GraphQL | |
| apiUrl | DOMA_API_URL | API endpoint (overridden by --testnet) | |
| routingApiUrl | DOMA_ROUTING_API_URL | Routing API endpoint | |
| chainId | DOMA_CHAIN_ID | Default chain ID | 97477 |
| testnet | DOMA_TESTNET | Use testnet | false |
| walletMode | DOMA_WALLET_MODE | Signer selection: auto, agent, private-key | auto |
Use --testnet on any command to target Doma Testnet:
doma --testnet dns list mydomain.comOn Doma chains, agent-mode transactions are gasless: the launchpad sponsors gas via ERC-4337 and EIP-7702, so the embedded wallet needs no ETH (see docs/agentic-wallet.md). In private-key mode, DNS and nameserver writes are likewise gasless via the same mechanism; other private-key writes pay their own gas.
Supported Chains
| Chain | ID |
| ------------ | ------- |
| Doma Mainnet | 97477 |
| Doma Testnet | 97476 |
| Ethereum | 1 |
| Base | 8453 |
Commands
| Command | What it does | Guide |
| --- | --- | --- |
| doma token | Token price, volume, venue, liquidity | below |
| doma balance | Wallet balances | below |
| doma quote | Best-route swap quote | below |
| doma swap | Execute a token swap | below |
| doma approve | Approve an ERC20 to a spender | below |
| doma bridge | Bridge ETH/USDC across chains | below |
| doma domain | On-chain info for a tokenized domain | below |
| doma subdomain | Manage subdomains via staking | below |
| doma dns | Manage on-chain DNS records | below |
| doma nameservers | Manage domain nameservers | below |
| doma marketplace | Buy and sell domains | docs/marketplace.md |
| doma auth | Agentic wallet (sign without a raw key) | docs/agentic-wallet.md |
| doma agent | Provision and verify agent identities (DNSid) | below |
| doma config | Show and manage CLI configuration | below |
Token
Get detailed token information including price, 24h change, volume, trading venue, fees, and liquidity.
doma token <token>Balance
Check wallet balances. Defaults to ETH + USDC if no token is specified.
doma balance [token]Quote
Get a swap quote. Auto-detects the best route (launchpad bonding curve, Uniswap V3, or multi-step).
doma quote <tokenIn> <tokenOut> <amount>Swap
Execute a token swap.
doma swap <tokenIn> <tokenOut> <amount>Options:
-s, --slippage <bps>: slippage tolerance in basis points (default: 50 = 0.5%)-y, --yes: skip the confirmation prompt
Approve
Approve an ERC20 token to a spender on the current chain. Defaults to approving Permit2 with the canonical unlimited amount (what Uniswap V3 swaps need). Works in both private-key and agent wallet modes.
doma approve <token>Options:
-c, --chain <chain>: chain name or ID (doma,base,97476,8453)--spender <addr>: spender address (default: the active chain's Permit2)--amount <human>: approval amount in human units (default: unlimited). Mutually exclusive with--revoke.--revoke: approve 0 (revoke the allowance). Mutually exclusive with--amount.--check: read-only, print the current on-chain allowance and exit-y, --yes: skip the confirmation prompt--quiet: suppress narration (for scripting)-f, --format <format>: output format
Native ETH cannot be approved (ERC20 only).
Bridge
Bridge ETH or USDC between Doma, Ethereum, and Base via Relay.
doma bridge <token> <amount> --from <chain> --to <chain>Default route is Doma to Base.
Domain
Get detailed on-chain information about a tokenized domain, including nameservers, DNSSEC DS keys, expiration, and token IDs.
doma domain <name>Subdomain
Manage subdomains through token staking.
doma subdomain check <label> <domain> # Check availability and price
doma subdomain claim <label> <domain> # Stake tokens to claim
doma subdomain unstake <nameOrId> # Unstake and release
doma subdomain list [domain] # List subdomains (--mine for yours)Options for list: --mine (only your subdomains), --take <n> (limit the number of results).
Alias: doma sub
DNS
Manage on-chain DNS records. Only available for domains using Doma nameservers.
doma dns list <domain> # List all records (alias: ls)
doma dns set <domain> <name> <type> <value> # Set a record
doma dns delete <domain> <name> <type> # Delete a recordOptions:
--host <host>: filterlistoutput by host--ttl <seconds>: TTL for the record onset(default: 3600)
Nameservers
Manage nameservers for a domain.
doma nameservers list <domain> # List current nameservers
doma nameservers set <domain> <ns1> [ns2] [ns3] [ns4] # Set nameservers (1-4)Aliases: doma ns set, doma ns list, doma ns ls
Only root domains are supported; subdomains cannot have nameservers set.
Marketplace
Buy and sell tokenized domains on the secondary market. Alias: doma mp.
doma marketplace get <domain> # Check if a domain is listed
doma marketplace buy <domain> # Buy the active listing
doma marketplace offer <domain> <amount> # Make a gasless offer
doma marketplace accept <orderId> # Accept an offer
doma marketplace cancel <orderId> # Cancel a listing or offerSee the full guide: docs/marketplace.md.
Agentic wallet (auth)
Authorize doma-cli to trade with your Doma wallet without pasting a private key. You approve a spending cap in the browser; the CLI signs through the launchpad until you revoke.
doma auth login # Authorize (opens browser); --amount <usd> for a custom cap
doma auth refill # Reset the spent allowance
doma auth set-cap <usd> # Change the cap without re-authorizing
doma auth revoke # Revoke access
doma auth status # Show wallet mode and sessionSee the full guide: docs/agentic-wallet.md.
Agent (DNSid)
Provision and verify a sybil-resistant agent identity on a Doma domain, built entirely on the existing on-chain DNS write/read. dnsid generates an Ed25519 keypair and publishes a self-signed DNSid -01 TXT record at the _dnsid host; verify runs a real Ed25519 signature check; verdict prints the phased trust decision. The -01 record splits keys: the entity key ek signs the record (sg), while ku is the operational/request key (the Web Bot Auth directory URL); sg is verified against ek, never ku (the -00 oi tag is renamed gi). Commands accept a registered apex domain; the --id FQDN may be the apex itself or a subdomain under it (e.g. billing.acme.ai).
doma agent dnsid <domain> --id <fqdn> # Provision a self-signed DNSid identity
doma agent webbotauth <domain> --id <fqdn> --dir-host <host> # Emit the Web Bot Auth directory + RFC 9421 signed sample request
doma agent wallet <domain> --id <fqdn> --keyid <thumbprint> # Produce the EIP-712 walletBinding + wallet:did:pkh:... discovery pointer
doma agent set <domain> --endpoint <url> # Write the _agentroot agent record (with identity pointers)
doma agent get <domain> --id <fqdn> # Read back the DNSid record
doma agent verify <domain> --id <fqdn> # Verify the DNSid Ed25519 signature
doma agent verdict <domain> --id <fqdn> # Print the phased trust verdict (JSON)Options:
--id <fqdn>: agent FQDN (<domain>or a subdomain of it); required ondnsid,webbotauth,get,verify,verdict--dir-host <host>: host that will serve/.well-known/http-message-signatures-directory; required onwebbotauth--ttl-days <n>: directory key validity window in days forwebbotauth(default: 30)--out <file>: write the directory JWK Set to a file instead of stdout (forwebbotauth)--ku <uri>: operational key directory URL (Web Bot Auth) fordnsid; omit to default to the agent FQDN.well-knowndirectory. This is the request key published viaagent webbotauth; it does not sign the record.--ek <uri>: entity JWKS URI (https:// on thegidomain) fordnsid— the key that signs the record. Omit to inline the generated entity key as adata:URI. When you pass an https--ek,dnsidprints the generated entity JWK so you can host it at that endpoint.--su <url>: status URL fordnsid(defaults tohttps://<id>/.well-known/dnsid-status)--endpoint <url>: agent endpoint (https only); required onset--record-id <id>: agent record id onset(default:agent)--name <name>,--caps <list>: optionalsetfields--identity <bindings...>: optionalsetidentity pointers, given as space-separated args (e.g.--identity dnsid:billing.acme.ai webbotauth:https://host/...); joined with a comma in the record asidentity=dnsid:billing.acme.ai,webbotauth:https://host/...--ttl <seconds>: TTL for the published record (default: 3600)
Agent identity (key publication)
| Command | Description |
| --- | --- |
| doma agent webbotauth <domain> --id <fqdn> --dir-host <host> | Emit the Web Bot Auth directory JWK Set and a signed RFC 9421 sample request; prints the webbotauth:<directory-url> pointer to wire via agent set |
| doma agent wallet <domain> --id <fqdn> --keyid <thumbprint> | Sign the EIP-712 WalletBinding (domain + keyid, no verifyingContract) with the configured private-key wallet; prints the did:pkh + signature + wallet:did:pkh:... pointer to wire via agent set. --keyid is the RFC 7638 thumbprint of the operational ku key (from agent webbotauth). Use --chain to specify the eip155 chainId (defaults to config chain). |
The signature check is self-asserted (it proves the record was signed by the published key), not a registry attestation or provenance grade.
Mainnet vs testnet: commands target Doma mainnet (chain 97477) by default; add --testnet for chain 97476. Mainnet writes are gasless through Doma's paymaster, and the signer must own the domain (doma config set privateKey or DOMA_PRIVATE_KEY).
Verifying a wallet binding needs the EIP-712 signature published in an AgentRoot manifest, because an inline pointer can only carry method:id. Mint the key (webbotauth), sign the binding (wallet), host an agentroot.json whose identities[] carries the wallet keyid and signature, then point _agentroot at it with doma dns set <domain> _agentroot TXT "v=ar1 manifest=<url>". The manifest is authoritative (it replaces inline records), so fold any existing records into it. Full runbook in docs/agent-identity.md.
Config
Show and manage CLI configuration.
doma config # Show current config
doma config list # Show current config (alias: ls)
doma config get <key> # Show a single value
doma config set <key> <value> # Set a config value
doma config delete <key> # Remove a config value (alias: rm)Valid keys: privateKey, apiKey, apiUrl, chainId, testnet, routingApiUrl, walletMode
Common Options
--testnet is a global flag (works before any command) that targets Doma Testnet.
Most commands also accept:
-c, --chain <chainId>: target chain (where applicable)-f, --format <format>: output format (json,table, orcompact)-y, --yes: skip the confirmation prompt on write commands that prompt-q, --quiet: suppress progress output (on commands that support it:token,quote,swap,approve)
Agent / scripting contract
doma-cli is built to be driven by agents and scripts:
-f, --format json: emit machine-readable JSON on stdout.-q, --quiet: suppress narration so stdout contains only the final result (supported ontoken,quote,swap,approve).swap --quietalso requires--yes(no TTY for the prompt).- Results go to stdout; errors and progress go to stderr.
- Commands exit non-zero on failure, so scripts can branch on exit code.
doma swap USDC <name> 10 --yes --quiet --format json | jq '.["Tx Hash"]'For the full capability map and the convention for keeping these docs in sync, see AGENTS.md.
Development
npm install
npm run dev # Run with tsx
npm run build # Build to dist/
npm run typecheck # Type-check without emitting
npm test # Run the doc-coverage test
npm run verify # typecheck + test + build (the CI + pre-push gate)A husky pre-push hook runs npm run verify before each push (wired by npm install). CI runs the same gate on every PR to main. Use git push --no-verify only for genuine emergencies.
Publishing
Publishing to npm happens automatically when you push a version tag (e.g., v0.7.0, v0.8.0). The CI/CD pipeline ensures the tag version matches package.json before publishing.
Release workflow
Update the version in
package.json:npm version patch # or minor/majorThis automatically commits the version bump and creates a git tag.
Push the tag to trigger the publish:
git push origin main --follow-tagsThe CI pipeline will:
- Run verify (typecheck, test, build)
- Validate the tag matches
package.jsonversion - Build the package
- Publish to npm
A Slack notification will be sent when publishing completes (success or failure)
The package is available at https://www.npmjs.com/package/@doma-protocol/cli
