Universal AO CLI tool for testing and automating any AO dApp (replaces AOS REPL)
This is a non-interactive command-line interface for the AO (Arweave Offchain) ecosystem. Unlike the official aos REPL tool, this CLI exits after each command completes, making it perfect for automation, testing, and CI/CD pipelines.
This repository is a standalone, self-contained implementation of the AO CLI with its own comprehensive test suite.
- โ Non-REPL Design: Each command executes and exits immediately
 - โ Full AO Compatibility: Works with all AO processes and dApps
 - โ Mainnet & Testnet Support: Seamlessly switch between AO networks
 - โ
 Automatic Module Loading: Resolves and bundles Lua dependencies (equivalent to 
.loadin AOS) - โ Rich Output Formatting: Clean JSON parsing and readable results
 - โ
 Structured JSON Output: 
--jsonoption for automation and scripting - โ Proxy Support: Automatic proxy detection and configuration
 - โ Comprehensive Commands: spawn, eval, load, message, inbox operations
 - โ Self-Contained Testing: Complete test suite included
 
- Node.js 18+
 - npm
 - AO wallet file (
~/.aos.json) 
git clone https://github.com/dddappp/ao-cli.git
cd ao-cli
npm install
npm link  # Makes 'ao-cli' available globallyao-cli --version
ao-cli --helpThis package is published as a scoped package for security and professionalism.
# 1. Run complete test suite
npm link  # Make ao-cli available locally
npm test  # Run all tests to ensure functionality
# 2. Login to npm
npm login
# 3. Test package
npm run prepublishOnly
# 4. Publish (scoped package requires --access public)
npm publish --access public
# View the package
# npm view @dddappp/ao-cli
# 5. Update version for new releases
npm version patch  # or minor/major
npm publish --access public# Install globally
npm install -g @dddappp/ao-cli
# Or use with npx
npx @dddappp/ao-cli --helpSecurity Note: Always verify package downloads and check the official npm page at https://www.npmjs.com/package/@dddappp/ao-cli
# Spawn with default module (testnet)
ao-cli spawn default --name "my-process-$(date +%s)"
# Spawn with custom module
ao-cli spawn <module-id> --name "my-process"
# Spawn on mainnet with default URL (https://forward.computer)
ao-cli spawn default --mainnet --name "mainnet-process"
# Spawn on mainnet with custom URL
ao-cli spawn default --mainnet https://your-mainnet-node.com --name "mainnet-process"# Load a Lua file (equivalent to '.load' in AOS REPL)
ao-cli load <process-id> tests/test-app.lua --waitๆณจๆ๏ผๅฆๆ่ฟ็จIDไปฅ
-ๅผๅคด๏ผๆจๅฏไปฅไฝฟ็จไปฅไธไปปไธ็งๆนๆณ๏ผ
- ไฝฟ็จ
 --ๅ้็ฌฆ๏ผao-cli load -- <process-id> tests/test-app.lua --wait- ๆ่ ๅผๅทๅ ่ฃน๏ผ
 ao-cli load "<process-id>" tests/test-app.lua --wait
# Send a message and wait for result
ao-cli message <process-id> TestMessage --data '{"key": "value"}' --wait
# Send without waiting
ao-cli message <process-id> TestMessage --data "hello"
# Send token transfer with direct properties (for contracts that read msg.Recipient, msg.Quantity)
ao-cli message <token-process-id> Transfer --prop Recipient=<target-address> --prop Quantity=100 --waitๆณจๆ๏ผๅฆๆ่ฟ็จIDไปฅ
-ๅผๅคด๏ผๆจๅฏไปฅไฝฟ็จไปฅไธไปปไธ็งๆนๆณ๏ผ
- ไฝฟ็จ
 --ๅ้็ฌฆ๏ผao-cli message -- <process-id> TestMessage ...- ๆ่ ๅผๅทๅ ่ฃน๏ผ
 ao-cli message "<process-id>" TestMessage ...
# Evaluate code from file
ao-cli eval <process-id> --file script.lua --wait
# Evaluate code string
ao-cli eval <process-id> --data 'return "hello"' --waitๆณจๆ๏ผๅฆๆ่ฟ็จIDไปฅ
-ๅผๅคด๏ผๆจๅฏไปฅไฝฟ็จไปฅไธไปปไธ็งๆนๆณ๏ผ
- ไฝฟ็จ
 --ๅ้็ฌฆ๏ผao-cli eval -- <process-id> --file script.lua --wait- ๆ่ ๅผๅทๅ ่ฃน๏ผ
 ao-cli eval "<process-id>" --file script.lua --wait
