Your personal EVM blockchain assistant, from the terminal.
A hybrid CLI+TUI tool built with Go for querying and managing multi-chain EVM transactions — optimized for Chiliz Chain, extensible to any EVM network.
Most EVM CLI tools are either too low-level (raw RPC calls) or too generic (Foundry's cast has no concept of saved chains, contacts, or token configs). Chiliz CLI fills the gap:
- Stateful — remembers your chains, tokens, and contacts across sessions via JSON config
- Dual Data Sources — combines RPC (real-time balance, blocks) with Explorer API (transaction history, token discovery) in a single command
- AI Agent Friendly —
--jsonoutput on every command, designed forchiliz address 0x... --json | jq - Chiliz-First — built for a chain with no dedicated CLI tooling (Chiliz is a go-ethereum fork)
- Hybrid — same binary runs as a scriptable CLI or an interactive TUI
Think of it as cast meets a personal wallet manager.
# Install (pick one)
brew tap GrapeInTheTree/tap && brew install chiliz # Homebrew
go install github.com/GrapeInTheTree/chiliz-cli/cmd/chiliz@latest # Go
# Initialize config (Chiliz Mainnet + Spicy Testnet)
chiliz init
# Start querying
chiliz chain-info # Chiliz mainnet status
chiliz validators # validator set
chiliz address 0xC3B2... # any address
chiliz --chain "spicy" chain-info # Spicy testnetbrew tap GrapeInTheTree/tap
brew install chilizgo install github.com/GrapeInTheTree/chiliz-cli/cmd/chiliz@latestPre-built binaries for macOS (Intel/Apple Silicon) and Linux (amd64/arm64) on the Releases page.
git clone https://github.com/GrapeInTheTree/chiliz-cli.git
cd chiliz-cli
go build -o chiliz ./cmd/chilizchiliz address 0xC3B2...D2c49
│
├── RPC (go-ethereum ethclient) ──────────────────> Chiliz Node
│ ├── eth_getBalance → native balance (rpc.ankr.com/chiliz)
│ ├── eth_getTransactionCount → nonce
│ └── eth_getCode → EOA or contract
│
└── Explorer API (Chiliscan/Routescan) ───────────> Indexer
├── txlist → recent transactions
└── addresstokenbalance → all ERC-20 holdings
──> output.Print(jsonMode, AddressInfo)
├── human-readable table (default)
└── JSON (--json flag)
| Data | Source | Why |
|---|---|---|
| Native balance, nonce, code | RPC eth_* |
Standard EVM methods |
| Tx by hash + receipt | RPC | Direct lookup |
| Block by number | RPC | Direct lookup |
| Gas price, chain ID | RPC | Real-time state |
| Tx history by address | Explorer API | No RPC method exists (eth_getTransactionsByAddress doesn't exist) |
| All token holdings | Explorer API | Token discovery requires an indexer |
chiliz Interactive TUI mode (no subcommand)
chiliz address <addr> Address info: balance, nonce, tx history, token holdings
chiliz tx <hash> Transaction details with receipt
chiliz block [number|latest] Block information
chiliz chain-info Chain status: latest block, gas price
chiliz call <contract> <sig> [args] Read-only contract call (eth_call)
chiliz validators Chiliz validator set and staking status
chiliz staking <addr> Personal staking positions and rewards
chiliz token <contract> Token metadata, price, and social links
chiliz contract <addr> Contract info: name, compiler, deployer, verified
chiliz holders <token> Top token holders and total holder count
chiliz logs --address --event On-chain event log filtering via eth_getLogs (RPC)
chiliz rpc <method> [params] Raw JSON-RPC escape hatch
chiliz init Initialize config (~/.chiliz/)
chiliz version Print version and build info
Global flags:
--chain <name> Blockchain network (default: first in chains.json)
--json Machine-readable JSON output
--config <path> Config directory path
-h, --help Help for any command
All address commands support contact names from contacts.json:
chiliz address danial # resolves to 0xef33...d93c
chiliz staking kayen # resolves to 0x86d3...8897
chiliz address 0xC3B2...D2c49 # direct address still worksComprehensive address overview — 5 concurrent fetches (3 RPC + 2 Explorer) for fast response.
$ chiliz address 0xC3B2A6D869868916b1f5D46f9b7C62eD2f1D2c49
Address: 0xC3B2A6D869868916b1f5D46f9b7C62eD2f1D2c49
Chain: Chiliz Chain (88888)
Balance: 5045.818772 CHZ
Nonce: 310
Type: EOA
Token Holdings:
PEPPER 12340.000000
Recent Transactions (last 10):
Hash Method Value Time
-----------------------------------------------------------------
0x9f97...9981 Transfer +3631.087415 4d ago
0x12a8...b3e5 Transfer +316.752300 7d ago
0x1a79...a414 Transfer -316.752300 7d ago
...Full transaction details including receipt, gas breakdown, and event logs.
$ chiliz tx 0x9f978b07484bb439e790079afe192e0a562a93a26c9d893ea8001ddda88e9981
Tx Hash: 0x9f978b...88e9981
Status: success
Block: 32492204
Time: 2026-03-23 00:23:15 UTC
From: 0xa3DF8880d1D1BfC5Bea208AC3f1662420B2E2657
To: 0xC3B2A6D869868916b1f5D46f9b7C62eD2f1D2c49
Value: 3631.087415 CHZ
Gas Price: 5001.00 Gwei
Gas Used: 21000 / 21000
Tx Fee: 0.105021 CHZ
Nonce: 5343
Logs: 0 events$ chiliz block latest
Block: #32617854
Hash: 0x3f1317eb...75aeb5a
Time: 2026-03-27 09:05:54 UTC
Miner: 0xc10ae5Cd2C63E4065f81E241c93237E06E12d41b
Gas Used: 70012 / 30000000
Base Fee: 2500.00 Gwei
Txs: 1 transactionsGeneric read-only contract calls — query any smart contract function.
# ERC-20 totalSupply
$ chiliz call 0x60F397acBCfB8f4e3234C659A3E10867e6fA6b67 "totalSupply()(uint256)"
8760093706618541126999998364250000
# Token name and decimals
$ chiliz call 0x60F397acBCfB8f4e3234C659A3E10867e6fA6b67 "name()(string)"
PEPPER
# Chiliz validator list (system contract)
$ chiliz call 0x0000000000000000000000000000000000001000 "getValidators()(address[])"
[0x8d9B6aB3..., 0xBf968b8a..., 0x31dB8118..., ...]
# Check if address is a validator
$ chiliz call 0x0000000000000000000000000000000000001000 "isValidator(address)(bool)" 0x8d9B6aB3Fe8EbF16d9242e48feFB89360fa62820
true
# JSON output
$ chiliz call 0x60F397acBCfB8f4e3234C659A3E10867e6fA6b67 "totalSupply()(uint256)" --json
{
"contract": "0x60F397acBCfB8f4e3234C659A3E10867e6fA6b67",
"method": "totalSupply()",
"values": ["8760093706618541126999998364250000"],
"raw": "0x000000000000000000000000000000000001afe7ed5e433cdebfb05bd38def90"
}
# Raw hex (no output types specified)
$ chiliz call 0x60F397acBCfB8f4e3234C659A3E10867e6fA6b67 "totalSupply()"
0x000000000000000000000000000000000001afe7ed5e433cdebfb05bd38def90Chiliz-exclusive: query on-chain Staking + Governance contracts for validator status with APY and Voting Power.
$ chiliz validators
Chiliz Chain Validators (13 active)
# Address Status Staked APY VP Commission
----------------------------------------------------------------------------------
1 0x8d9B...2820 Active 293.33M CHZ 18.32% 12.40% 1.0%
2 0xBf96...0B5f Active 291.01M CHZ 17.57% 12.30% 5.0%
3 0x31dB...B074 Active 256.79M CHZ 16.65% 10.85% 10.0%
4 0xa90d...A00e Active 222.23M CHZ 17.57% 9.39% 5.0%
...APY is estimated from on-chain rewards data (same approach as the staking web UI). Voting Power matches exactly.
$ chiliz chain-info --json
{
"name": "Chiliz Chain",
"chain_id": 88888,
"rpc_url": "https://rpc.ankr.com/chiliz",
"latest_block": 32617854,
"gas_price": "2501.00 Gwei",
"currency_symbol": "CHZ"
}Every command supports --json for piping and AI agent consumption:
chiliz address 0xC3B2... --json | jq .native_balance
chiliz chain-info --json | jq .latest_block
chiliz tx 0x9f97... --json | jq '{status, fee: .tx_fee}'Run chiliz with no arguments for interactive mode.
┌─────────────────────────────────────┐
│ 🔗 GO-ETHEREUM-BUTLER 🔗 │
│ Multi-Chain EVM Transaction Manager│
│ │
│ ┌─────────────────────────────┐ │
│ │ Main Menu │ │
│ │ │ │
│ │ 📤 Send Transaction │ │
│ │ 💰 Check Balance ◄ │ │
│ │ 🚪 Exit │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
| Key | Action |
|---|---|
up / k |
Move cursor up |
down / j |
Move cursor down |
enter |
Select / Confirm |
esc |
Back to main menu |
ctrl+c |
Quit |
0-9, . |
Amount input (send flow) |
backspace |
Delete last character |
Check Balance — Select wallet > chain > token (native or ERC-20) > view balance
Send Transaction — Select wallet > chain > token > recipient > enter amount > confirm > tx hash
Chiliz CLI uses JSON config files. All are gitignored by default — create your own from the examples below.
[
{
"name": "Chiliz Chain",
"rpc_url": "https://rpc.ankr.com/chiliz",
"chain_id": 88888,
"currency_symbol": "CHZ",
"logo_url": "",
"explorer_api_url": "https://api.routescan.io/v2/network/mainnet/evm/88888/etherscan/api"
}
]| Field | Required | Description |
|---|---|---|
name |
Yes | Display name, also used with --chain flag |
rpc_url |
Yes | Any EVM-compatible JSON-RPC endpoint |
chain_id |
Yes | EIP-155 chain ID |
currency_symbol |
Yes | Native token symbol (CHZ, ETH, etc.) |
logo_url |
No | Optional logo URL |
explorer_api_url |
No | Etherscan-compatible API URL. Enables tx history and token discovery. Without it, CLI still shows RPC-based data. |
[
{
"symbol": "PEPPER",
"name": "Pepper Token",
"address": "0x60F397acBCfB8f4e3234C659A3E10867e6fA6b67",
"decimals": 18,
"chain_id": 88888,
"logo_url": ""
}
]decimalsmust match the contract (18 for most, 6 for USDC/USDT, 8 for WBTC)chain_idmust match a chain inchains.json- Native tokens (CHZ, ETH) are automatically available — no entry needed
- Same token on different chains needs separate entries
[
{ "name": "My Friend", "address": "0x..." },
{ "name": "Team Wallet", "address": "0x..." }
]Used by the TUI send flow for recipient selection.
BUTLER_WALLET_MAIN=your_private_key_here_without_0x_prefix
BUTLER_WALLET_TEST=your_test_private_key_hereCopy from .env.example. Private keys are never logged, cached, or committed to git. CLI read-only commands (address, tx, block, chain-info) do not access private keys at all.
Config Directory Resolution
Chiliz CLI searches for config files in this order:
--config /path/to/dirflag (explicit)CHILIZ_CONFIG_DIRenvironment variable~/.chiliz/directory (ifchains.jsonexists there)- Current working directory (default)
This allows installing chiliz globally via brew and keeping configs in ~/.chiliz/.
cmd/chiliz/
main.go Entry point: Cobra Execute()
cmd/
root.go Root command + global flags + PersistentPreRunE
tui.go TUI launcher (no-args fallback)
address.go chiliz address — parallel RPC + Explorer
tx.go chiliz tx — tx + receipt lookup
block.go chiliz block — block by number
chaininfo.go chiliz chain-info — chain status
call.go chiliz call — generic contract reads (eth_call)
internal/
domain/
models.go Chain, Token, Wallet, Contact structs
output.go AddressInfo, TxDetail, BlockInfo, ChainStatus, CallResult
infra/
config/config.go JSON/env config loading + path resolution
ethereum/
client.go RPC: balance, nonce, code, blocks, tx, gas, call
abi_helper.go Dynamic ABI encoding/decoding (no abigen needed)
erc20.go ERC-20: balance, transfer, formatting
abi/erc20.json Standard ERC-20 ABI
contracts/erc20.go Auto-generated Go bindings (abigen)
explorer/
etherscan.go Chiliscan API: tx history, token discovery
output/
formatter.go Human + JSON dual formatter
tui/
app.go Bubble Tea router
style/style.go Lipgloss styles
pages/ mainmenu, balance, send
Design Decisions
Cobra + Bubbletea hybrid — Cobra routes subcommands. No args = Bubbletea TUI. Single binary, same infra layer shared. This follows the pattern used by lazygit, k9s, and other Go CLI/TUI hybrids.
Package-level appContext — CLI commands share resolved config/chain/explorer via a package-level struct in root.go. Appropriate for a CLI tool (single execution path, no concurrency at the command level). Not suitable for a server; would need DI then.
Each RPC function creates its own ethclient — Dial → defer Close → call → return. For a CLI that runs one command and exits, connection pool overhead isn't worth the lifecycle management complexity.
Explorer graceful degradation — If a chain has no explorer_api_url or the API is down, chiliz address still shows balance, nonce, and contract status from RPC. Explorer sections are simply omitted.
Output types in domain/ — AddressInfo, TxDetail, etc. are stable JSON contracts. Placing them in domain/ keeps them framework-agnostic and reusable across CLI, TUI, and future API layers.
pow10 uses big.Int — The original int64-based pow10() would silently overflow for tokens with >18 decimals. Fixed to use big.Int.Exp() which is safe for any decimal count.
Dynamic ABI via abi_helper.go — chiliz call uses abi.ParseSelector + Arguments.Pack/Unpack for runtime ABI encoding without JSON files. The same module will be reused by future commands (validators, staking, event logs). ParseCallSignature splits cast-style signatures via parenthesis depth counting because abi.ParseSelector rejects trailing characters.
Releases are automated via GoReleaser + GitHub Actions.
# 1. Commit your changes
git add . && git commit -m "feat: ..."
# 2. Tag and push
git tag v0.3.0
git push && git push --tags
# 3. GitHub Actions automatically:
# - Cross-compiles linux/darwin × amd64/arm64
# - Creates GitHub Release with changelog and binaries
# - Updates Homebrew formula in GrapeInTheTree/homebrew-tapUsers upgrade with brew upgrade chiliz or go install ...@latest.
Release Infrastructure Details
| File | Purpose |
|---|---|
.goreleaser.yml |
Build matrix (linux/darwin × amd64/arm64), archive format, Homebrew tap config |
.github/workflows/release.yml |
Triggered on v* tag push, runs goreleaser release --clean |
Required GitHub secrets:
HOMEBREW_TAP_TOKEN— Fine-grained PAT withreposcope onGrapeInTheTree/homebrew-tapGITHUB_TOKEN— Automatic, used for creating GitHub Releases
Chiliz CLI supports tab completion for bash, zsh, and fish:
# Bash
chiliz completion bash > /etc/bash_completion.d/chiliz
# Zsh (add to ~/.zshrc: fpath=(~/.zsh/completions $fpath))
chiliz completion zsh > ~/.zsh/completions/_chiliz
# Fish
chiliz completion fish > ~/.config/fish/completions/chiliz.fishgo build -o chiliz ./cmd/chiliz # Build
go test ./... # Test (22 cases)
go vet ./... # Lint
tail -f chiliz.log # TUI logsRegenerate ERC-20 Bindings
If you update internal/infra/ethereum/abi/erc20.json:
go install github.com/ethereum/go-ethereum/cmd/abigen@latest
abigen --abi internal/infra/ethereum/abi/erc20.json \
--pkg contracts --type ERC20 \
--out internal/infra/ethereum/contracts/erc20.goExtending the App
No code changes needed:
| What | File |
|---|---|
| Add EVM chain | chains.json (include explorer_api_url for tx history) |
| Add ERC-20 token | tokens.json (decimals must match contract) |
| Add contact | contacts.json |
Code changes needed:
| What | Where |
|---|---|
| Add CLI command | Create cmd/chiliz/cmd/<name>.go, register in root.go init() |
| Add wallet | internal/infra/config/config.go LoadWallets() + .env |
| Add TUI page | Create internal/tui/pages/<name>/model.go, register in app.go |
| Add blockchain query | Add to internal/infra/ethereum/client.go |
| Add explorer query | Add to internal/infra/explorer/etherscan.go |
| Add output type | Add struct to internal/domain/output.go, add case in internal/output/formatter.go |
| Add contract type | Place ABI in abi/, run abigen, use bindings in new file |
| Component | Technology |
|---|---|
| Language | Go 1.25+ |
| CLI Framework | spf13/cobra v1.10.2 |
| TUI Framework | charmbracelet/bubbletea v1.3.10 |
| TUI Styling | charmbracelet/lipgloss v1.1.0 |
| EVM Client | ethereum/go-ethereum v1.16.7 |
| Env Loader | joho/godotenv v1.5.1 |
| Release | GoReleaser + GitHub Actions |
| Explorer API | Chiliscan (Routescan, Etherscan-compatible) |
- Private keys live only in
.env(gitignored) and are loaded on-demand at signing time viaconfig.GetPrivateKey() - Keys are never cached in memory, logged, or written to any file
- CLI read-only commands never access private keys
- Git history audited: no secrets have ever been committed
- Log file permissions set to
0600(owner read/write only) .env,chains.json,tokens.json,contacts.jsonare all gitignored