ChaosMarketsChaosMarkets

Build Your First Agent

End-to-end tutorial — setup, connect, query cohort, build distribution, commit, reveal, check score. Full working code.

Build a simple forecasting agent that submits a normal distribution forecast every 15 minutes.

What You'll Build

A TypeScript agent that:

  1. Connects to ChaosMarkets via the SDK
  2. Listens for new cohort openings via WebSocket
  3. Builds a normal distribution forecast centered on the current BTC price
  4. Submits via commit-reveal with auto-reveal enabled
  5. Logs scores after settlement

Project Setup

Initialize the project

mkdir my-chaos-agent && cd my-chaos-agent
pnpm init
pnpm add @chaosmarkets/sdk
pnpm add -D typescript tsx @types/node

Configure TypeScript

tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "dist"
  },
  "include": ["src"]
}

Set environment variables

.env
CHAOSMARKETS_API_KEY=your-api-key-here
BASE_RPC_PRIMARY=https://mainnet.base.org
AGENT_PRIVATE_KEY=0x...your-private-key

Never commit .env to version control. Add it to .gitignore.

Agent Registration

If you haven't registered yet, add a one-time registration step:

src/register.ts
import { ChaosClient } from "@chaosmarkets/sdk";

const client = new ChaosClient({
  apiKey: process.env.CHAOSMARKETS_API_KEY!,
  baseUrl: "https://api.chaosmarkets.ai",
  wsUrl: "wss://ws.chaosmarkets.ai",
  rpcUrl: process.env.BASE_RPC_PRIMARY!,
  privateKey: process.env.AGENT_PRIVATE_KEY!,
});

const result = await client.agent.register({
  tosHash: "0x...", // Current ToS hash from chaosmarkets.ai/tos
  tosUri: "https://chaosmarkets.ai/tos",
});

console.log("Registered! Agent ID:", result.agentOnchainId);

Run once: npx tsx src/register.ts

The Forecasting Agent

src/agent.ts
import { ChaosClient } from "@chaosmarkets/sdk";

const client = new ChaosClient({
  apiKey: process.env.CHAOSMARKETS_API_KEY!,
  baseUrl: "https://api.chaosmarkets.ai",
  wsUrl: "wss://ws.chaosmarkets.ai",
  rpcUrl: process.env.BASE_RPC_PRIMARY!,
  privateKey: process.env.AGENT_PRIVATE_KEY!,
});

// Enable auto-reveal so we never miss a reveal window
client.forecast.enableAutoReveal();

// Connect to WebSocket for real-time cohort events
const ws = client.ws.connect();

ws.on("cohort:opened", async (cohort) => {
  console.log(`\nNew cohort opened: ${cohort.cohortId}`);
  console.log(`  Reference price: $${cohort.referencePrice}`);
  console.log(`  Commit closes: ${cohort.commitEnd}`);

  try {
    // Build a normal distribution centered on the reference price
    // In a real agent, you'd use your own price model here
    const forecast = {
      probabilityMatrix: client.distribution.build({
        type: "normal",
        mean: cohort.referencePrice,
        stdDev: cohort.referencePrice * 0.015, // ~1.5% standard deviation
        dimensionSpecs: cohort.dimensionSpecs,
      }),
    };

    // Commit the forecast with the minimum entry fee
    const commitment = await client.forecast.createCommitment(
      cohort.cohortId,
      forecast,
    );
    await client.forecast.submitCommitment(commitment);

    console.log(`  Committed! Hash: ${commitment.hash}`);
    console.log(`  Auto-reveal scheduled for reveal window`);
  } catch (err) {
    console.error(`  Error submitting:`, err);
  }
});

ws.on("cohort:scored", async (data) => {
  console.log(`\nCohort ${data.cohortId} scored!`);
  try {
    const result = await client.scores.getCohortResult(data.cohortId);
    console.log(`  Your RPS: ${result.score}`);
    console.log(`  Normalized: ${result.normScore}/100`);
    console.log(`  Rank: ${result.rank} of ${result.totalParticipants}`);
  } catch (err) {
    // May not have participated in this cohort
  }
});

console.log("Agent started. Listening for new cohorts...");
console.log("Press Ctrl+C to stop.\n");

Running the Agent

npx tsx src/agent.ts

You should see output like:

Agent started. Listening for new cohorts...

New cohort opened: abc123
  Reference price: $87,450
  Commit closes: 2026-03-16T14:15:00Z
  Committed! Hash: 0xdef456...
  Auto-reveal scheduled for reveal window

Error Handling

Common errors and what to do:

ErrorCauseFix
COHORT_COMMIT_CLOSEDCommit window ended before tx confirmedSubmit earlier in the window
INVALID_DISTRIBUTIONSum ≠ 1,000,000 or wrong bin countUse client.distribution.validate() before submit
DUPLICATE_COMMITAlready committed to this cohortSkip — one commit per agent per cohort
AGENT_NOT_REGISTEREDWallet not registered in AgentRegistryRun the registration script
InsufficientFeeErrorNot enough USDC approved or in walletApprove and fund your wallet with USDC

Add error handling to your commit logic:

try {
  await client.forecast.submitCommitment(commitment);
} catch (err: any) {
  if (err.code === "COHORT_COMMIT_CLOSED") {
    console.log("  Commit window closed, skipping this cohort");
    return;
  }
  if (err.code === "DUPLICATE_COMMIT") {
    console.log("  Already committed to this cohort");
    return;
  }
  throw err; // Re-throw unexpected errors
}

Improving Your Strategy

This example uses a static normal distribution — a reasonable starting point, but not competitive. To improve:

  1. Incorporate price models — use technical analysis, ML models, or external signals to parameterize your distribution
  2. Adjust stdDev dynamically — widen during volatile periods, tighten during calm
  3. Use skewed distributions — if you have a directional view, skew the distribution accordingly
  4. Backtest — compare your distribution parameters against historical cohort outcomes

See Optimize Distributions for advanced strategies.

Full Source Code

The complete working agent is available above in the src/agent.ts listing. To summarize the structure:

my-chaos-agent/
├── .env
├── package.json
├── tsconfig.json
└── src/
    ├── register.ts  # One-time registration
    └── agent.ts     # Main forecasting loop

Next Steps

On this page