# Get latest message
ao-cli inbox <process-id> --latest
# Get all messages
ao-cli inbox <process-id> --all
# Wait for new messages
ao-cli inbox <process-id> --wait --timeout 30๐ Inboxๆบๅถ่ฏดๆ๏ผInbox ๆฏ่ฟ็จๅ ้จ็ๅ จๅฑๅ้๏ผ่ฎฐๅฝๆๆๆฅๆถๅฐ็ๆฒกๆ handlers ๅค็็ๆถๆฏใ่ฆ่ฎฉๅๅคๆถๆฏ่ฟๅ ฅ*่ฟ็จ๏ผๅ้ๆน๏ผ*็ Inbox๏ผ้่ฆๅจ่ฟไธช่ฟ็จ๏ผๅ้ๆน๏ผๅ ้จๆง่กSendๆไฝ๏ผไฝฟ็จ
ao-cli eval๏ผ๏ผๅค้จAPI่ฐ็จไธไผ่ฎฉๆถๆฏ่ฟๅ ฅ Inboxใ๐ --trace ๅ่ฝ่ฏดๆ๏ผ
eval --trace้่ฟๆฅ่ฏข็ฎๆ ่ฟ็จ็็ปๆๅๅฒ๏ผๅฐ่ฏ้่ฟๆถๆฏReference็ฒพ็กฎๅ ณ่ๅนถๆพ็คบๅฏนๅบ็Handlerๆง่ก็ปๆใๅฆๆๆพๅฐ็ฒพ็กฎๅน้ ๏ผไผๆพ็คบ่ฏฅๆถๆฏ่งฆๅhandler็print่พๅบ๏ผๅฆๆๆ ๆณ็ฒพ็กฎๅ ณ่๏ผๅๆพ็คบๆ่ฟ็handlerๆดปๅจไฝไธบๅ่ใๆณจๆ๏ผๅฆๆ่ฟ็จIDไปฅ
-ๅผๅคด๏ผๆจๅฏไปฅไฝฟ็จไปฅไธไปปไธ็งๆนๆณ๏ผ
- ไฝฟ็จ
 --ๅ้็ฌฆ๏ผao-cli inbox -- <process-id> --latest- ๆ่ ๅผๅทๅ ่ฃน๏ผ
 ao-cli inbox "<process-id>" --latest
# Mainnet mode and URL (automatically enables mainnet when set)
export AO_URL=https://forward.computer
# Proxy settings (auto-detected if not set)
export HTTPS_PROXY=http://proxy:port
export HTTP_PROXY=http://proxy:port
# Gateway and scheduler
export GATEWAY_URL=https://arweave.net
export SCHEDULER=http://scheduler.url
# Wallet location
export WALLET_PATH=/path/to/wallet.json
# Test wait time
export AO_WAIT_TIME=3  # seconds to wait between operations๐ Environment Variable Details:
AO_URL: When set, automatically enables mainnet mode and uses the specified URL as the AO node endpoint. No need to combine with--mainnetflag.
- Example:
 export AO_URL=https://forward.computerenables mainnet with Forward Computer node- The CLI parameter
 --mainnettakes priority overAO_URLif both are provided
