CLI for interacting with AO processes using @permaweb/aoconnect - spawn processes, send messages, read results, monitor messages, and dry run
A command-line interface for interacting with AO processes using the @permaweb/aoconnect library.
| User Request | Command |
|--------------|---------|
| "use aoconnect to spawn" | spawn |
| "use aoconnect to message" | message |
| "use aoconnect to read result" | result |
| "use aoconnect to dryrun" | dryrun |
| "use aoconnect to monitor" | monitor |
| "use aoconnect to connect" | connect |
Install the aoconnect skill and its dependency:
npx skills add https://github.com/permaweb/skills --skill aoconnect
npm install --save @permaweb/aoconnect
Or manually:
cd skills/aoconnect
npm install @permaweb/aoconnect
node skills/aoconnect/index.mjs spawn \
--wallet ./wallet.json \
--module <module-txid> \
--scheduler <scheduler-address>
Options:
--wallet <path> - Path to Arweave wallet JSON--module <txid> - The arweave TxID of the ao Module--scheduler <address> - The Arweave wallet address of a Scheduler Unit--data <string> - Optional data to include in spawn messageExample:
node skills/aoconnect/index.mjs spawn \
--wallet ./wallet.json \
--module "l3hbt-rIJ_dr9at-eQ3EVajHWMnxPNm9eBtXpzsFWZc" \
--scheduler "_GQ33BkPtZrqxA84vM8Zk-N2aO0toNNu_C-l-rawrBA"
Output:
{
"messageId": "l3hbt-rIJ_dr9at-eQ3EVajHWMnxPNm9eBtXpzsFWZc",
"processId": "5SGJUlPwlenkyuG9-xWh0Rcf0azm8XEd5RBTiutgWAg",
"height": 587540,
"tags": [
{ "name": "App-Process", "value": "l3hbt..." },
{ "name": "App-Name", "value": "arweave-ao" }
]
}
node skills/aoconnect/index.mjs message \
--wallet ./wallet.json \
--process <process-id> \
--data=<message-data> \
--tags Name=Value,Another=Tag
Options:
--wallet <path> - Path to Arweave wallet JSON (required)--process <id> - The ao Process ID (required)--data <string> - Message data (optional, random string if not provided)--tags <name=value,another=value> - Message tags (optional)Example:
node skills/aoconnect/index.mjs message \
--wallet ./wallet.json \
--process "5SGJUlPwlenkyuG9-xWh0Rcf0azm8XEd5RBTiutgWAg" \
--data="Hello from AO!" \
--tags "Action=greet", "User=Rakis"
Output:
{
"messageId": "l3hbt-rIJ_dr9at-eQ3EVajHWMnxPNm9eBtXpzsFWZc",
"height": 587540,
"tags": [
{ "name": "Action", "value": "greet" },
{ "name": "User", "value": "Rakis" },
{ "name": "Original-Message", "value": "l3hbt..." }
]
}
node skills/aoconnect/index.mjs result \
--message=<message-id> \
--process=<process-id>
Options:
--message=<id> - The ao message ID to evaluate (required)--process=<id> - The ao Process ID (required)Example:
node skills/aoconnect/index.mjs result \
--message="l3hbt-rIJ_dr9at-eQ3EVajHWMnxPNm9eBtXpzsFWZc" \
--process="5SGJUlPwlenkyuG9-xWh0Rcf0azm8XEd5RBTiutgWAg"
Output:
{
"messages": [
{
"messageId": "l3hbt-rIJ_dr9at-eQ3EVajHWMnxPNm9eBtXpzsFWZc",
"tags": [
{ "name": "Action", "value": "greet" },
{ "name": "User", "value": "Rakis" }
],
"data": "Hello from AO!"
}
],
"spawns": [],
"output": {
"messages": [
{
"from": "address",
"to": "process-id",
"target": "process-id",
"tags": [
{ "name": "Response", "value": "Hello from AO!" }
],
"data": "",
"height": 587541
}
],
"size": 256
},
"error": null
}
node skills/aoconnect/index.mjs dryrun \
--message=<message-id> \
--process=<process-id>
Options:
--message=<id> - The ao message ID to dry run (required)--process=<id> - The ao Process ID (required)Example:
node skills/aoconnect/index.mjs dryrun \
--message="l3hbt-rIJ_dr9at-eQ3EVajHWMnxPNm9eBtXpzsFWZc" \
--process="5SGJUlPwlenkyuG9-xWh0Rcf0azm8XEd5RBTiutgWAg"
Output:
{
"messages": [
{
"messageId": "l3hbt-rIJ_dr9at-eQ3EVajHWMnxPNm9eBtXpzsFWZc",
"tags": [
{ "name": "Action", "value": "greet" }
]
}
],
"spawns": [],
"output": {
"messages": [
{
"from": "address",
"to": "process-id",
"target": "process-id",
"tags": [
{ "name": "Response", "value": "Hello from AO!" }
],
"height": 587541
}
],
"size": 256
},
"error": null
}
Note: Dry run evaluates the message but doesn't save it to memory. Perfect for testing without committing to the chain.
node skills/aoconnect/index.mjs monitor \
--process <process-id> \
--on-message "<callback>"
Options:
--process <id> - The ao Process ID to monitor (required)--on-message "<function>" - JavaScript function to call for each new message (required)Example:
node skills/aoconnect/index.mjs monitor \
--process "5SGJUlPwlenkyuG9-xWh0Rcf0azm8XEd5RBTiutgWAg" \
--on-message 'return { tags: msg.tags, data: msg.data }'
Note: In chat interface, use this pattern:
node skills/aoconnect/index.mjs monitor --process <id> --on-message "{console.log(msg.tags)}"
node skills/aoconnect/index.mjs connect --mu <url> --cu <url> --gateway <url>
Options:
--mu <url> - Message Unit URL (optional)--cu <url> - Compute Unit URL (optional)--gateway <url> - Arweave gateway URL (optional)Example:
node skills/aoconnect/index.mjs connect \
--mu "https://mu.ao-testnet.xyz" \
--cu "https://cu.ao-testnet.xyz" \
--gateway "https://arweave.net"
Claude Code / OpenCode will automatically invoke the aoconnect skill when you:
use aoconnect to spawn <process>
use aoconnect to message <process> --data=<string>
use aoconnect to read result --message=<id>
use aoconnect to dryrun --message=<id>
The skill will prompt for wallet path if not configured.
node skills/aoconnect/index.mjs message \
--wallet ./wallet.json \
--process "ao-token-demo-AOe5Hdg4UQhOiE0ZYvRjB_8YDhROi3pA0YCEhPzb_KQ" \
--data=<raw-balance-value> \
--tags "Action=Transfer", "Recipient=<address>"
Always dry run first to verify your message works:
node skills/aoconnect/index.mjs message \
--wallet ./wallet.json \
--process <process-id> \
--data="test"
node skills/aoconnect/index.mjs dryrun \
--message=<message-id> \
--process=<process-id>
node skills/aoconnect/index.mjs monitor \
--process "<active-process-id>" \
--on-message "{console.log('New message:', msg.tags)}"
Error: walletPath is required. Please provide a path to your Arweave wallet JSON file.
Solution: Provide a wallet path:
--wallet ./wallet.json
Error: Failed to send message: Invalid process ID
Solution: Verify the process ID is correct and valid.
Error: Failed to send message: Unauthorized
Solution: Ensure your wallet has sufficient balance and proper permissions.
Send a message to an ao Process.
Parameters:
processId (string): The ao Process IDoptions (Object): Message options
data (string): Message datatags (Array): Message tagswalletPath (string): Path to wallet JSONReturns: Promise<Object> - Message result
Read the result of an ao message evaluation.
Parameters:
options (Object)
message (string): The message IDprocess (string): The Process IDReturns: Promise<Object> - Result object
Dry run a message without committing to memory.
Parameters:
options (Object)
message (string): The message IDprocess (string): The Process IDReturns: Promise<Object> - Dry run result
Spawn an ao Process.
Parameters:
options (Object)
module (string): Module TxIDscheduler (string): Scheduler addresswalletPath (string): Path to wallet JSONtags (Array): Tags for spawn messageReturns: Promise<Object> - Spawn result
Monitor messages from a Process.
Parameters:
options (Object)
process (string): Process IDonMessage (Function): Callback for new messagesReturns: string - Monitor ID
Stop monitoring messages.
Parameters:
monitorId (string): Monitor IDConnect to ao nodes with custom configuration.
Parameters:
config (Object)
MU_URL (string): Message Unit URLCU_URL (string): Compute Unit URLGATEWAY_URL (string): Arweave gateway URLReturns: Object - aoconnect functions
Get connected aoconnect functions.
Parameters:
config (Object): Connection configReturns: Object - aoconnect functions
This skill works in both Node.js and browser environments.
import { messageAo, createDataItemSigner } from "./index.mjs";
import { readFileSync } from "node:fs";
const wallet = JSON.parse(readFileSync("./wallet.json", "utf-8"));
const result = await messageAo("process-id", {
walletPath: "./wallet.json",
data: "Hello AO!",
tags: [{ name: "Action", value: "greet" }]
});
import { messageAo, createDataItemSigner } from "./index.mjs";
const result = await messageAo("process-id", {
walletPath: "/path/to/wallet.json", // or loaded from localStorage
data: "Hello AO!",
tags: [{ name: "Action", value: "greet" }]
});
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer