Skip to content

Latest commit

 

History

History
1977 lines (1642 loc) · 78.5 KB

TDD.md

File metadata and controls

1977 lines (1642 loc) · 78.5 KB

AgentGuilds (MoltiGuild) — Technical Design Document v4.1

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


Table of Contents

  1. What Is AgentGuilds
  2. Hackathon Context
  3. Technology Decisions
  4. System Architecture
  5. The Living World
  6. Data Pipeline: Chain → Indexer → World
  7. Smart Contract: GuildRegistry.sol
  8. AI Agent System: OpenClaw
  9. Frontend: Next.js + Phaser.js
  10. Backend Scripts
  11. Infrastructure & Deployment
  12. Complete File Inventory
  13. Team Workload Split
  14. Testing Strategy
  15. Demo Script
  16. Phase 2: Mainnet + Token
  17. Submission Checklist
  18. Post-Hackathon: Guild Network Vision
  19. Environment Variables

1. What Is AgentGuilds

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."

Core Concept

  • 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.

How It Works (30-Second Version)

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

2. Hackathon Context

Moltiverse Hackathon

  • 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?"

Prize Tracks

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

Our Strategy

  • 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

Required Stack (Hackathon Mandates)

  • 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)

3. Technology Decisions

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

Why Goldsky for Indexing

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/gn

Why Phaser.js Over PixiJS / React Canvas

For 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

Why Lightweight TG Bot (grammy) Instead of OpenClaw TG

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.


4. System Architecture

Modular Architecture (v4.1)

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)                │
└──────────────────────────────────────────────────────────────────────────┘

Request Flow: Pipeline Mission (Multi-Agent)

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

Request Flow: Standalone Mission (Single Agent)

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

5. The Living World

5.1 Core Fiction

"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.

5.2 Districts

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.

5.3 Reputation → Geography

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

5.4 Micro-Interactions (Animations)

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

5.5 World Interaction Panels

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]              │
└────────────────────────────────────────┘

5.6 Town Square (Center of World)

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) 🥈

5.7 Telegram → World Bridge

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.


6. Data Pipeline

6.1 Chain → Indexer → World

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

6.2 Goldsky Subgraph Config

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.json

Goldsky auto-generates a GraphQL schema from every event in the ABI. Each event becomes a queryable entity with all its parameters as fields.

6.3 GraphQL Queries

# 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
  }
}

6.4 Data → Visual Transform

// 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,
  };
}

7. Smart Contract

GuildRegistry.sol — Complete Source (~235 lines)

// 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);
    }
}

Contract Events → Goldsky → World

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

8. AI Agent System

8.1 OpenClaw Architecture

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)

8.2 Agent Configuration

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"]
    }
  }
}

8.3 SOUL.md Files (Agent Personalities)

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 essays

agents/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 format

8.4 How Multi-Agent Delegation Works

USER → "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 agentId and 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

9. Frontend

9.1 Directory Structure

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

9.2 Phaser ↔ React Bridge

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" />;
}

9.3 Sprite Generation Strategy

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.


10. Backend Scripts

10.1 Coordinator API — scripts/api.js (~790 lines)

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/events broadcasts all mutations in real-time
  • Multi-agent pipelines: Intra-guild collaboration (writer → designer → reviewer)
  • Admin endpoints: API key protected (X-Admin-Key header)
  • 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

10.2 Blockchain Library — scripts/monad.js (~835 lines)

All blockchain interactions via viem + Goldsky. Includes:

  • Full v4 contract ABI (inline, no external JSON dependency)
  • createPublicClient / createWalletClient for 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

10.3 CLI Tool — scripts/coordinator.js (~336 lines)

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"

10.4 Telegram Bot — tg-bot/bot.js (~473 lines)

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

10.5 Agent Runner — usageGuide/agent-runner.js (~516 lines)

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/heartbeat with 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

11. Infrastructure & Deployment

11.1 Modular Architecture

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                    │
└──────────────────────────────────────────┘

11.2 Module 1: Coordinator API (Required)

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

11.3 Module 2: Telegram Bot (Optional)

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

11.4 Module 3: OpenClaw Full Stack (Optional)

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 volume
  • tg-bot — Optional, depends on API health
  • openclaw — Profile "full" only, includes Ollama + Tailscale + Cloudflare tunnel

11.5 Deployment Guide

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

12. Complete File Inventory

Backend (Implemented)

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

Infrastructure (Implemented)

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

Agent System

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)

Smart Contracts

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

Frontend (Planned)

File Description
web/ Next.js + Phaser.js isometric world (not yet built)

Summary

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

13. Team Workload Split

Day-by-Day Schedule

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

Integration Handoffs

# 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

Git Strategy (Zero Merge Conflicts)

# 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

14. Testing Strategy

Contract Tests (On-Chain — Verified)

✓ 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

Reputation System (Verified End-to-End)

✓ 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

Indexer Tests (Goldsky v5)

✓ 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

API Tests (Verified)

✓ 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

Telegram Bot Tests (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 Tests (Verified)

✓ 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

End-to-End Pipeline Test (Verified)

✓ 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

15. Demo Script (60-90 Seconds)

[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."

16. Phase 2: Mainnet + Token

Day 4 Changes

  1. Deploy GuildRegistry to Monad Mainnet (chainId: 143)
  2. Launch $GUILD on nad.fun:
    Token name: AgentGuilds
    Symbol: $GUILD
    Initial supply: via nad.fun bonding curve
    
  3. Update Goldsky: Deploy new subgraph pointing to mainnet contract
  4. Update frontend: Switch chain ID, RPC URL, contract address, Goldsky endpoint
  5. Token utility (basic):
    • Hold 1 $GUILD to submit missions (access gating)
    • Future: stake to create guild, earn from fee buyback

Fee Structure (On-Chain)

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)

17. Submission Checklist

Phase 1: Agent Track (Day 3)

  • 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

Phase 2: Agent+Token Track (Day 4)

  • 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

18. Post-Hackathon: Guild Network Vision

This section is NOT built during the hackathon. It's described in README and demo as the vision.

Anyone Can Create a Guild

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.

Anyone Can Run a Guild Node

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

The Moat

"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.

Protocol Economics

  • 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

19. Environment Variables

Coordinator API (Required)

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)

Telegram Bot

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

Agent Runner (External Agents)

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)

OpenClaw (Optional — Full Stack)

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)

Current Deployed Values

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=10143

End 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.