AO CLI supports both AO testnet and mainnet. By default, all commands use testnet.
# All commands default to testnet
ao-cli spawn default --name "testnet-process"# Use --mainnet flag (uses https://forward.computer as default)
ao-cli spawn default --mainnet --name "mainnet-process"
# Specify custom mainnet URL with --mainnet flag
ao-cli spawn default --mainnet https://your-mainnet-node.com --name "mainnet-process"
# Use AO_URL environment variable (automatically enables mainnet)
export AO_URL=https://forward.computer
ao-cli spawn default --name "mainnet-process"
# Environment variable + custom URL
export AO_URL=https://your-custom-node.com
ao-cli spawn default --name "mainnet-process"- Testnet: 
https://cu.ao-testnet.xyz,https://mu.ao-testnet.xyz - Mainnet: 
https://forward.computer(default), or any AO mainnet node 
- CLI parameters take highest priority (e.g., 
--mainnet https://custom-node.com) - Environment variables are used when CLI parameters are not provided (e.g., 
AO_URL=https://custom-node.com) - Defaults are used when neither CLI nor environment variables are set
 
๐ก Important:
- Setting
 AO_URLenvironment variable automatically enables mainnet mode. You don't need to combine it with--mainnetflag.- Mainnet operations require payment: Unlike testnet, mainnet processes charge fees for computation. Ensure your wallet has sufficient AO tokens.
 
ao-cli spawn default --name test --wallet /path/to/custom/wallet.json#!/bin/bash
# Run the complete test suite
./tests/run-tests.sh# 1. Spawn process
PROCESS_ID=$(ao-cli spawn default --name "test-$(date +%s)" | grep "Process ID:" | awk '{print $4}')
# 2. Load test application
ao-cli load "$PROCESS_ID" tests/test-app.lua --wait
# 3. Test basic messaging
ao-cli message "$PROCESS_ID" TestMessage --data "Hello AO CLI!" --wait
# 4. Test data operations
ao-cli message "$PROCESS_ID" SetData --data '{"key": "test", "value": "value"}' --wait
ao-cli message "$PROCESS_ID" GetData --data "test" --wait
# 5. Test eval functionality
ao-cli eval "$PROCESS_ID" --data "return {counter = State.counter}" --wait
# 6. Check inbox
ao-cli inbox "$PROCESS_ID" --latestAO CLI supports structured JSON output for automation, testing, and scripting. Use the --json flag to enable machine-readable output.
All commands return JSON with a consistent structure:
{
  "command": "spawn|load|message|eval|inbox|address",
  "success": true|false,
  "timestamp": "2025-10-22T01:54:52.958Z",
  "version": "1.0.3",
  "data": {
    // Command-specific data (when successful)
    "processId": "...",
    "messageId": "...",
    "result": {...}
  },
  "error": "error message", // Only present when success is false
  "gasUsed": 123, // Optional, present when applicable
  "extra_fields": {...} // Command-specific additional data
}# Get wallet address in JSON format
ao-cli address --json
# Spawn process and parse the result
PROCESS_ID=$(ao-cli spawn default --name "test" --json | jq -r '.data.processId')
# Send message and check success
ao-cli message "$PROCESS_ID" TestAction --data "test" --wait --json | jq '.success'
# Error handling - errors go to stderr as JSON
ao-cli address --wallet nonexistent.json --json 2>&1 | jq '.error'- Reliable Parsing: No more fragile text parsing with 
grepandawk - Structured Data: Easy access to process IDs, message IDs, and results
 - Error Handling: Consistent error reporting in JSON format
 - CI/CD Ready: Perfect for automated testing and deployment pipelines
 - Language Agnostic: JSON can be parsed by any programming language
 
These options work with all commands:
--json: Output results in JSON format for automation and scripting--mainnet [url]: Enable mainnet mode (uses https://forward.computer if no URL provided)--wallet <path>: Custom wallet file path (default: ~/.aos.json)--gateway-url <url>: Arweave gateway URL--cu-url <url>: Compute Unit URL (testnet only)--mu-url <url>: Messenger Unit URL (testnet only)--scheduler <id>: Scheduler ID--proxy <url>: Proxy URL for HTTPS/HTTP/ALL_PROXY
Environment Variables (Global):
AO_URL: Set mainnet URL and automatically enable mainnet mode (e.g.,AO_URL=https://forward.computer)
Hidden Parameters (for AOS compatibility):
--url <url>: Set AO URL directly (equivalent to AOS hidden parameter)
Get the wallet address from the current wallet.
Usage:
ao-cli addressAlternative Method (if address command is not available):
Send a message to any process and check the receiving process's inbox - the From field will contain your wallet address.
# Send a test message to any process (use an action that won't be handled)
ao-cli message <process-id> UnknownAction --data "test" --wait
# Check the RECEIVING process's inbox to see your address in the From field
ao-cli inbox <process-id> --latestTest Results:
- โ
 Direct 
addresscommand: Shows wallet addressHrhlqAg1Tz3VfrFPozfcb2MV8uGfYlOSYO4qraRqKl4 - โ
 Alternative method: Theoretically verified - When sending unhandled messages to a process, the 
Fromfield in the receiving process's inbox contains the sender's wallet address - ๐ Test Limitation: Due to current network connectivity issues, the inbox method cannot be practically tested, but the implementation follows AO protocol correctly
 
Spawn a new AO process.
Options:
--name <name>: Process name
Load Lua file with automatic dependency resolution.
Options:
--wait: Wait for evaluation result
Evaluate Lua code.
Options:
--file <path>: Lua file to evaluate--data <string>: Lua code string--wait: Wait for result
Send a message to a process.
Options:
--data <data>: Message data (JSON string or plain text)--tag <tags...>: Additional tags in format name=value--prop <props...>: Message properties (direct attributes) in format name=value--wait: Wait for result
Check process inbox.
Options:
--latest: Get latest message--all: Get all messages--wait: Wait for new messages--timeout <seconds>: Wait timeout (default: 30)
All commands provide clean, readable output:
๐ MESSAGE #1 RESULT:
โฝ Gas Used: 0
๐จ Messages: 1 item(s)
   1. From: Process123
      Target: Process456
      Data: {
        "result": {
          "success": true,
          "counter": 1
        }
      }
| Operation | AOS REPL | AO CLI | 
|---|---|---|
| Spawn | aos my-process | 
ao-cli spawn default --name my-process | 
| Spawn (Mainnet) | aos my-process --mainnet <url> | 
ao-cli spawn default --mainnet <url> --name my-process | 
| Spawn (AOS Style) | aos my-process --url <url> | 
ao-cli spawn default --url <url> --name my-process | 
| Load Code | .load app.lua | 
ao-cli load <pid> app.lua --wait | 
| Send Message | Send({Action="Test"}) | 
ao-cli message <pid> Test --wait | 
| Send Message (Inboxๆต่ฏ) | Send({Action="Test"}) | 
ao-cli eval <pid> --data "Send({Action='Test'})" --wait | 
| Check Inbox | Inbox[#Inbox] | 
ao-cli inbox <pid> --latest | 
| Eval Code | eval code | 
ao-cli eval <pid> --data "code" --wait | 
๐ก ้่ฆ่ฏดๆ๏ผ
- ่ฆๆต่ฏInboxๅ่ฝ๏ผๅฟ ้กปไฝฟ็จ
 ao-cli evalๅจ่ฟ็จๅ ้จๆง่กSendๆไฝใ็ดๆฅไฝฟ็จao-cli messageไธไผ่ฎฉๅๅคๆถๆฏ่ฟๅ ฅInbox๏ผๅ ไธบ้ฃๆฏๅค้จAPI่ฐ็จใ- ๅฆๆ่ฟ็จIDไปฅ
 -ๅผๅคด๏ผๆจๅฏไปฅไฝฟ็จ--ๅ้็ฌฆๆๅผๅทๅ ่ฃน๏ผไพๅฆ๏ผao-cli load -- <pid> tests/test-app.lua --waitๆao-cli load "<pid>" tests/test-app.lua --waitใ
ao-cli/
โโโ ao-cli.js          # Main CLI implementation
โโโ package.json       # Dependencies and scripts
โโโ tests/             # Self-contained test suite
โ   โโโ test-app.lua   # Test AO application
โ   โโโ run-tests.sh   # Complete test automation
โโโ README.md          # This file
The repository includes a comprehensive self-contained test suite that verifies all CLI functionality.
# Run all tests
./tests/run-tests.sh
# Custom wait time between operations
AO_WAIT_TIME=5 ./tests/run-tests.shThe test suite covers:
- โ
 Process spawning (
spawncommand) - โ
 Lua code loading (
loadcommand) - โ
 Message sending and responses (
messagecommand) - โ
 Code evaluation (
evalcommand) - โ
 Inbox checking (
inboxcommand) - โ Error handling and validation
 - โ State management and data persistence
 - โ AOS Compatibility: Complete workflow testing (spawn โ load handler โ send message)
 - โ Mainnet Support: Free spawning and message sending to mainnet nodes
 - โ
 Full AOS Compatibility: 
--urlparameter, ANS-104 signing, free mainnet spawning - โ Complete Token Workflow: Spawn โ Load โ Mint โ Balance checking with real contracts
 
AO CLI supports AOS-style mainnet operations using the --url parameter:
# Test complete AOS workflow: spawn โ load handler โ send message โ response
./tests/test-mainnet-free-spawn.sh
# Manual test - spawn process
ao-cli spawn default --url http://node.arweaveoasis.com:8734 --name "test-process"
# Manual test - load handler (like AOS .editor)
ao-cli message <process-id> Eval --data 'Handlers.add("ping", "ping", function(msg) print("pong from " .. msg.From) end)' --url http://node.arweaveoasis.com:8734
# Manual test - send message (like AOS send())
ao-cli message <process-id> ping --data "ping" --url http://node.arweaveoasis.com:8734Key Achievement: AO CLI is fully compatible with AOS --url parameter functionality!
โ Complete AOS Compatibility:
- โ
 Spawn processes without account balance (like 
aos process --url <node>) - โ
 Use correct hyper module for lua@5.3a execution (
wal-fUK-YnB9Kp5mN8dgMsSqPSqiGx-0SvwFUSwpDBI) - โ
 Set proper device configuration (
device: 'process@1.0') for mainnet connections - โ
 Load handlers using 
ao-cli message <id> Eval(equivalent to AOS.editor) - โ
 Send messages to trigger handlers (equivalent to AOS 
send()function) - โ
 Load contracts using 
ao-cli load(equivalent to AOS.load-blueprint) - โ Send signed ANS-104 messages to mainnet nodes
 - โ Use identical signing and request formats as AOS
 - โ
 Work with Arweave Oasis nodes: 
http://node.arweaveoasis.com:8734 - โ Complete workflow: spawn โ load handler โ send message โ response
 
Current Status:
- โ Process spawning: Works reliably on mainnet nodes (AOS compatibility achieved)
 - โ
 Contract loading: Initiates successfully (like AOS 
.load-blueprint) - โ Message sending: Requests sent successfully with ANS-104 signing
 - โ
 Handler execution: Fully working! Can load handlers and see immediate execution results (like AOS 
send()) 
๐ฏ Mission Accomplished: AO CLI now fully supports AOS-style --url parameter for free mainnet operations!
๐ Complete Workflow Tests:
# Test the complete AOS-compatible workflow: spawn + load + mint + balance
./tests/test-ao-token.sh
# Demo: AO CLI vs AOS side-by-side comparison
./tests/demo-aos-compatibility.sh
# Note: If your network requires a proxy to access AO nodes, set these environment variables:
# export HTTPS_PROXY=http://127.0.0.1:1235
# export HTTP_PROXY=http://127.0.0.1:1235
# export ALL_PROXY=socks5://127.0.0.1:1234The tests/test-app.lua provides handlers for:
TestMessage: Basic message testing with counterSetData/GetData: Key-value data operationsTestInbox: Inbox functionality testingTestError: Error handling testing
- 
Dependency Updates
- Regularly update 
@permaweb/aoconnectand other dependencies to latest versions - Add automated dependency vulnerability scanning
 
 - Regularly update 
 - 
Enhanced Error Handling
- Add more granular error messages for different failure scenarios
 - Implement retry logic for network timeouts
 - Add better validation for process IDs and message formats
 
 - 
Performance Optimizations
- Add module caching to speed up repeated code loading
 - Implement parallel processing for batch operations
 - Add connection pooling for multiple AO operations
 
 - 
Testing Improvements
- Add unit tests for individual CLI commands
 - Implement integration tests with different AO dApps
 - Add performance benchmarking tests
 
 - 
Developer Experience
- Add shell completion scripts (bash/zsh/fish)
 - Create VS Code extension for AO development
 - Add interactive mode option alongside non-REPL design
 
 - 
Documentation
- Add video tutorials for common use cases
 - Create cookbook with real-world AO dApp examples
 - Add API reference documentation
 
 - 
CI/CD Integration
- Add GitHub Actions workflows for automated testing
 - Create Docker images for easy deployment
 - Add pre-built binaries for multiple platforms
 
 - 
Monitoring & Observability
- Add metrics collection for operation performance
 - Implement structured logging with log levels
 - Add health check endpoints for monitoring
 
 
We welcome contributions! Please see our contribution guidelines and feel free to submit issues or pull requests.
- 
"fetch failed"
- Check proxy settings
 - Verify network connectivity
 
 - 
"Wallet file not found"
# Ensure wallet exists ls -la ~/.aos.json
 - 
"Module not found" errors
- Check Lua file paths
 - Ensure dependencies are in the same directory
 
 - 
Empty inbox results
- Use 
--waitoption - Increase timeout with 
--timeout 
 - Use 
 
Enable verbose logging:
export DEBUG=ao-cli:*- Add command definition in 
ao-cli.js - Implement handler function
 - Update this README
 
./tests/run-tests.shISC