Claude-skill-registry arweave-ao-cookbook
Build decentralized applications on AO - a permanent, decentralized compute platform using actor model for parallel processes with native message-passing and permanent storage on Arweave
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/arweave-ao-cookbook" ~/.claude/skills/majiayu000-claude-skill-registry-arweave-ao-cookbook && rm -rf "$T"
skills/data/arweave-ao-cookbook/SKILL.mdAO Cookbook Skill
Purpose
Master building decentralized applications on AO - a revolutionary decentralized compute system where countless parallel processes interact within a single, cohesive environment. AO combines permanent storage on Arweave with actor model architecture to create truly decentralized, permanently available compute.
What is AO?
AO is a decentralized compute system built on the AO-Core protocol that employs the actor model (inspired by Erlang), enabling independent process operation through native message-passing mechanisms. Each process is an independent server in the network, communicating through messages stored permanently on Arweave.
HyperBEAM is the current production network, delivering:
- High-performance message processing
- Instant HTTP access to process state
- Trustless, permissionless infrastructure
- Permanent availability
Key Differentiator: Unlike traditional blockchains or cloud platforms, AO provides "your personal server in the AO computer" - a genuinely decentralized alternative to traditional hosting with permanent message storage.
When to Use This Skill
✅ Perfect for:
- Building decentralized applications requiring permanent storage
- Creating smart contracts with complex state and interactions
- Developing chatbots, games, and interactive applications on blockchain
- Implementing token systems, voting mechanisms, and governance
- Building systems that require trustless, permanent compute
- Creating applications that benefit from parallel process execution
- Developing Arweave-integrated applications
❌ Not ideal for:
- Simple static websites (use traditional hosting)
- Applications requiring real-time sub-millisecond latency
- Systems that need to delete or modify historical data
- Traditional centralized database applications
- Projects without permanent storage requirements
Core Concepts
1. Processes
Independent servers in the decentralized AO network. Each process:
- Has its own state and memory
- Executes autonomously
- Communicates via messages
- Persists permanently on Arweave
- Can spawn other processes
2. Messages
The core communication mechanism between processes:
- Permanently stored on Arweave
- Asynchronous by nature
- Contain data and metadata
- Trigger handler functions
- Enable process interaction
3. Handlers
Event processors that respond to incoming messages:
- Pattern-match on message properties
- Execute logic based on message content
- Update process state
- Send responses to other processes
- Enable reactive programming model
4. aos (AO Shell)
Interactive development environment:
- Command-line interface for AO processes
- Built-in Lua REPL
- Supports modules and blueprints
- Enables rapid prototyping
- Provides process management tools
5. Permanence
Everything is permanent on Arweave:
- Messages never disappear
- Code is immutable once deployed
- State history is preserved
- Audit trails are built-in
- No centralized control
Installation & Setup
Prerequisites
- NodeJS: Version 20 or higher
- Code Editor: Any editor (VS Code recommended)
- Arweave Wallet (optional): For custom wallet authentication
Step 1: Install AOS
# Install AOS globally via npm npm i -g https://get_ao.arweave.net # Verify installation aos --version
Step 2: Connect to HyperBEAM Network
# Option 1: Connect to HyperBEAM for optimal performance aos --node https://forward.computer # Option 2: Use default settings aos # Option 3: Specify custom wallet aos --wallet ~/.arweave-wallet.json # Auto-generated wallet location # Default: ~/.aos.json (created automatically if not specified)
Step 3: Verify Connection
-- In aos shell, try basic commands: print("Hello AO") -- Output: Hello AO -- Check your process ID Name -- Output: Your process name Owner -- Output: Your wallet address -- View inbox #Inbox -- Output: Number of unhandled messages
Basic Usage Patterns
Pattern 1: Simple State Management
-- Initialize state variable counter = 0 -- Create handler for increment messages Handlers.add( "increment", Handlers.utils.hasMatchingTag("Action", "Increment"), function(msg) counter = counter + 1 print("Counter incremented to: " .. counter) -- Send response Send({ Target = msg.From, Data = tostring(counter) }) end ) -- Access state via HTTP -- https://forward.computer/<process-id>~process@1.0/compute/counter
Why this works: State persists permanently and is accessible via HTTP through HyperBEAM.
Pattern 2: Message Passing Between Processes
-- Send message to another process Send({ Target = "process-id-here", Action = "Chat-Message", Data = "Hello from my process!" }) -- Handle incoming messages Handlers.add( "chat", Handlers.utils.hasMatchingTag("Action", "Chat-Message"), function(msg) print("Received: " .. msg.Data) print("From: " .. msg.From) -- Reply to sender Send({ Target = msg.From, Data = "Message received!" }) end )
Pattern: Asynchronous message-passing enables loosely-coupled process communication.
Pattern 3: Inbox Monitoring
-- Custom prompt showing inbox count function Prompt() return "📬 Inbox: " .. #Inbox .. " > " end -- Check inbox if #Inbox > 0 then -- Access first message local msg = Inbox[1] print("From: " .. msg.From) print("Data: " .. msg.Data) end
Pattern: Monitor incoming messages in real-time with custom prompts.
Pattern 4: Using Modules
-- Load JSON module local json = require("json") -- Encode data local data = { name = "Alice", balance = 1000 } local encoded = json.encode(data) -- Decode JSON local decoded = json.decode(encoded) print(decoded.name) -- Output: Alice -- Use .utils module for functional programming local utils = require(".utils") local numbers = {1, 2, 3, 4, 5} local doubled = utils.map(function(n) return n * 2 end, numbers) -- Result: {2, 4, 6, 8, 10}
Available Modules:
: JSON encoding/decodingjson
: Core AO functions (Send, Spawn)ao
: Base64 encoding/decoding.base64
: Formatted output (tprint).pretty
: Functional utilities (map, reduce, filter).utils
Pattern 5: Multi-line Code with Editor Mode
-- Enter editor mode .editor -- Write multi-line function (type all lines, then Ctrl+D to execute) function createToken(name, symbol, supply) return { Name = name, Symbol = symbol, TotalSupply = supply, Balances = {} } end -- Press Ctrl+D to exit editor mode -- Use the function myToken = createToken("MyToken", "MTK", 1000000) print(myToken.Name) -- Output: MyToken
Pattern 6: Loading External Lua Files
-- Load functions from file .load myFunctions.lua -- Functions from file are now available -- (assuming myFunctions.lua defines functions)
Use case: Organize complex logic in files, load into aos session.
Common Workflows
Workflow 1: Building a Token System
-- Initialize token state Token = { Name = "MyToken", Symbol = "MTK", TotalSupply = 1000000, Balances = {} } -- Initialize owner balance Token.Balances[Owner] = Token.TotalSupply -- Transfer handler Handlers.add( "transfer", Handlers.utils.hasMatchingTag("Action", "Transfer"), function(msg) local recipient = msg.Tags.Recipient local amount = tonumber(msg.Tags.Amount) -- Validate sender has balance if Token.Balances[msg.From] >= amount then Token.Balances[msg.From] = Token.Balances[msg.From] - amount Token.Balances[recipient] = (Token.Balances[recipient] or 0) + amount Send({ Target = msg.From, Data = "Transfer successful" }) else Send({ Target = msg.From, Data = "Insufficient balance" }) end end ) -- Balance query handler Handlers.add( "balance", Handlers.utils.hasMatchingTag("Action", "Balance"), function(msg) local target = msg.Tags.Target or msg.From local balance = Token.Balances[target] or 0 Send({ Target = msg.From, Data = tostring(balance) }) end )
Workflow 2: Creating a Chatroom
-- Chatroom state Chatroom = { Members = {}, Messages = {} } -- Join handler Handlers.add( "join", Handlers.utils.hasMatchingTag("Action", "Join"), function(msg) Chatroom.Members[msg.From] = true -- Notify all members for member, _ in pairs(Chatroom.Members) do Send({ Target = member, Action = "Notification", Data = msg.Tags.Username .. " joined the chatroom" }) end end ) -- Send message handler Handlers.add( "broadcast", Handlers.utils.hasMatchingTag("Action", "Broadcast"), function(msg) -- Store message table.insert(Chatroom.Messages, { From = msg.From, Text = msg.Data, Timestamp = msg.Timestamp }) -- Broadcast to all members for member, _ in pairs(Chatroom.Members) do if member ~= msg.From then Send({ Target = member, Action = "ChatMessage", From = msg.From, Data = msg.Data }) end end end )
Workflow 3: Spawning New Processes
-- Spawn a new process Send({ Target = ao.id, -- ao core process Action = "Eval", Data = [[ -- Code for new process Handlers.add( "ping", Handlers.utils.hasMatchingTag("Action", "Ping"), function(msg) Send({ Target = msg.From, Data = "Pong!" }) end ) ]] }) -- Programmatic spawn with Spawn() local newProcess = Spawn("module-id", { Data = "Initial state", Tags = { Name = "SubProcess", Type = "Worker" } })
Workflow 4: Using Blueprints
Available blueprint templates:
- chatroom: Complete chatroom implementation
- token: Token standard with transfer/balance
- voting: Voting mechanism with proposals
- staking: Token staking with rewards
- CRED: Reputation/credit system
-- Load blueprint (example - actual syntax may vary) -- Blueprints provide pre-built handlers and state management
Advanced Patterns
Pattern: State Persistence & HTTP Access
-- Define state that should be HTTP accessible GameState = { players = {}, score = 0, round = 1 } -- State is automatically accessible via HTTP -- GET https://forward.computer/<process-id>~process@1.0/compute/GameState -- Returns JSON representation of GameState
Power: Any process variable becomes instantly queryable via HTTP through HyperBEAM.
Pattern: Handler Composition
-- Helper function for common checks local function isAuthorized(msg) return msg.From == Owner end -- Composed handler with authorization Handlers.add( "admin-action", function(msg) return Handlers.utils.hasMatchingTag("Action", "Admin")(msg) and isAuthorized(msg) end, function(msg) -- Admin logic here print("Admin action executed") end )
Pattern: Error Handling
Handlers.add( "safe-operation", Handlers.utils.hasMatchingTag("Action", "SafeOp"), function(msg) local success, result = pcall(function() -- Potentially error-prone operation local value = tonumber(msg.Tags.Amount) assert(value > 0, "Amount must be positive") return value * 2 end) if success then Send({ Target = msg.From, Data = tostring(result) }) else Send({ Target = msg.From, Error = result -- Contains error message }) end end )
Troubleshooting
Issue: "aos command not found"
Solution:
# Verify NodeJS version node --version # Should be v20+ # Reinstall aos npm i -g https://get_ao.arweave.net # Check PATH echo $PATH | grep npm
Issue: Connection timeout
Solution:
# Try different node aos --node https://forward.computer # Check network connection curl https://forward.computer # Verify wallet if using custom aos --wallet ~/.arweave-wallet.json
Issue: "Handler not triggering"
Solutions:
-
Check tag matching:
-- Verify message has correct tags print(msg.Tags.Action) -- Should match your matcher -
Test handler directly:
-- Simulate message local testMsg = { From = "test-id", Tags = { Action = "Test" }, Data = "test data" } -- Call handler function manually -
Check handler order:
-- List all handlers Handlers.list() -- Handlers execute in order, first match wins
Issue: State not persisting
Explanation: State in aos session is temporary until messages are sent/processed. To persist:
- Send messages to your process (triggers permanent storage)
- Deploy handlers as permanent code
- Use
to reload functions across sessions.load
Issue: "Inbox full" or performance degradation
Solution:
-- Process and clear inbox for i = 1, #Inbox do local msg = Inbox[i] -- Handle message print("Processing: " .. msg.From) end -- Inbox clears automatically after handlers process messages
CLI Reference
aos Command-Line Options
aos [options] Options: --wallet <path> Path to Arweave wallet (default: ~/.aos.json) --node <url> AO node URL (default: https://forward.computer) --module <id> Module ID for process --cron <interval> Cron interval for process --version Show version --help Show help
aos Shell Commands
| Command | Purpose | Example |
|---|---|---|
| Enter multi-line edit mode | then Ctrl+D to execute |
| Load Lua file | |
| Exit aos shell | |
| Count unhandled messages | |
| Access message at index | |
Global Functions & Variables
| Global | Type | Purpose |
|---|---|---|
| Function | Send message to process |
| Function | Create new process |
| Table | Unhandled messages |
| Module | Handler management |
| String | Process owner address |
| String | Process name |
Best Practices
1. Handler Organization
-- Group related handlers -- Authentication handlers Handlers.add("auth:login", ...) Handlers.add("auth:logout", ...) -- Business logic handlers Handlers.add("game:move", ...) Handlers.add("game:score", ...)
2. State Management
-- Use clear state structures State = { users = {}, config = { maxUsers = 100, timeout = 300 }, stats = { totalMessages = 0, activeUsers = 0 } } -- Avoid global pollution -- Use tables to organize
3. Error Handling
-- Always validate inputs function validateAmount(amount) local num = tonumber(amount) assert(num, "Amount must be a number") assert(num > 0, "Amount must be positive") return num end -- Use pcall for risky operations local success, result = pcall(validateAmount, msg.Tags.Amount) if not success then Send({ Target = msg.From, Error = result }) return end
4. Testing Handlers
-- Create test utilities function testHandler(handler, mockMsg) return pcall(function() handler(mockMsg) end) end -- Test before deploying local testMsg = { From = "test-sender", Tags = { Action = "Transfer", Amount = "100" }, Data = "" } local success, err = testHandler(transferHandler, testMsg) print(success and "✓ Test passed" or "✗ Test failed: " .. err)
5. Documentation
--[[ Handler: token:transfer Purpose: Transfer tokens between addresses Tags Required: - Action: "Transfer" - Recipient: target address - Amount: token amount (string number) Returns: Success/failure message ]] Handlers.add("token:transfer", ...)
Resources
Official Documentation
- Cookbook: https://cookbook_ao.arweave.net/
- HyperBEAM: https://forward.computer
- GitHub: https://github.com/permaweb/ao
Community
- Discord: Community support and discussions
- Tutorials: Begin track, Bots & Games, Advanced guides
Learning Paths
- Getting Started: Welcome → Installation → Basic messaging
- Token Development: Token tutorial → Transfer mechanics → Balance queries
- Game Development: Bots & Games track → State management → Multiplayer
- Advanced: Custom modules → Process spawning → HTTP integration
Examples Repository
See
/examples directory for complete working examples:
- Full chatroom implementationchatroom.lua
- Token standard with all handlerstoken.lua
- Simple game with state managementgame.lua
- Voting system with proposalsvoting.lua
Version History
- 1.0.0 (2025-12-26): Initial skill creation
- Core concepts and patterns
- Installation and setup
- Basic and advanced workflows
- Troubleshooting guide
- CLI reference
- Best practices
Last Updated: December 26, 2025 Source: https://cookbook_ao.arweave.net/ Community: AO Discord and GitHub Status: Production Ready ✅