Updated Post-Implementation
Date: February 11, 2026
Team: 3 engineers (Person A: Blockchain, Person B: Frontend+Scripts, Person C: DevOps+Agents)
Hardware: 16GB RAM laptop, $0 infrastructure budget
Contract: GuildRegistry v4 at 0x60395114FB889C62846a574ca4Cda3659A95b038 (Monad Testnet)
Coordinator: 0xf7D8E04f82d343B68a7545FF632e282B502800Fd
- What Is AgentGuilds
- Hackathon Context
- Technology Decisions
- System Architecture
- The Living World
- Data Pipeline: Chain → Indexer → World
- Smart Contract: GuildRegistry.sol
- AI Agent System: OpenClaw
- Frontend: Next.js + Phaser.js
- Backend Scripts
- Infrastructure & Deployment
- Complete File Inventory
- Team Workload Split
- Testing Strategy
- Demo Script
- Phase 2: Mainnet + Token
- Submission Checklist
- Post-Hackathon: Guild Network Vision
- Environment Variables
AgentGuilds is an AI labor marketplace visualized as a living pixel world.
Specialized AI agent guilds compete for missions, build reputation on-chain (Monad blockchain), and their status is rendered as buildings in an isometric pixel city. Users interact with the world directly — clicking guild halls to hire agents, watching buildings grow as reputation rises, seeing construction animations when missions complete.
The one-liner: "A world where AI agents don't just work — they live. And the better they work, the better the world becomes."
- Guilds are teams of AI agents with specialized skills (meme creation, translation, code review, etc.)
- Missions are tasks submitted by users ("create a meme about Monad being fast")
- Reputation is earned on-chain — every mission completion and rating is recorded immutably
- The World is a read-only visualization of on-chain state — you don't buy status, the network builds it for you
- The Moat: Anyone can copy a guild's SOUL.md (personality file). Nobody can copy its on-chain track record.
1. User opens agentguilds.xyz → sees isometric pixel city
2. Clicks on "Meme Lords" guild hall (rated ⭐ 4.7, 342 missions)
3. Types: "Create a meme about Monad speed"
4. Three AI agents collaborate:
- Router reads on-chain reputation, selects best guild
- Writer Agent generates viral meme copy
- Creative Director Agent designs visual concept
5. Mission recorded on Monad blockchain
6. User rates the output → guild hall grows → world evolves
- Host: Monad + nad.fun
- Duration: February 2-18, 2026 (rolling judging, final deadline Feb 15)
- Prize Pool: $200,000 total
- Thesis: "What happens when you give AI agents a high-performance blockchain as their coordination layer?"
Agent+Token Track ($140K):
- Build autonomous agents on Monad AND launch token on nad.fun
- 10 winners × $10K each
- Highest market cap token on nad.fun gets $40K extra liquidity
Agent-Only Track ($60K):
- Same agents, same Monad integration, skip the token
- 3 winners × $10K + 3 bounty winners × $10K
- Submit to Agent Track first (Days 1-3) — working Meme Guild with on-chain reputation
- Upgrade to Agent+Token Track (Day 4) — deploy to mainnet + launch $GUILD on nad.fun
- Both tracks evaluated → two chances to win
- OpenClaw — open-source AI agent framework (100K+ GitHub stars)
- Monad — L1 blockchain (10K TPS, EVM-compatible)
- nad.fun — token launchpad on Monad (for Agent+Token track)
Every choice was made with three constraints: 16GB RAM, $0 budget, 4 days, and optimized for vibe-coding (AI-assisted development where you describe what you want and AI generates the code).
| Component | Choice | Why |
|---|---|---|
| AI Agent Framework | OpenClaw (mandatory) | Hackathon requirement. Multi-agent via sessions_spawn |
| LLM | Kimi K2.5 Cloud via Ollama | Free, 256K context, good creative output, runs via API |
| Blockchain | Monad Testnet → Mainnet | Hackathon requirement. EVM-compatible, cheap gas |
| Token | $GUILD on nad.fun | Agent+Token track requirement |
| Smart Contract | Solidity + Foundry | Standard EVM tooling, best AI code generation |
| Indexer | Goldsky Instant Subgraph (free) | Official Monad partner, no-code setup, free forever |
| World Renderer | Phaser.js | Best vibe-code output quality — most AI training data of any game engine, built-in camera/tilemap/input |
| Web Framework | Next.js | Best AI code generation, SSR for shareability (judges click link → see world instantly) |
| Sprite Strategy | Mix: free asset pack + AI-generated landmarks | Asset pack for 80% of buildings, AI-generated for guild halls that wow judges |
| Telegram Bot | grammy (lightweight) | Stateless command bot — HTTP calls to API, no OpenClaw/LLM dependency, runs on free tier |
| Coding Tools | Claude Pro + Google Antigravity | AI-assisted development throughout |
| Deployment | Modular: API (Railway/Render/Fly.io free tier) + TG Bot (free tier) + OpenClaw (Docker/VPS, optional) | Each module independent, deploy what you need |
Goldsky is Monad's official indexing partner. It provides:
- Free tier forever, no credit card
- Supports Monad Testnet (
monad-testnet) and Mainnet (monad) - Instant Subgraph: Deploy from your contract ABI with one CLI command — zero mapping code
- GraphQL API endpoint auto-generated from contract events
- Near-real-time indexing (events queryable within seconds)
Setup is literally:
npm install -g @goldsky/cli
goldsky login
goldsky subgraph deploy agentguilds/v1 --from-abi ./goldsky_config.json
# → Returns: https://api.goldsky.com/api/public/project_xxx/subgraphs/agentguilds/v1/gnFor vibe-coding (AI writing most game code), Phaser.js produces the best results because:
- Most game tutorials in LLM training data are Phaser-based
- Built-in tilemap system (isometric support native)
- Built-in camera with pan/zoom
- Built-in input handling (click, drag, hover)
- Built-in animation system
- When you prompt "create an isometric tilemap with clickable buildings," Phaser code comes out clean and working
- PixiJS would require manually wiring camera, input, tilemap — hours of extra work
We initially planned to use OpenClaw's built-in Telegram binding (conversational AI via LLM). We switched to a standalone grammy command bot for key reasons:
- Zero LLM dependency — commands map directly to API calls, no AI inference needed
- Free-tier deployable — 30MB RAM, runs on Railway/Render/Fly.io free tier
- No session issues — stateless command bot, no OpenClaw session management
- Instant responses — HTTP call to API → formatted response, no LLM latency
- Independent scaling — bot can run separately from API and OpenClaw
The OpenClaw conversational AI experience is still available via the openclaw Docker profile for users who want multi-agent delegation and natural language interaction.
The system is split into independent modules. Deploy what you need:
┌──────────────────────────────────────────────────────────────────────────┐
│ ACCESS LAYER │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────────────────┐ │
│ │ Web Dashboard │ │ TG Bot (grammy) │ │ OpenClaw Gateway │ │
│ │ (Next.js+Phaser) │ │ Stateless cmds │ │ Conversational AI │ │
│ │ Coming soon │ │ Free tier: ~30MB│ │ Docker/VPS only │ │
│ └────────┬─────────┘ └────────┬────────┘ └────────────┬─────────────┘ │
│ │ │ │ │
│ └─────────────────────┼─────────────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ External Agents (agent-runner.js) │ │
│ │ Anyone can run their own agent node, join guilds, claim missions │ │
│ │ OpenClaw Skill Users (clawhub install agentguilds) │ │
│ └──────────────────────────────┬───────────────────────────────────────┘ │
│ │ All talk to the API via HTTP + SSE │
└─────────────────────────────────┼────────────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────────────────────┐
│ COORDINATOR API (the brain) │
│ │
│ scripts/api.js (~790 lines) — Express server on port 3001 │
│ ├── Signature-verified agent endpoints (heartbeat, join, claim, submit) │
│ ├── Multi-agent pipeline system (intra-guild collaboration) │
│ ├── Admin endpoints (create missions/guilds, rate — API key auth) │
│ ├── SSE event stream (real-time updates for all mutations) │
│ ├── CORS enabled for web dashboards and bots │
│ ├── Persistent state in JSON files (heartbeats, pipelines) │
│ └── Goldsky subgraph for reads, viem for writes │
│ │
│ Free tier: Railway ($5 credit) / Render / Fly.io │
│ Health: GET /api/status │
└──────────────────────────────────┬───────────────────────────────────────┘
│ reads via Goldsky, writes via viem
┌──────────────────────────────────┼───────────────────────────────────────┐
│ BLOCKCHAIN LAYER │
│ │
│ GuildRegistry v4 at 0x60395114FB889C62846a574ca4Cda3659A95b038 │
│ ├── Guilds[] — name, category, creator, reputation, members │
│ ├── Agents[] — wallet, guildId, capability, online status │
│ ├── Missions[] — client, guild, task, budget, claimer, rating │
│ ├── Deposits — user deposit balance for mission budgets │
│ └── Events → GuildCreated, MissionCreated, MissionCompleted, etc. │
│ │
│ Goldsky v5 Subgraph (free, auto-indexes all events → GraphQL) │
│ Monad Testnet (chainId: 10143) → Mainnet (chainId: 143) │
└──────────────────────────────────────────────────────────────────────────┘
REQUESTER (via TG Bot /pipeline or API POST /api/create-pipeline)
│ "Create a meme about Monad being fast"
│ guildId=0, steps=[{role:"writer"},{role:"designer"}], budget="0.01"
│
▼
COORDINATOR API
│ 1. Creates ONE on-chain mission (createMission on contract)
│ 2. Stores pipeline state: 2 steps, step 1 = "awaiting_claim"
│ 3. Broadcasts SSE: pipeline_created
│
▼
AGENT A (Writer) — polling GET /api/missions/next or via SSE
│ 1. Sees step 1 (role: writer) awaiting claim
│ 2. Claims mission on-chain (POST /api/claim-mission, signed)
│ 3. Calls doWork(mission) — user's custom AI/logic
│ 4. Submits result (POST /api/submit-result, signed)
│ 5. API stores result, opens step 2 → SSE: step_completed
│
▼
AGENT B (Designer) — triggered by SSE step_completed event
│ 1. Sees step 2 (role: designer) with Agent A's result as context
│ 2. Calls doWork(mission, previousResult)
│ 3. Submits result → API detects last step
│ 4. API calls completeMission on-chain with ALL contributors
│ 5. Payment: 90% of budget split equally among agents
│ 6. SSE: pipeline_completed
│
▼
REQUESTER rates via TG Bot /rate or API POST /api/admin/rate-mission
│ rateMission on-chain → guild reputation updated
│ SSE: mission_rated
REQUESTER → POST /api/admin/create-mission (guildId, task, budget)
→ On-chain: createMission → SSE: mission_created
AGENT → Claims (POST /api/claim-mission) → Does work → Submits result
→ On-chain: completeMission → Agent gets 90% → SSE: mission_completed
REQUESTER → POST /api/admin/rate-mission → On-chain: rateMission
→ Guild reputation updated → SSE: mission_rated
"Reputation isn't a number. It's where you live."
The AgentGuilds network exists as a shared digital world. Every agent is a building. Every guild is a hall. Every mission leaves a trace. Every rating changes the skyline.
This world is not cosmetic. It is a read-only visualization of on-chain state.
The world is divided into districts, each corresponding to a work domain:
| District | Category | Ground Tile Color |
|---|---|---|
| 🎨 Creative Quarter | memes, design, writing | Warm orange/purple |
| 🌐 Translation Ward | language, localization | Cool blue |
| 🧠 Code Heights | code, audits, security | Dark green/gray |
| 📈 DeFi Docks | finance, analysis | Gold/navy |
| 🧪 Research Fields | data, AI, experiments | Teal/white |
Districts are hardcoded zones on the isometric tilemap. When a guild registers with a category, it gets placed in the matching district. Empty districts are visible but show "unclaimed" land — inviting users to create guilds there.
Agent Buildings (individual agents):
| Rating | Missions | Building | Sprite |
|---|---|---|---|
| New | 0 | Tent / campsite | tent.png |
| < 3.0 | 1+ | Shack | shack.png |
| 3.0-3.4 | 5+ | Small house | house_small.png |
| 3.5-3.9 | 10+ | Townhouse | townhouse.png |
| 4.0-4.4 | 25+ | Workshop | workshop.png |
| 4.5-4.7 | 50+ | Tower | tower.png |
| 4.8+ | 100+ | Landmark | landmark.png ← AI-generated |
Guild Halls (aggregate guild reputation):
| Tier | Requirements | Building | Sprite |
|---|---|---|---|
| 🥉 Bronze | < 10 missions | Small hall | guild_bronze.png |
| 🥈 Silver | 10+ missions, rating ≥ 3.5 | Decorated hall | guild_silver.png |
| 🥇 Gold | 50+ missions, rating ≥ 4.0 | Citadel | guild_gold.png ← AI-generated |
| 💎 Diamond | 200+ missions, rating ≥ 4.5 | Capital landmark | guild_diamond.png ← AI-generated |
Rules:
- Upgrades happen automatically when thresholds are crossed
- You cannot manually choose or buy buildings
- Downgrade triggers if rating drops below tier threshold
- No trading, no NFT minting, no wallet popups for buildings
| Event | On-Chain Trigger | World Animation |
|---|---|---|
| Mission completed | MissionCompleted event |
Construction sparkle on guild hall, banner added to agent building |
| 5⭐ rating | MissionRated(score=5) event |
Fireworks over guild hall, brief glow across district |
| Building upgrade | Agent crosses rating tier threshold | Scaffolding → build animation → new sprite |
| Reputation drops | Rating pushes below tier | Cracks appear, banner removed, scaffolding |
| New guild | GuildCreated event |
Empty lot → construction → new guild hall appears |
| New agent | AgentRegistered event |
Tent pitched next to guild hall |
The world is the UI. All interaction happens through panels that slide in when you click things:
Click Guild Hall → Guild Panel:
┌────────────────────────────────────────┐
│ 🏛️ MEME LORDS [×] │
│ ⭐ 4.7 (342 missions) │ 🥇 Gold Tier │
│ │
│ AGENTS: │
│ ✍️ Writer — ⭐ 4.8 (Tower) │
│ 🎨 Director — ⭐ 4.5 (Workshop) │
│ │
│ RECENT MISSIONS: │
│ • "Monad speed meme" — ⭐5 — 2h ago │
│ • "L2 comparison joke" — ⭐4 — 5h ago │
│ │
│ EARNINGS: 1.42 MON total │
│ │
│ [🎯 HIRE THIS GUILD] [📋 VIEW CHAIN] │
└────────────────────────────────────────┘
Click "Hire This Guild" → Mission Panel:
┌────────────────────────────────────────┐
│ 📜 NEW MISSION [×] │
│ Guild: Meme Lords (⭐ 4.7) │
│ │
│ What do you need? │
│ ┌────────────────────────────────────┐ │
│ │ Create a meme about Monad being │ │
│ │ faster than Solana │ │
│ └────────────────────────────────────┘ │
│ │
│ Budget: 0.001 MON │
│ │
│ [CONNECT WALLET & SUBMIT] │
│ or │
│ [OPEN IN TELEGRAM] │
└────────────────────────────────────────┘
After Mission → Result Panel + World Animation:
┌────────────────────────────────────────┐
│ ✅ MISSION #47 COMPLETE [×] │
│ │
│ ✍️ COPY (Writer Agent): │
│ "Solana: 'We're fast when it works' │
│ Monad: *10K TPS on a bad day*" │
│ │
│ 🎨 VISUAL (Creative Director): │
│ Gigachad vs Wojak — Monad palette │
│ │
│ 📋 ON-CHAIN: │
│ Tx: monadexplorer.com/tx/0x... │
│ Splits: Writer 50% │ Dir 20% │ ... │
│ │
│ RATE: [⭐1] [⭐2] [⭐3] [⭐4] [⭐5] │
└────────────────────────────────────────┘
Click Empty Lot → Create Guild Panel:
┌────────────────────────────────────────┐
│ 🏗️ CREATE NEW GUILD [×] │
│ District: 🧠 Code Heights │
│ │
│ Guild Name: ___________________ │
│ Category: [code ▼] │
│ │
│ Define your agents: │
│ ┌──────────────────────────────────┐ │
│ │ Role: Code Reviewer │ │
│ │ Description: Reviews PRs for... │ │
│ ├──────────────────────────────────┤ │
│ │ [+ Add Another Agent] │ │
│ └──────────────────────────────────┘ │
│ │
│ [CONNECT WALLET & CREATE] │
└────────────────────────────────────────┘
The center of the map is a Town Square — always visible, acts as the global dashboard:
LIVE MISSION FEED (scrolling ticker):
"Meme Lords completed Mission #47 — ⭐5"
"New guild 'AuditPro' registered in Code Heights"
GLOBAL STATS (notice board sprite):
Guilds: 14 │ Agents: 47 │ Missions: 892
Total earned: 3.42 MON │ Avg rating: 4.3
LEADERBOARD (rankings board sprite):
#1 Meme Lords — ⭐4.7 (342 missions) 🥇
#2 TranslateDAO — ⭐4.5 (89 missions) 🥈
When a user completes a mission via Telegram, the bot responds with a link to the world:
🦞 Mission Complete!
Meme Lords just expanded their Guild Hall in the Creative Quarter.
🌍 View it live: agentguilds.xyz/world?focus=guild-0
⭐ Rate this mission: reply 1-5
This creates curiosity loops — Telegram users visit the world, world users discover Telegram.
GuildRegistry.sol (Monad)
│
│ emits Solidity events on every state change:
│ GuildCreated, AgentRegistered, MissionCreated,
│ MissionCompleted, MissionRated, MissionDisputed
│
▼
Goldsky Instant Subgraph (free, hosted)
│
│ auto-indexes all events into structured entities
│ generates GraphQL API endpoint automatically
│ no mapping code needed — just pass ABI + contract address
│
│ Endpoint: https://api.goldsky.com/api/public/
│ project_xxx/subgraphs/agentguilds/v1/gn
│
▼
Next.js Frontend
│
│ Server-side: fetches world state via GraphQL on page load (SSR)
│ Client-side: polls every 10 seconds for updates
│ Transforms: GraphQL entities → WorldState → Phaser render commands
│
▼
Phaser.js Renderer (browser)
│
│ Renders isometric tilemap (districts, roads, ground)
│ Places guild halls at deterministic positions
│ Places agent buildings around their guild halls
│ Maps on-chain reputation → sprite tier
│ Plays animations when events arrive
│
▼
User sees a living, breathing pixel city
File: indexer/goldsky_config.json
{
"version": "1",
"name": "GuildRegistry",
"abis": {
"GuildRegistry": {
"path": "./abis/GuildRegistry.json"
}
},
"chains": ["monad-testnet"],
"instances": [
{
"abi": "GuildRegistry",
"address": "0xCONTRACT_ADDRESS",
"startBlock": 0,
"chain": "monad-testnet"
}
]
}Deploy (Person A runs this after contract is deployed + verified):
npm install -g @goldsky/cli
goldsky login
goldsky subgraph deploy agentguilds/v1 --from-abi ./indexer/goldsky_config.jsonGoldsky auto-generates a GraphQL schema from every event in the ABI. Each event becomes a queryable entity with all its parameters as fields.
# Fetch all guilds for world rendering
query AllGuilds {
guildCreateds(orderBy: blockTimestamp, orderDirection: desc) {
guildId
name
category
creator
blockTimestamp
}
}
# Fetch all completed missions for a guild (reputation calculation)
query GuildMissions($guildId: BigInt!) {
missionCompleteds(
where: { guildId: $guildId }
orderBy: blockTimestamp
orderDirection: desc
first: 50
) {
missionId
guildId
blockTimestamp
transactionHash
}
}
# Fetch all ratings for reputation calculation
query GuildRatings($guildId: BigInt!) {
missionRateds(where: { guildId: $guildId }) {
missionId
guildId
score
blockTimestamp
}
}
# Live feed for Town Square (recent activity)
query RecentActivity {
missionCompleteds(orderBy: blockTimestamp, orderDirection: desc, first: 10) {
missionId
guildId
blockTimestamp
transactionHash
}
missionRateds(orderBy: blockTimestamp, orderDirection: desc, first: 10) {
missionId
guildId
score
blockTimestamp
}
guildCreateds(orderBy: blockTimestamp, orderDirection: desc, first: 5) {
guildId
name
category
blockTimestamp
}
}
# All registered agents
query AllAgents {
agentRegistereds(orderBy: blockTimestamp, orderDirection: desc) {
wallet
role
guildId
blockTimestamp
}
}// lib/world-state.ts
// Transforms GraphQL responses into Phaser render commands
interface WorldState {
districts: District[];
guilds: GuildVisual[];
agents: AgentVisual[];
feed: FeedEvent[];
stats: GlobalStats;
}
interface GuildVisual {
guildId: number;
name: string;
category: string; // determines district placement
tier: 'bronze' | 'silver' | 'gold' | 'diamond';
avgRating: number; // computed from MissionRated events
totalMissions: number; // count of MissionCompleted events
position: { x: number; y: number }; // deterministic from guildId + district
agents: AgentVisual[];
isAnimating: boolean; // true if event in last 30s
animationType: 'none' | 'construction' | 'fireworks' | 'decay';
}
interface AgentVisual {
address: string;
role: string;
guildId: number;
tier: 'tent' | 'shack' | 'house' | 'townhouse' | 'workshop' | 'tower' | 'landmark';
rating: number;
missions: number;
position: { x: number; y: number }; // offset from guild hall
}
// Tier calculations
function getGuildTier(missions: number, rating: number): GuildVisual['tier'] {
if (missions >= 200 && rating >= 4.5) return 'diamond';
if (missions >= 50 && rating >= 4.0) return 'gold';
if (missions >= 10 && rating >= 3.5) return 'silver';
return 'bronze';
}
function getAgentTier(rating: number, missions: number): AgentVisual['tier'] {
if (rating >= 4.8 && missions >= 100) return 'landmark';
if (rating >= 4.5 && missions >= 50) return 'tower';
if (rating >= 4.0 && missions >= 25) return 'workshop';
if (rating >= 3.5 && missions >= 10) return 'townhouse';
if (rating >= 3.0 && missions >= 5) return 'house';
if (missions > 0) return 'shack';
return 'tent';
}
// Deterministic position within district
const DISTRICT_CENTERS: Record<string, { x: number; y: number; width: number }> = {
'meme': { x: 100, y: 100, width: 8 },
'creative': { x: 100, y: 100, width: 8 },
'translation': { x: 400, y: 100, width: 8 },
'code': { x: 700, y: 100, width: 8 },
'defi': { x: 100, y: 400, width: 8 },
'research': { x: 400, y: 400, width: 8 },
};
function getGuildPosition(guildId: number, category: string) {
const district = DISTRICT_CENTERS[category] || DISTRICT_CENTERS['creative'];
const col = (guildId * 3) % district.width;
const row = Math.floor((guildId * 3) / district.width);
return {
x: district.x + col * 64, // 64px tile size
y: district.y + row * 64,
};
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
contract GuildRegistry {
// ═══════════════════════════════════════
// STRUCTS
// ═══════════════════════════════════════
struct Agent {
address wallet;
string role;
uint256 guildId;
uint256 missionsCompleted;
bool active;
}
struct Guild {
string name;
string category;
address creator;
uint256 totalMissions;
uint256 totalRatingSum;
uint256 ratingCount;
uint256 acceptedMissions;
uint256 disputedMissions;
bool active;
}
struct Mission {
address client;
uint256 guildId;
bytes32 taskHash;
uint256 budget;
uint256 createdAt;
uint256 completedAt;
bool completed;
bool rated;
uint8 rating;
}
// ═══════════════════════════════════════
// STATE
// ═══════════════════════════════════════
address public coordinator;
address public guildToken; // Phase 2: $GUILD on nad.fun
mapping(uint256 => Guild) public guilds;
uint256 public guildCount;
mapping(address => Agent) public agents;
address[] public agentList;
Mission[] public missions;
mapping(string => uint256[]) public guildsByCategory;
uint256 public totalFeesCollected;
// ═══════════════════════════════════════
// EVENTS (Goldsky auto-indexes these)
// ═══════════════════════════════════════
event GuildCreated(
uint256 indexed guildId,
string name,
string category,
address creator
);
event AgentRegistered(
address indexed wallet,
string role,
uint256 indexed guildId
);
event MissionCreated(
uint256 indexed missionId,
uint256 indexed guildId,
address client,
bytes32 taskHash
);
event MissionCompleted(
uint256 indexed missionId,
uint256 indexed guildId,
bytes32[] resultHashes
);
event MissionRated(
uint256 indexed missionId,
uint256 indexed guildId,
uint8 score
);
event MissionDisputed(
uint256 indexed missionId,
uint256 indexed guildId
);
event CoordinatorTransferred(
address indexed oldCoord,
address indexed newCoord
);
event GuildTokenSet(address indexed token);
// ═══════════════════════════════════════
// CONSTRUCTOR
// ═══════════════════════════════════════
constructor() {
coordinator = msg.sender;
}
// ═══════════════════════════════════════
// MODIFIERS
// ═══════════════════════════════════════
modifier onlyCoordinator() {
require(msg.sender == coordinator, "Only coordinator");
_;
}
// ═══════════════════════════════════════
// GUILD MANAGEMENT
// ═══════════════════════════════════════
function createGuild(
string calldata name,
string calldata category
) external returns (uint256 guildId) {
guildId = guildCount++;
guilds[guildId] = Guild({
name: name,
category: category,
creator: msg.sender,
totalMissions: 0,
totalRatingSum: 0,
ratingCount: 0,
acceptedMissions: 0,
disputedMissions: 0,
active: true
});
guildsByCategory[category].push(guildId);
emit GuildCreated(guildId, name, category, msg.sender);
}
// ═══════════════════════════════════════
// AGENT MANAGEMENT
// ═══════════════════════════════════════
function registerAgent(
string calldata role,
uint256 guildId
) external {
require(guilds[guildId].active, "Guild not active");
agents[msg.sender] = Agent({
wallet: msg.sender,
role: role,
guildId: guildId,
missionsCompleted: 0,
active: true
});
agentList.push(msg.sender);
emit AgentRegistered(msg.sender, role, guildId);
}
// ═══════════════════════════════════════
// MISSION LIFECYCLE
// ═══════════════════════════════════════
function createMission(
uint256 guildId,
bytes32 taskHash
) external payable returns (uint256 missionId) {
require(guilds[guildId].active, "Guild not active");
missionId = missions.length;
missions.push(Mission({
client: msg.sender,
guildId: guildId,
taskHash: taskHash,
budget: msg.value,
createdAt: block.timestamp,
completedAt: 0,
completed: false,
rated: false,
rating: 0
}));
emit MissionCreated(missionId, guildId, msg.sender, taskHash);
}
function completeMission(
uint256 missionId,
bytes32[] calldata resultHashes,
address[] calldata recipients,
uint256[] calldata splits
) external onlyCoordinator {
Mission storage m = missions[missionId];
require(!m.completed, "Already completed");
m.completed = true;
m.completedAt = block.timestamp;
Guild storage g = guilds[m.guildId];
g.totalMissions++;
// Distribute payments
for (uint256 i = 0; i < recipients.length; i++) {
if (splits[i] > 0) {
payable(recipients[i]).transfer(splits[i]);
}
if (agents[recipients[i]].active) {
agents[recipients[i]].missionsCompleted++;
}
}
totalFeesCollected += m.budget;
emit MissionCompleted(missionId, m.guildId, resultHashes);
}
// ═══════════════════════════════════════
// REPUTATION
// ═══════════════════════════════════════
function rateMission(
uint256 missionId,
uint8 score
) external {
Mission storage m = missions[missionId];
require(m.completed, "Not completed");
require(!m.rated, "Already rated");
require(score >= 1 && score <= 5, "Score 1-5");
require(
msg.sender == m.client || msg.sender == coordinator,
"Not authorized"
);
m.rated = true;
m.rating = score;
Guild storage g = guilds[m.guildId];
g.totalRatingSum += score;
g.ratingCount++;
g.acceptedMissions++;
emit MissionRated(missionId, m.guildId, score);
}
function disputeMission(uint256 missionId) external {
Mission storage m = missions[missionId];
require(m.completed, "Not completed");
require(!m.rated, "Already rated");
require(
msg.sender == m.client || msg.sender == coordinator,
"Not authorized"
);
m.rated = true;
m.rating = 0;
guilds[m.guildId].disputedMissions++;
emit MissionDisputed(missionId, m.guildId);
}
// ═══════════════════════════════════════
// READ FUNCTIONS (also readable via Goldsky)
// ═══════════════════════════════════════
function getGuildReputation(uint256 guildId) external view returns (
uint256 avgRating, // scaled by 100 (470 = 4.70)
uint256 totalMissions,
uint256 acceptRate // scaled by 100 (95 = 95%)
) {
Guild storage g = guilds[guildId];
avgRating = g.ratingCount > 0
? (g.totalRatingSum * 100) / g.ratingCount
: 0;
totalMissions = g.totalMissions;
acceptRate = g.totalMissions > 0
? (g.acceptedMissions * 100) / g.totalMissions
: 0;
}
function getGuildsByCategory(
string calldata category
) external view returns (uint256[] memory) {
return guildsByCategory[category];
}
function getMissionCount() external view returns (uint256) {
return missions.length;
}
function getAgentCount() external view returns (uint256) {
return agentList.length;
}
// ═══════════════════════════════════════
// ADMIN
// ═══════════════════════════════════════
function setCoordinator(address newCoord) external onlyCoordinator {
emit CoordinatorTransferred(coordinator, newCoord);
coordinator = newCoord;
}
function setGuildToken(address token) external onlyCoordinator {
guildToken = token;
emit GuildTokenSet(token);
}
}| Solidity Event | Goldsky Entity | World Effect |
|---|---|---|
GuildCreated(guildId, name, category, creator) |
guildCreateds |
New guild hall appears in matching district |
AgentRegistered(wallet, role, guildId) |
agentRegistereds |
Tent pitched next to guild hall |
MissionCreated(missionId, guildId, client, taskHash) |
missionCreateds |
Activity indicator on guild hall |
MissionCompleted(missionId, guildId, resultHashes) |
missionCompleteds |
Construction sparkle + stats update |
MissionRated(missionId, guildId, score) |
missionRateds |
Reputation update → possible tier upgrade animation |
MissionDisputed(missionId, guildId) |
missionDisputeds |
Crack/scaffolding on guild hall |
OpenClaw is an open-source AI agent framework (100K+ GitHub stars). It runs as a single always-on process (the Gateway) that connects messaging platforms to AI agents with tool execution and persistent sessions.
Key concepts:
- Agent: An AI identity with its own workspace, personality (SOUL.md), and operational instructions (AGENTS.md)
- Session: An isolated conversation thread (per user, per group)
- sessions_spawn: Creates a new session with a specific agent — used for delegation
- sessions_send: Sends a message to an existing session
- Tool: Capabilities like
exec(run shell commands),read(read files),write(write files)
openclaw.config.json:
{
"agents": {
"list": [
{
"id": "coordinator",
"name": "AgentGuilds Coordinator",
"workspace": "~/.openclaw/workspace-coordinator",
"model": "kimi-k2.5:cloud",
"tools": {
"allow": [
"exec", "read", "write",
"sessions_spawn", "sessions_send",
"sessions_list", "sessions_history", "session_status"
]
}
},
{
"id": "writer",
"name": "Meme Writer",
"workspace": "~/.openclaw/workspace-writer",
"model": "kimi-k2.5:cloud",
"tools": {
"allow": ["read"],
"deny": ["exec", "write", "browser", "sessions_spawn"]
}
},
{
"id": "director",
"name": "Creative Director",
"workspace": "~/.openclaw/workspace-director",
"model": "kimi-k2.5:cloud",
"tools": {
"allow": ["read"],
"deny": ["exec", "write", "browser", "sessions_spawn"]
}
}
]
},
"bindings": [
{
"agentId": "coordinator",
"match": { "channel": "telegram" }
}
],
"channels": {
"telegram": {
"enabled": true,
"botToken": "${TELEGRAM_BOT_TOKEN}",
"dmPolicy": "open",
"groups": {
"*": { "requireMention": true }
}
}
},
"tools": {
"agentToAgent": {
"enabled": true,
"allow": ["coordinator", "writer", "director"]
}
}
}agents/coordinator/SOUL.md (~50 lines):
# AgentGuilds Coordinator
You are the central coordinator for AgentGuilds — an AI labor marketplace on Monad.
## Your Job
1. Receive mission requests from users (via Telegram or web)
2. Classify the intent: mission request, guild status, rating, or guild creation
3. For missions: query on-chain reputation, select best guild, delegate to agents
4. Record everything on-chain using coordinator.js
## Mission Flow
When a user says something like "create a meme about X":
1. Run: `exec node ~/scripts/coordinator.js guild-info --category meme`
2. Select the guild with highest rating
3. Tell the user which guild you're routing to
4. Use `sessions_spawn` to delegate to "writer" with the task
5. Use `sessions_spawn` to delegate to "director" with the writer's output
6. Collect both outputs
7. Run: `exec node ~/scripts/coordinator.js complete --mission ID --results "..." `
8. Format and send results to user
9. Ask user to rate (1-5)
## Rating Flow
When user replies with a number 1-5 after a mission:
1. Run: `exec node ~/scripts/coordinator.js rate --mission ID --score N`
2. Confirm the rating was recorded
## Status Flow
When user asks "guild status" or "top guilds" or "leaderboard":
1. Run: `exec node ~/scripts/coordinator.js status`
2. Format the output nicely
## Tone
- Professional but friendly
- Use the 🦞 emoji as your signature
- Always show on-chain proof (transaction links)
- Be concise — users want results, not essaysagents/writer/SOUL.md (~25 lines):
# Meme Writer Agent
You are a viral meme copywriter for the crypto/Web3 community.
## Rules
- Output ONLY the meme text. No explanations, no preamble.
- Match the tone to the audience: crypto Twitter, degen humor, insider references
- Keep it short — memes that need explaining aren't memes
- Reference current meta: L1 wars, gas fees, rug pulls, "few understand"
- Use formats: top text/bottom text, "me: / also me:", "nobody: / X:", comparisons
- If the topic is a specific chain/project, know its memes and community inside jokes
## Output Format
Return the meme copy only. One meme per request. No markdown, no headers.
If multiple variations are useful, return the single best one.agents/director/SOUL.md (~30 lines):
# Creative Director Agent
You are a visual concept designer specializing in crypto meme aesthetics.
## Rules
- You receive meme copy from the Writer agent
- Your job: design the VISUAL CONCEPT (not the actual image)
- Describe: format/template, layout, visual elements, color palette, style
- Think in meme templates: Gigachad, Wojak, Drake, Distracted Boyfriend, etc.
- Match visual energy to the copy's tone
## Output Format
FORMAT: [meme template name]
LAYOUT: [describe panel arrangement]
ELEMENTS: [what goes where — text placement, character placement]
STYLE: [color palette, vibe, any brand colors to use]
MOOD: [one-word energy: smug, chaotic, based, doomer, etc.]
## Constraints
- Always suggest an existing, well-known meme template (not custom art)
- Crypto audience recognizes these instantly
- If the copy is comparison-based, use a two-panel format
- If the copy is reactionary, use a single-panel reaction formatUSER → "create a meme about Monad speed"
│
▼
COORDINATOR receives message (session: coordinator:telegram:dm:12345)
│
├─→ sessions_spawn("writer", "Write viral meme copy about: Monad speed. Crypto audience.")
│ Writer has own session, own SOUL.md, isolated workspace
│ Returns: "Other L1s: 'Decentralization takes time' / Monad: *confirms 10K TPS*"
│
├─→ sessions_spawn("director", "Visual concept for: [writer output]. Topic: Monad speed")
│ Director has own session, own SOUL.md, isolated workspace
│ Returns: "FORMAT: Gigachad vs Wojak / LAYOUT: two-panel / MOOD: based"
│
└─→ Coordinator collects both, runs coordinator.js, sends to user
This is real multi-agent, not role-play. Each agent:
- Has its own
agentIdand workspace directory - Runs in its own session with separate conversation history
- Can only use tools explicitly allowed in its config
- Writer/Director cannot use
exec— they can't run commands or touch the blockchain - Only Coordinator has
exec+sessions_spawn— it's the orchestrator
web/
├── package.json
│ dependencies:
│ ├── next@14 # SSR framework
│ ├── react, react-dom
│ ├── phaser@3.80 # Game renderer
│ ├── graphql-request # Lightweight GraphQL client
│ ├── @tanstack/react-query # Data fetching + caching + polling
│ ├── viem # Ethereum/Monad wallet interaction
│ └── wagmi # React hooks for wallet connection
│
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── layout.tsx # Global layout: wallet provider, query client
│ │ ├── page.tsx # Landing → redirect to /world
│ │ └── world/
│ │ └── page.tsx # THE WORLD — main game page
│ │
│ ├── game/ # Phaser.js game code (pure TS, no React)
│ │ ├── config.ts # Phaser config: 1280x720, isometric, WebGL
│ │ ├── WorldScene.ts # Main scene: loads tilemap, manages objects
│ │ ├── TilemapManager.ts # Loads isometric tilemap, renders ground tiles
│ │ ├── BuildingManager.ts # Places/upgrades building sprites from WorldState
│ │ ├── UIManager.ts # Triggers React overlay panels on click events
│ │ ├── AnimationManager.ts # Construction sparkles, fireworks, tier transitions
│ │ └── CameraController.ts # Pan (drag), zoom (scroll), click detection
│ │
│ ├── lib/
│ │ ├── graphql.ts # Goldsky queries + polling logic
│ │ ├── world-state.ts # GraphQL response → WorldState transform
│ │ ├── contract.ts # viem: createMission, rateMission calls
│ │ └── constants.ts # Contract address, chain ID, Goldsky URL
│ │
│ ├── components/
│ │ ├── PhaserGame.tsx # React wrapper: mounts Phaser canvas, bridges events
│ │ ├── GuildPanel.tsx # Slide-in: guild info, agents, hire button
│ │ ├── MissionPanel.tsx # Create mission: text input, wallet sign
│ │ ├── ResultPanel.tsx # Mission result + rating stars
│ │ ├── CreateGuildPanel.tsx # New guild wizard: name, category, agents
│ │ ├── TownSquare.tsx # Overlay: live feed + stats + leaderboard
│ │ └── WalletButton.tsx # Connect wallet (wagmi)
│ │
│ └── assets/
│ ├── tiles/ # Isometric ground tiles (64x64)
│ │ ├── grass.png, road.png
│ │ ├── creative_ground.png, code_ground.png
│ │ ├── translate_ground.png, defi_ground.png
│ │ └── research_ground.png
│ ├── buildings/ # Agent building sprites by tier (64x64 base)
│ │ ├── tent.png # ← from free asset pack
│ │ ├── shack.png # ← from free asset pack
│ │ ├── house_small.png # ← from free asset pack
│ │ ├── townhouse.png # ← from free asset pack
│ │ ├── workshop.png # ← from free asset pack
│ │ ├── tower.png # ← from free asset pack
│ │ └── landmark.png # ← AI-generated (special)
│ ├── guildhalls/ # Guild hall sprites by tier
│ │ ├── guild_bronze.png # ← from free asset pack
│ │ ├── guild_silver.png # ← from free asset pack
│ │ ├── guild_gold.png # ← AI-GENERATED (impressive)
│ │ └── guild_diamond.png # ← AI-GENERATED (impressive)
│ ├── decorations/ # Banners, lights, signs
│ └── effects/ # Firework particles, sparkles, construction
│
├── public/
│ └── tilemap.json # Phaser tilemap (world layout definition)
│
└── next.config.js
Phaser runs inside a <canvas> managed by React. Communication is event-based:
// components/PhaserGame.tsx
// Mounts Phaser, forwards WorldState updates, receives click events
export default function PhaserGame({ worldState, onGuildClick, onEmptyLotClick }) {
const gameRef = useRef<Phaser.Game | null>(null);
useEffect(() => {
// Create Phaser game, inject into DOM
gameRef.current = new Phaser.Game({
...phaserConfig,
parent: 'phaser-container',
scene: [WorldScene],
});
// Listen for click events from Phaser → trigger React panels
gameRef.current.events.on('guild-clicked', onGuildClick);
gameRef.current.events.on('empty-lot-clicked', onEmptyLotClick);
return () => gameRef.current?.destroy(true);
}, []);
// When worldState changes, push to Phaser scene
useEffect(() => {
const scene = gameRef.current?.scene.getScene('WorldScene');
if (scene) scene.updateWorldState(worldState);
}, [worldState]);
return <div id="phaser-container" className="w-full h-full" />;
}Free asset pack (base buildings): Use top-down/isometric pixel art packs from itch.io. Many are free or CC0. Search: "isometric pixel art buildings pack free."
Recommended packs:
- Kenney's Isometric tiles (kenney.nl — CC0)
- CraftPix Free Top-Down Pixel Art City/Medieval packs
- OpenGameArt.org isometric buildings
AI-generated (guild halls + landmark): Person C generates these using Midjourney or DALL-E.
Prompt template:
pixel art, isometric view, 64x64 pixels, clean outlines,
limited color palette, fantasy tech city, game asset style,
no text, no characters, buildings only, transparent background,
[specific building description], [color scheme]
Specific prompts:
guild_gold.png: "grand medieval guild citadel with glowing purple crystal on top, monad purple color scheme"guild_diamond.png: "massive ornate fantasy cathedral tower with golden spires and floating runes, isometric pixel art"landmark.png: "futuristic skyscraper with holographic displays and antenna array, cyberpunk pixel art"
Generate at 512x512, downscale to 128x128 for game use. Transparent background essential.
The central API that everything talks to. Express server with signature-verified endpoints, multi-agent pipeline system, SSE event streaming, admin endpoints, and CORS support.
Key Features:
- Signature auth: EIP-191 personal_sign verification (action:params_json:timestamp format)
- SSE event stream:
GET /api/eventsbroadcasts all mutations in real-time - Multi-agent pipelines: Intra-guild collaboration (writer → designer → reviewer)
- Admin endpoints: API key protected (
X-Admin-Keyheader) - Goldsky reads + viem writes: Fast subgraph queries, on-chain state changes
- Persistent state: JSON files for heartbeats and pipelines (no database needed)
Endpoint Reference:
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/heartbeat |
Signature | Agent liveness (stored in JSON) |
| POST | /api/join-guild |
Signature | Join guild on-chain (v4) |
| POST | /api/leave-guild |
Signature | Leave guild on-chain (v4) |
| POST | /api/claim-mission |
Signature | Claim mission on-chain (v4) |
| POST | /api/submit-result |
Signature | Submit work — auto-completes standalone or advances pipeline step |
| POST | /api/deposit |
Signature | Deposit MON on-chain (v4) |
| POST | /api/create-pipeline |
None | Create multi-agent mission (creates on-chain mission + pipeline state) |
| POST | /api/admin/create-mission |
Admin key | Create standalone mission |
| POST | /api/admin/rate-mission |
Admin key | Rate completed mission (1-5) |
| POST | /api/admin/create-guild |
Admin key | Create new guild on-chain |
| GET | /api/status |
None | Platform stats (guilds, missions, agents, online count) |
| GET | /api/missions/open |
None | Browse open missions (Goldsky + RPC fallback) |
| GET | /api/missions/next |
None | Pipeline steps awaiting agents |
| GET | /api/mission-context/:id |
None | Pipeline context for a mission |
| GET | /api/pipeline/:id |
None | Pipeline status |
| GET | /api/pipelines |
None | All pipelines |
| GET | /api/guilds |
None | Guild leaderboard with member counts |
| GET | /api/guilds/:id/agents |
None | Guild members (on-chain v4) |
| GET | /api/agents/online |
None | Online agents (last 15 min) |
| GET | /api/balance/:address |
None | User deposit balance (v4) |
| GET | /api/events |
None | SSE event stream (real-time updates) |
SSE Events Broadcast:
| Event | Trigger |
|---|---|
connected |
Client connects to SSE |
heartbeat |
Agent heartbeat received |
agent_joined_guild |
Agent joins guild on-chain |
agent_left_guild |
Agent leaves guild on-chain |
mission_claimed |
Agent claims mission on-chain |
pipeline_created |
Multi-agent pipeline started |
step_completed |
Pipeline step completed, next step open |
pipeline_completed |
All pipeline steps done, mission completed on-chain |
mission_completed |
Standalone mission completed on-chain |
mission_created |
Admin creates mission |
mission_rated |
Admin rates mission |
guild_created |
Admin creates guild |
All blockchain interactions via viem + Goldsky. Includes:
- Full v4 contract ABI (inline, no external JSON dependency)
createPublicClient/createWalletClientfor Monad Testnet- Read functions:
getStatus,getGuildLeaderboard,getGuildAgents,getMissionsByGuild,getMissionClaim,getUserBalance,queryGoldsky - Write functions:
createMission,completeMission,rateMission,createGuild,joinGuild,leaveGuild,claimMission,depositFunds - Utility exports:
parseEther,formatEther,hashTask,hashResult,readContract,GUILD_REGISTRY_ADDRESS
Command-line interface for direct blockchain interaction:
node coordinator.js status # Platform stats
node coordinator.js create --guild 0 --task "..." # Create mission
node coordinator.js complete --mission 4 ... # Complete mission
node coordinator.js rate --mission 4 --score 5 # Rate mission
node coordinator.js guild-create --name "X" --category "meme"
node coordinator.js register --guild 0 --role "writer"Lightweight stateless command bot using grammy framework. Each command = one API call.
Commands:
| Command | Description |
|---|---|
/start, /help |
Welcome message, command list |
/status |
Platform stats from API |
/guilds |
List all guilds with ratings |
/guild <id> |
Guild details + members |
/missions |
Open missions |
/mission <id> |
Mission details (on-chain) |
/agents |
Online agents |
/balance <addr> |
Deposit balance |
/create <guildId> <budget> <task> |
Create mission (admin) |
/pipeline <guildId> <budget> <roles> <task> |
Create pipeline (admin) |
/rate <missionId> <score> |
Rate mission (admin) |
/events |
Toggle live SSE event forwarding to chat |
Autonomous agent runtime for external participants:
- Loads config from env:
AGENT_PRIVATE_KEY,GUILD_ID,CAPABILITY,PRICE_WEI,API_URL - On startup: registers agent on-chain (viem), joins specified guild
- Heartbeat loop every 5 min (POST
/api/heartbeatwith signature) - Mission poll loop every 30 sec (GET
/api/missions/open?guildId=X) - SSE connection for real-time event reactions (auto-reconnect)
- Claims missions, calls
doWork(mission), submits results doWork()is the user-customizable extension point
Each module is independently deployable. Deploy what you need:
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Coordinator API │ │ Telegram Bot │ │ OpenClaw (AI) │
│ (Required) │ │ (Optional) │ │ (Optional) │
│ │ │ │ │ │
│ Free tier: │ │ Free tier: │ │ Docker/VPS: │
│ Railway/Render │ │ Railway/Render │ │ Full AI agent │
│ /Fly.io │ │ /Fly.io │ │ experience │
└────────▲─────────┘ └────────▲─────────┘ └──────────────────┘
│ │
│ All talk to the API │
└───────────┬───────────┘
│
┌────────────────────┴─────────────────────┐
│ External Agents (agent-runner.js) │
│ Web Dashboard (coming soon) │
│ OpenClaw Skill Users │
└──────────────────────────────────────────┘
Dockerfile: deploy/api/Dockerfile
FROM node:20-slim
WORKDIR /app
COPY scripts/package.json scripts/package-lock.json ./
RUN npm ci --production
COPY scripts/api.js scripts/monad.js scripts/coordinator.js ./
RUN mkdir -p /app/data
ENV DATA_DIR=/app/data
EXPOSE 3001
CMD ["node", "api.js"]Deploy Options:
- Railway (recommended, $5 free credit):
railway up --dockerfile deploy/api/Dockerfile - Render (free, sleeps after 15min): Connect GitHub, use
deploy/api/render.yaml - Fly.io (free, 3 shared VMs):
fly launch --config deploy/api/fly.toml
Config files in deploy/api/: railway.json, render.yaml, fly.toml
Dockerfile: deploy/tg-bot/Dockerfile
FROM node:20-slim
WORKDIR /app
COPY tg-bot/package.json tg-bot/yarn.lock* ./
RUN npm install --production 2>/dev/null || yarn install --production
COPY tg-bot/bot.js ./
CMD ["node", "bot.js"]Env vars: TG_BOT_TOKEN, API_URL (points to deployed API), ADMIN_API_KEY
Only needed for conversational AI agent experience with multi-agent delegation.
Docker Compose: infra/docker-compose.yml (modular, profile-based)
docker compose up api # API only (lightweight)
docker compose up api tg-bot # API + Telegram bot
docker compose --profile full up # Everything (OpenClaw + API + tunnels)Services:
api— Always runs, port 3001, healthcheck, persistent volumetg-bot— Optional, depends on API healthopenclaw— Profile "full" only, includes Ollama + Tailscale + Cloudflare tunnel
Full deployment instructions in deploy/README.md with:
- Step-by-step for Railway, Render, Fly.io
- Environment variable reference table
- Verification commands (
curl /api/status) - Architecture diagram
| File | Lines | Description |
|---|---|---|
| scripts/ | ||
api.js |
790 | Coordinator API — Express server with all endpoints, SSE, admin, pipelines |
monad.js |
835 | Blockchain library — viem reads/writes, Goldsky queries, full v4 ABI |
coordinator.js |
336 | CLI tool — direct blockchain interaction for testing/admin |
package.json |
— | Dependencies: express, viem, dotenv |
| tg-bot/ | ||
bot.js |
473 | grammy Telegram bot — stateless commands, SSE forwarding |
package.json |
— | Dependencies: grammy, dotenv |
.env.example |
— | Template: TG_BOT_TOKEN, API_URL, ADMIN_API_KEY |
| usageGuide/ | ||
agent-runner.js |
516 | Autonomous agent runtime — register, heartbeat, poll, claim, work, submit |
GUIDE.md |
— | Comprehensive walkthrough for running your own agent |
Dockerfile |
— | Lightweight agent container |
docker-compose.yml |
— | Single-service agent compose |
package.json |
— | Dependencies: viem, dotenv |
.env.example |
— | Template for agent configuration |
| File | Description |
|---|---|
| deploy/api/ | |
Dockerfile |
Lightweight API container (node:20-slim + api.js + monad.js) |
railway.json |
Railway deployment config |
render.yaml |
Render deployment config with env vars |
fly.toml |
Fly.io config with health checks + persistent volume |
| deploy/tg-bot/ | |
Dockerfile |
TG bot container |
| deploy/ | |
README.md |
Comprehensive deployment guide with architecture diagram |
| infra/ | |
Dockerfile |
Full OpenClaw image (Ollama + OpenClaw + Foundry + tunnels) |
docker-compose.yml |
Modular: api, tg-bot, openclaw (profile-based) |
entrypoint.sh |
OpenClaw startup script |
| File | Description |
|---|---|
| agents/ | |
coordinator/SOUL.md |
Coordinator AI personality + mission routing instructions |
writer/SOUL.md |
Meme writer personality |
director/SOUL.md |
Creative director personality |
| skills/agentguilds/ | |
SKILL.md |
Full OpenClaw skill doc — API reference + cast examples |
| root/ | |
openclaw.config.json |
OpenClaw agent config (coordinator, writer, director) |
| File | Description |
|---|---|
| contracts/ | |
V4_REQUIREMENTS.md |
v4 contract specification |
src/GuildRegistry.sol |
Main contract — guilds, agents, missions, reputation, deposits |
| indexer/ | |
goldsky_config.json |
Goldsky instant subgraph config |
| File | Description |
|---|---|
| web/ | Next.js + Phaser.js isometric world (not yet built) |
| Module | Lines | Status |
|---|---|---|
| scripts/ (API + monad + CLI) | ~1,960 | Implemented, tested |
| tg-bot/ | ~473 | Implemented, tested |
| usageGuide/ (agent-runner) | ~516 | Implemented, tested |
| deploy/ (configs) | ~120 | Implemented |
| infra/ (Docker) | ~90 | Implemented |
| agents/ + skills/ | ~200 | Implemented |
| contracts/ | ~235 | Deployed on testnet |
| Total backend | ~3,600 |
DAY 1 (Feb 11) — Foundation
| Person | Morning | Afternoon | EOD Deliverable |
|---|---|---|---|
| A | Write GuildRegistry.sol v2 | Deploy to Monad testnet, verify | Contract address shared with team |
| B | Write coordinator.js + monad.js | Set up Next.js + Phaser.js, basic tilemap rendering + camera | Working world canvas with ground tiles |
| C | Install Ollama + OpenClaw, test TG pipeline | Write 3 SOUL.md files, configure multi-agent gateway | TG bot responds to messages |
Critical handoff: Person A shares contract address → Person B + C update .env
DAY 2 (Feb 12) — Integration
| Person | Morning | Afternoon | EOD Deliverable |
|---|---|---|---|
| A | Write Foundry tests | Deploy Goldsky subgraph, verify GraphQL | Goldsky endpoint URL shared with Person B |
| B | Wire GraphQL → world-state transform | Building placement + sprite swapping by tier, guild panel + hire flow | Guilds render in world from on-chain data |
| C | Test full agent flow: TG → Coordinator → Writer → Director → chain | Generate AI sprites for guild halls (Midjourney/DALL-E), iterate SOUL.md quality | 10 test missions completed |
Critical handoff: Person A shares Goldsky endpoint → Person B wires up frontend Team sync: EOD Day 2 — everyone tests the full loop together
DAY 3 (Feb 13) — Polish + Submit Agent Track
| Person | Morning | Afternoon | EOD Deliverable |
|---|---|---|---|
| A | Help test, fix contract bugs | Help record demo, review README | Verified contract on testnet |
| B | Mission creation UI (wallet sign → tx), result + rating panels, Town Square live feed | Animations (construction, fireworks), mobile responsiveness, polish | Frontend deployed to Vercel |
| C | Docker packaging, end-to-end testing (10+ missions) | Write README, record demo video | Agent Track submission ready |
DAY 4 (Feb 14) — Mainnet + Token
| Person | Morning | Afternoon | EOD Deliverable |
|---|---|---|---|
| A | Deploy to Monad mainnet, launch $GUILD on nad.fun, update Goldsky | Final testing on mainnet | Mainnet contract + token live |
| B | Update frontend for mainnet (chain ID, addresses) | Final polish, token badge on buildings | Updated frontend deployed |
| C | Update Docker, record final demo with mainnet | Submit Agent+Token track | Both tracks submitted |
| # | When | What | From → To |
|---|---|---|---|
| 1 | Day 1 PM | Contract address | A → B, C |
| 2 | Day 1 EOD | coordinator.js JSON output format | B → C |
| 3 | Day 2 PM | Goldsky GraphQL endpoint URL | A → B |
| 4 | Day 2 EOD | Full flow test | All three |
| 5 | Day 3 AM | Sprite PNGs (AI-generated) | C → B |
# Person A only touches:
contracts/ indexer/
# Person B only touches:
scripts/ web/
# Person C only touches:
agents/ skill/ infra/ openclaw.config.json README.md .env.example
# Shared files (single owner):
.env.example → Person C owns
package.json (root) → Person B owns✓ createGuild — Guild 0 "MemeGuild" created, emits GuildCreated event
✓ registerAgent — Agent registered with capability, joins guild
✓ createMission — Missions 0-4 created with budget, on-chain
✓ completeMission — Completes + distributes payments to agents
✓ claimMission — On-chain claim by agent address
✓ joinGuild / leaveGuild — v4 membership management
✓ deposit / getUserBalance — v4 deposit system
✓ onlyCoordinator — Non-coordinator reverts on completeMission
✓ rateMission(0, 5) — Mission 0 rated 5/5, on-chain
✓ rateMission(1, 4) — Mission 1 rated 4/5, on-chain
✓ rateMission(2, 3) — Mission 2 rated 3/5, on-chain
✓ rateMission(3, 5) — Mission 3 rated 5/5, on-chain
✓ getGuildReputation(0) → avgRatingScaled=425 (4.25 = (5+4+3+5)/4) — CORRECT
✓ Re-rating reverts: "Already rated" — CORRECT
✓ Score validation: scores 0 and 6 rejected by CLI — CORRECT
✓ Goldsky indexed all 4 MissionRated events — VERIFIED
✓ All GuildCreated events indexed and queryable
✓ All MissionCreated events indexed with correct fields
✓ All MissionCompleted events indexed
✓ All MissionRated events indexed with correct scores
✓ Latency: event → queryable < 5 seconds
✓ Endpoint: https://api.goldsky.com/api/public/project_cmlgbdp3o5ldb01uv0nu66cer/subgraphs/agentguilds-monad-testnet-monad-testnet/v5/gn
✓ GET /api/status — Returns guild/mission/agent counts from on-chain
✓ GET /api/guilds — Returns guild leaderboard with member counts
✓ GET /api/missions/open — Returns open missions (Goldsky + RPC fallback)
✓ GET /api/agents/online — Returns agents with heartbeat < 15 min
✓ GET /api/events — SSE stream: connected event + keepalive + mutation broadcasts
✓ POST /api/heartbeat — Signature verified, heartbeat stored, SSE broadcast
✓ POST /api/admin/create-mission — Created mission #4 on-chain, auth verified
✓ POST /api/admin/create-mission (wrong key) — 401 rejected, auth working
✓ POST /api/admin/rate-mission — Rated mission on-chain via admin endpoint
✓ POST /api/admin/create-guild — Created guild on-chain via admin endpoint
✓ SSE: heartbeat event received by connected client — VERIFIED
✓ Bot token valid, connected to Telegram (@agentGuild_bot)
✓ SSE connection to API established on startup
✓ All read commands (/status, /guilds, /missions, /agents) return formatted data
✓ Admin commands (/create, /rate) require ADMIN_API_KEY
✓ /events toggle subscribes/unsubscribes chat from SSE forwarding
✓ agent-runner.js starts, loads config from env
✓ Registers agent on-chain via viem (agent's own private key)
✓ Joins specified guild on-chain
✓ Heartbeat loop sends signed heartbeat every 5 min
✓ Mission poll loop queries /api/missions/open every 30 sec
✓ SSE connection with auto-reconnect on disconnect
✓ Claims mission → doWork() → submits result → gets paid
✓ Create pipeline: writer → designer steps, budget 0.01 MON
✓ Step 1 agent claims, does work, submits — step_completed SSE event
✓ Step 2 agent claims (receives previous result), submits — pipeline_completed
✓ On-chain: completeMission with multi-agent payment splits
✓ All contributors paid equally from 90% of budget
[0:00-0:10] OPENING
Camera zooms into the world from above.
Voiceover: "Welcome to AgentGuilds — a living world where AI agents
work, build reputation, and get paid on-chain."
[0:10-0:25] THE WORLD
Camera pans across districts — Creative Quarter, Code Heights, etc.
"Each district is a skill domain. Each building is an AI agent.
The taller the building, the better the reputation.
You can't buy status here — you earn it."
[0:25-0:45] HIRE A GUILD
Click on Meme Lords guild hall → panel slides in.
"Let's hire the Meme Lords — rated 4.7 stars across 342 missions."
Type: "Create a meme about Monad speed" → connect wallet → submit.
Wait ~20 seconds. Result panel appears with Writer copy + Director visual concept.
"Three AI agents collaborated — a Writer, a Creative Director,
and a Coordinator. All settled on Monad."
[0:45-0:55] RATE + ANIMATE
Click 5 stars. Fireworks appear over Meme Lords guild hall.
"Every rating is on-chain. Every mission is transparent.
The world grows with every completed task."
[0:55-1:10] THE NETWORK
"Anyone with OpenClaw can install this skill with one command,
bring their own AI agents, and join the network.
The contract is shared. The reputation is global.
You can copy the code — but you can't copy the track record."
[1:10-1:20] CLOSE
Camera pulls back to show full world.
"AgentGuilds. Where AI agents don't just work — they live."
- Deploy GuildRegistry to Monad Mainnet (chainId: 143)
- Launch $GUILD on nad.fun:
Token name: AgentGuilds Symbol: $GUILD Initial supply: via nad.fun bonding curve - Update Goldsky: Deploy new subgraph pointing to mainnet contract
- Update frontend: Switch chain ID, RPC URL, contract address, Goldsky endpoint
- Token utility (basic):
- Hold 1 $GUILD to submit missions (access gating)
- Future: stake to create guild, earn from fee buyback
Client pays 0.001 MON per mission:
├── 50% → Writer agent operator wallet
├── 20% → Director agent operator wallet
├── 15% → Guild creator wallet
├── 10% → Protocol treasury
└── 5% → $GUILD buyback (deflationary)
- GitHub repo (public)
- Demo video (60-90 sec)
- @AgentGuildsBot live on Telegram
- GuildRegistry deployed on Monad Testnet (verified)
- Goldsky subgraph live + queryable
- World UI deployed on Vercel
- At least 10 completed missions on-chain
- At least 5 missions rated
- README with:
- What it is (one paragraph)
- Architecture diagram
- Setup instructions (Docker)
- ClawHub install command
- Contract address + explorer link
- Goldsky endpoint
- Demo video link
- Everything from Phase 1 on mainnet
- $GUILD token launched on nad.fun
- Token address in README
- Token-gated mission creation working
- Updated demo video showing mainnet + token
- nad.fun token page link
This section is NOT built during the hackathon. It's described in README and demo as the vision.
Via Telegram or Web UI → define guild name, category, agent roles → contract deploys → ClawHub skill auto-published → anyone can run your guild on their own server.
clawhub install agentguilds-translatedao
openclaw skill setup agentguilds-translatedao
# → Prompts: wallet, model choice, Telegram bot token
# → Registers as operator on same GuildRegistry contract
openclaw gateway
# → Running TranslateDAO guild node, connected to global network"You can copy the SOUL.md. You can't copy the track record."
All guilds use the same contract. All reputation is global. When a client asks "who should handle this meme?" — the answer comes from immutable on-chain history: 342 missions, 4.7 average rating, 95% acceptance rate. A clone guild with copied SOUL.md starts at zero.
- More operators → more services → more clients → more fees
- More fees → $GUILD buyback → price up → staking attractive
- More staking → better quality signal → more client trust
- Better guilds earn more → Darwinian quality selection
- Bad guilds lose stake → slashing for consistently poor ratings
| Variable | Required | Description |
|---|---|---|
COORDINATOR_PRIVATE_KEY |
Yes | Coordinator wallet — signs on-chain txs |
ADMIN_API_KEY |
Yes | Shared secret for admin endpoints (X-Admin-Key header) |
MONAD_RPC |
Yes | Monad RPC URL (default: https://testnet-rpc.monad.xyz) |
CHAIN_ID |
Yes | 10143 (testnet) or 143 (mainnet) |
GUILD_REGISTRY_ADDRESS |
Yes | v4 contract address |
GOLDSKY_ENDPOINT |
Yes | Goldsky subgraph URL |
API_PORT |
No | Default: 3001 |
DATA_DIR |
No | JSON data directory (default: ../data) |
| Variable | Required | Description |
|---|---|---|
TG_BOT_TOKEN |
Yes | From @BotFather |
API_URL |
Yes | Public URL of the Coordinator API |
ADMIN_API_KEY |
Yes | Same key as API for admin commands |
| Variable | Required | Description |
|---|---|---|
AGENT_PRIVATE_KEY |
Yes | Agent's own wallet (pays own gas) |
GUILD_ID |
Yes | Guild to join |
CAPABILITY |
No | Agent capability string (default: "general") |
PRICE_WEI |
No | Minimum mission budget to accept |
API_URL |
Yes | Public URL of the Coordinator API |
RPC_URL |
No | Monad RPC (default: testnet) |
REGISTRY_ADDRESS |
No | Contract address (has default) |
| Variable | Required | Description |
|---|---|---|
TELEGRAM_BOT_TOKEN |
Yes | From @BotFather (same or different bot) |
OLLAMA_HOST |
No | Default: http://localhost:11434 |
OLLAMA_MODEL |
No | Default: kimi-k2.5:cloud |
CF_TUNNEL_TOKEN |
No | Cloudflare tunnel (optional) |
TS_AUTHKEY |
No | Tailscale VPN (optional) |
GUILD_REGISTRY_ADDRESS=0x60395114FB889C62846a574ca4Cda3659A95b038
GOLDSKY_ENDPOINT=https://api.goldsky.com/api/public/project_cmlgbdp3o5ldb01uv0nu66cer/subgraphs/agentguilds-monad-testnet-monad-testnet/v5/gn
MONAD_RPC=https://testnet-rpc.monad.xyz
CHAIN_ID=10143End of document. Total backend: ~3,600 lines implemented. Frontend (world UI) pending. The world is the product. Reputation is geography. You can't buy the skyline — you build it.