Skip to main content

Overview

The X bot (@Mouth_App) is a standalone Node.js service that monitors Twitter/X for mentions, parses challenge intents using an LLM, creates draft challenges in the database, and replies with a link to pvp.mouth.app/challenge/{id}. It is purely a distribution layer — it does not handle funds, deploy contracts, or resolve challenges. All on-chain operations happen when users click the link and interact with the web app.

Service Architecture

The bot runs as an independent process, separate from the backend API. Both share the same Neon PostgreSQL database.

Key Dependencies

Mention Polling

The bot uses the User Mention Timeline endpoint (GET /2/users/:id/mentions) to fetch new mentions every 30 seconds.

Polling Flow

  1. On startup, fetch the bot’s user ID from @Mouth_App username
  2. Poll mentions with since_id to only get new tweets
  3. For each mention:
    • Dedup check: skip if tweet_id already exists in draft_challenges
    • LLM parse: extract challenge parameters from tweet text
    • Confidence filter: skip if LLM confidence < 0.5 (not a real challenge)
    • Create draft: insert into draft_challenges with parsed data
    • Post reply: respond with challenge link

Rate Limits

The X API free/pay-per-use tier provides:
  • Mention reads: polled every 30 seconds, 100 tweets per request
  • Tweet writes: replies posted per processed challenge
The bot tracks since_id in memory to avoid re-fetching old mentions. On restart, it re-fetches recent mentions but deduplicates via the database.

LLM Tweet Parser

The parser uses Claude Haiku 4.5 (claude-haiku-4-5-20251001) via the Anthropic API to extract structured challenge data from natural language tweets.

Input

A raw tweet like:

Output

Extraction Rules

Cost

Claude Haiku 4.5 is the cheapest model available. Each tweet parse costs approximately $0.001-0.002 — negligible even at high volume.

Database: draft_challenges

Draft challenges are stored in a separate table from bets, with no foreign keys to users. This is intentional:
  • The bot doesn’t know if the challenger or opponent are registered users
  • Draft only stores X handles as strings — identity resolution happens when users log in
  • A draft becomes a real bet only after the challenger confirms and deposits USDC

Indexes

Draft Lifecycle

Reply Templates

The bot posts different replies depending on the event:

Challenge Created (PvP)

Challenge Created (Open)

Challenge Accepted

Challenge Resolved

X API Authentication

The bot uses OAuth 1.0a User Context for posting replies (writing as @Mouth_App) and Bearer Token for reading mentions.
The X app must have Read and Write permissions enabled, and the app type must be set to Web App, Automated App or Bot (confidential client). After changing permissions, the Access Token must be regenerated.

Environment Variables

Deployment

The bot is deployed as a standalone service on Railway, separate from the backend API. Both connect to the same Neon PostgreSQL database.

Why Standalone?

  • Isolation: if the bot crashes or hits X rate limits, the API stays up
  • Independent scaling: bot is I/O-bound (X API + LLM), API is request-driven
  • Simpler deploys: bot can be restarted without affecting live users

Draft → Bet Conversion

When a user clicks the challenge link (pvp.mouth.app/challenge/{id}), the flow is:
  1. Frontend fetches draft data from GET /challenges/:id
  2. Challenger logs in with X via Privy → backend recognizes the X handle
  3. Review: challenger sees pre-filled form (title, amount, odds, expiration) — can edit
  4. Confirm + Deposit: challenger deposits USDC → backend creates the real bet entry, deploys smart contract, and updates draft_challenges.bet_id + draft_challenges.status = 'confirmed'
  5. Opponent clicks same link → sees “Accept Challenge” → deposits → bet goes active
  6. Bot posts update on X: “It’s ON!”
The draft_challenges table has no foreign keys to users. Identity resolution (X handle → wallet address) only happens when the user logs in and the backend calls resolveXHandleToWallet(). See Identity & Wallets for details on pre-generated wallets.