xbot is an autonomous agent that posts to X (Twitter), measures engagement, learns what works, and autonomously improves its posting strategy over time using AI.
Instead of posting the same content repeatedly, xbot runs every 3 hours: it generates new tweets (1-3 pieces per run) based on your niche, posts them, waits for engagement to accumulate, scores them using a weighted engagement formula, analyzes patterns, and updates its strategy. Over time, it discovers which formats, tones, topics, and posting times drive the most valuable engagement for your account.
The bot continuously experiments with different posting hours to find your audience's peak engagement windows.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Your Bot Identity β
β (config/niche.md β you write once) β
β β
β β’ Topic/niche β’ Audience β’ Tone β’ Success metrics β
β β’ Engagement weights β’ Content boundaries β
ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββ
β DAILY RESEARCH LOOP β
β (researcher.py runs daily) β
ββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββΌβββββββββββββ
β β β
βΌ βΌ βΌ
ββββββββββ βββββββββββ ββββββββββ
β SCORE β βGENERATE β β POST β
β past ββ βnew tweetββ β to X β
βtweets β β(Gemini) β β β
ββββββββββ βββββββββββ ββββββββββ
β β β
β ββββββββββββββ€
β β
βββββββββββββββββββ¬ββββββββ
β
Wait 23hrs
β
βΌ
ββββββββββββββββ
β REFLECT β
β Analyze β
β patterns & β
β update β
β strategy β
ββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββ
β Updated Strategy (strategy.md) β
β β’ Best formats & avg scores β
β β’ Next hypothesis to test β
β β’ Experiment history β
β β’ Discarded approaches β
ββββββββββββββββββββββββββββββββββββββ
The loop: Generate β Post β Wait β Score β Reflect β Update Strategy β Repeat
Each tweet is an experiment. The bot learns which formats, tones, and topics drive engagement. Over weeks, it discovers the optimal content mix for your niche.
The Problem: Traditional bots score tweets once at 24 hours and lock the score in. But tweets continue gathering engagement for days. So the model learns from an incomplete picture.
xbot's Solution: Continuous re-scoring with intelligent priorities.
- Days 0-1: Engagement accumulating, no score yet
- Days 1-7: Re-scored daily, latest score used for learning
- Day 2: Score = 100 pts
- Day 3: Score = 145 pts (re-scored, reflects fuller engagement)
- Day 5: Score = 200 pts (re-scored again, used for strategy)
- Days 7-30: Optional re-score (30% chance to check for late engagement)
- Days 30+: Score locked, never re-scored
Why This Matters:
- β Learns from mature engagement data, not 24-hour snapshots
- β Distinguishes "flash engagement" (peaks fast, dies) from "sustainable engagement" (slow grow, stays high)
- β Better trend detectionβif an archetype is declining, you notice faster
- β Score history shows engagement arc, revealing valuable patterns
Example:
"Question + Data" format:
- Initial (24h): 100 pts
- Later (7d): 280 pts
Without re-scoring, model thinks this format scores 100 pts.
With re-scoring, model learns it scores 280 pts.
Huge difference in strategy!
All scoring details: See "Score Tracking & Continuous Re-Scoring" in strategy.md.
The bot is designed to prevent a common problem: convergence. Without safeguards, optimization leads to the bot discovering "Topic X + Format Y + Hour Z = highest score" and then repeating it forever until followers get bored.
xbot prevents this with 5 layers of anti-convergence:
-
Time Decay: Scores older than 60 days are dropped. This ensures the bot adapts when X's algorithm changes or trends shift.
-
Novelty Bonuses: Unexplored combinations get bonus scores (+15% to +50%). If "Thread Format" was tested 30 days ago but not recently, it gets a novelty boost to encourage re-testing.
-
Diversity Quotas: Hard limits on repetition. Max 2 archetypes per topic per 7 days, ensuring followers see variety.
-
Decline Detection: If a "best practice" starts scoring 20%+ worse recently, the bot automatically reduces reliance and explores alternatives.
-
Contrarian Testing: Every 5 posts, force testing the opposite of what's working best to discover new meta-strategies.
Result: The bot continuously improves while staying unpredictable and adapting to real-time algorithm changes.
Details on anti-convergence tracking: See the "Anti-Convergence Strategy" section in strategy.md.
git clone https://github.com/yourusername/xbot.git
cd xbotcp .env.example .env
# Edit .env and fill in your X API and Gemini API keysSee Where to Get API Keys below.
Edit config/niche.md and fill in:
- Account topic/niche (what your bot posts about)
- Target audience (who should find it valuable?)
- Tone and voice (casual? technical? contrarian?)
- Content boundaries (what never to post about)
- Success metrics (what matters most: replies? followers? impressions?)
- Engagement weights (customize the scoring formula)
- Posting constraints (character limits, emoji usage, hashtags, etc.)
This file defines your bot's entire personality. Spend time on it.
pip install -r requirements.txtRequires: Python 3.11+
python poster.pyThis posts a test tweet and logs the experiment. Check your X account to verify it worked.
python scorer.pyThis fetches engagement metrics for tweets posted >23 hours ago and scores them. Won't do anything if no tweets are old enough yet.
python researcher.pyThis runs one complete research loop cycle:
- Score old experiments (posts 23+ hours old)
- Analyze strategy and update strategy.md
- Generate 1-3 content pieces dynamically (mix of single tweets and threads)
- Post each piece
- Log each experiment with archetype, topic, thread length, and posting hour
Watch the console output to see each step progress.
Push the repo to GitHub:
git add .
git commit -m "Initial autobot setup"
git push -u origin mainThen add your API keys as GitHub repository secrets:
- Go to Settings β Secrets and variables β Actions
- Click New repository secret and add each of these:
X_API_KEYX_API_SECRETX_ACCESS_TOKENX_ACCESS_TOKEN_SECRETX_BEARER_TOKENNVIDIA_API_KEY
The workflow in .github/workflows/daily_post.yml will now run automatically every 3 hours (at 00:00, 03:00, 06:00, 09:00, 12:00, 15:00, 18:00, 21:00 UTC) and commit changes back to the repo. This enables the bot to discover which hours drive the best engagement.
- Go to X Developer Portal
- Create a new project or use an existing one
- Create an "App" within the project
- Go to Keys and tokens tab
- Generate/copy these values:
- API Key β
X_API_KEY - API Secret β
X_API_SECRET - Access Token β
X_ACCESS_TOKEN - Access Token Secret β
X_ACCESS_TOKEN_SECRET - Bearer Token β
X_BEARER_TOKEN
- API Key β
Permissions needed:
- Read: tweets, follows, blocks, mutes, bookmarks, users
- Write: tweets, follows, bookmarks
- Go to NVIDIA API Catalog
- Sign in or create an account
- Generate an API key
- Copy it β
NVIDIA_API_KEY
The bot uses the Qwen 3.5-122B model via NVIDIA's API for tweet generation and strategy analysis.
| File | Owner | Notes |
|---|---|---|
config/niche.md |
You | Define bot identity once. Update if strategy shifts. |
strategy.md |
Agent | Autonomously rewritten daily by researcher.py based on experiment results. Don't edit manually. |
data/experiments.jsonl |
Agent | Append-only log of all posts. Each line is one experiment (JSON). Don't edit. |
generator.py |
You | Generates tweets using NVIDIA API (Qwen 3.5-122B). Modify prompts if needed. |
poster.py |
You | Posts tweets and logs experiments. Core posting logic. |
scorer.py |
You | Fetches metrics and scores tweets. Modify weights here if needed. |
researcher.py |
You | Main orchestration loop. Analyzes strategy using NVIDIA API. Modify schedule or add steps here. |
requirements.txt |
You | Dependencies. Update if you add new packages. |
.env |
You | API keys. Keep secret. Never commit to git. |
.env.example |
You | Template for .env. Safe to commit. |
.gitignore |
You | Already ignores .env, data/, and pycache. |
Experiments are appended to data/experiments.jsonlβone JSON object per line.
Each record looks like:
{
"tweet_id": "1234567890",
"text": "Your posted tweet text here or [\"tweet 1\", \"tweet 2\", ...]",
"archetype": "The Controversial Opinion",
"topic": "Founder Reality",
"thread_length": 3,
"posted_hour": 9,
"hypothesis": "Testing if 3-piece threads on Founder Reality drive more replies",
"format_used": "3-piece thread",
"posted_at": "2026-03-31T09:15:30Z",
"score": 285.5
}Columns:
tweet_id: X's unique identifier for the tweettext: The exact tweet text (string for single tweets, array for threads)archetype: Which of the 10 archetypes was used (e.g., "The Debate Starter", "The Data Drop")topic: Topic cluster covered (e.g., "AI & Future", "Founder Reality")thread_length: How many parts (1 for single, 2-7 for threads)posted_hour: UTC hour when posted (0-23) β tracks best posting timeshypothesis: One sentence: what was this tweet testing?format_used: Short label combining archetype + thread lengthposted_at: ISO 8601 timestamp (UTC) when postedscore: Weighted engagement score (null until 23+ hours have passed)
To analyze experiments:
# See the last 5 experiments
tail -5 data/experiments.jsonl
# Pretty-print one experiment
cat data/experiments.jsonl | jq '.' | head -20
# Find highest-scoring experiments by archetype
cat data/experiments.jsonl | jq 'select(.score != null) | {archetype, score}' | sort -rn
# See which posting hours perform best
cat data/experiments.jsonl | jq 'select(.score != null) | {posted_hour, score}' | sort -rnThe agent reads this file daily to identify which archetypes, topics, thread lengths, and posting times score highest, then updates strategy.md accordingly.
The engagement weights in config/niche.md determine your bot's priorities. They're in the Engagement Weights section:
| Interaction Type | Points |
|---|---|
| Impression | 0.1 |
| Like | 2 |
| Retweet | 6 |
| Reply | 8 |How to think about it:
- Replies (high value): Direct engagement, signals readers are interested enough to respond. Set high (4-7).
- Retweets (medium-high): Active endorsement, spreads your reach. Set medium (4-6).
- Likes (medium): Passive approval, good but less meaningful than replies. Set lower (2-4).
- Impressions (low): Just means it was shown. Set very low (0.1-0.5).
Different goals, different weights:
- Building community / driving replies: Increase reply weight to 7+, keep others low
- Going viral / maximizing reach: Increase retweet weight to 8+, impression weight to 1+
- Balanced growth: Keep all 2-5 (current defaults are good)
- Engagement over vanity metrics: Lower likes/impressions, raise replies/retweets
The agent uses these weights to score every tweet, so changing them changes what the bot considers "success"βand thus what it generates more of.
Adjust weights and observe: Change them, run the loop a few times, then check which formats the agent starts favoring in strategy.md. The weights directly shape the agent's learning.
"Error: Missing X_API_KEY in .env"
β Copy .env.example to .env and fill in all 6 keys. See Where to Get API Keys.
"Tweet posting failed" β Check that your X app has write:tweets permission. Go to Developer Portal.
"No pending experiments to score"
β Tweets need to be 23+ hours old to score. Post a tweet, wait a day, then run python scorer.py.
"Strategy update failed"
β Check that GEMINI_API_KEY is valid. Visit Google AI Studio.
"Git push failed in GitHub Actions" β The workflow uses the default GitHub token. If it still fails, check repo permissions under Settings β Actions β General.
xbot/
βββ config/
β βββ niche.md # Bot identity (you fill this in)
βββ data/
β βββ .gitkeep
β βββ experiments.jsonl # Experiment log (agent appends)
βββ .github/
β βββ workflows/
β βββ daily_post.yml # GitHub Actions scheduler
βββ strategy.md # Current strategy (agent rewrites daily)
βββ generator.py # Generate tweets with Gemini
βββ poster.py # Post tweets to X
βββ scorer.py # Score tweets by engagement
βββ researcher.py # Main orchestration loop
βββ requirements.txt # Dependencies
βββ .env.example # Template for secrets (commit this)
βββ .env # Your actual secrets (git-ignored)
βββ .gitignore # Ignores .env, __pycache__, data/
βββ README.md # This file
- Set up your identity: Fill in
config/niche.mdwith your bot's niche, tone, and success metrics. - Test locally: Run
python researcher.pya few times to ensure everything works. - Go live: Push to GitHub, add secrets (including
NVIDIA_API_KEY), and let it run daily. - Monitor: Check
strategy.mddaily to see what the agent learned. Readdata/experiments.jsonlto spot trends. - Iterate: If results aren't great, adjust niche.md (success metrics, tone, content boundaries) or tune engagement weights.
Good luck! π
MIT