4.9 KiB
xBot
AI-powered Twitter/X bot that generates and posts tweets on configurable schedules using stealth browser automation.
How it works
- Scheduler runs via cron, picks random times within a configured window
- Bot logs into X via Kernel.sh stealth browsers (residential proxies + CAPTCHA solving)
- Claude (Anthropic API) generates tweets based on your prompts
- Links are inserted after generation — URLs never touch the AI
- History is tracked per-prompt and fed back to avoid repetition
Setup
Prerequisites
Install
git clone https://github.com/MattJackson/xBot.git
cd xBot
npm install
Configure
- Copy the example files:
cp .env.example .env
cp prompts.example.json prompts.json
- Edit
.envwith your credentials:
MYACCOUNT_USER=your_twitter_handle
MYACCOUNT_PW=your_password
MYACCOUNT_EMAIL=your_email@example.com
MYACCOUNT_PHONE=1234567890
KERNEL=sk_your_kernel_key
ANTHROPIC=sk-ant-your_anthropic_key
Credentials are prefixed by account name (uppercase). To add another account, add another set:
ANOTHERACCOUNT_USER=...
ANOTHERACCOUNT_PW=...
ANOTHERACCOUNT_EMAIL=...
ANOTHERACCOUNT_PHONE=...
- Edit
prompts.jsonwith your prompts (see Prompt Configuration below).
Run
Post a single tweet:
node bot.js <prompt-name>
Schedule posts for the day (picks random times, waits, then posts):
node scheduler.js <prompt-name>
Cron
Add a cron job for each prompt. The scheduler handles random timing within the window — cron just needs to trigger it once daily before the window opens.
crontab -e
# Runs daily — scheduler picks random time(s) between 8am-8pm PST
0 16 * * * cd /path/to/xBot && /usr/bin/node scheduler.js my-prompt >> bot.log 2>&1
The cron time should be in UTC. 0 16 * * * = midnight PST (8 hours ahead), ensuring the scheduler starts before the 8am PST window.
Prompt Configuration
prompts.json is an array of prompt objects:
[
{
"name": "my-prompt",
"account": "myaccount",
"prompt": "Your prompt text here. Generate 1 tweet. Just the tweet.",
"links": {
"link": "https://example.com"
},
"schedule": {
"type": "daily",
"window": [8, 20],
"postsPerDay": [1, 3],
"minGapHours": 4
}
}
]
Fields
| Field | Required | Description |
|---|---|---|
name |
Yes | Unique identifier. Used as CLI argument and for history files. |
account |
Yes | Maps to env var prefix. "myaccount" looks up MYACCOUNT_USER, etc. |
prompt |
Yes | The prompt sent to Claude. Include generation instructions here. |
links |
No | Key-value map. <key> placeholders in the generated tweet are replaced with the URL. URLs never reach the AI. |
schedule |
Yes | Scheduling configuration (see below). |
Schedule types
Daily — posts every day, 1 or more times:
{
"type": "daily",
"window": [8, 20],
"postsPerDay": [1, 3],
"minGapHours": 4
}
window:[startHour, endHour]in PST. Posts only happen within this range.postsPerDay:[min, max]. A random count is picked each day. Defaults to[1, 1].minGapHours: Minimum hours between posts on the same day. Defaults to4.
Random — posts on random days with a minimum gap:
{
"type": "random",
"window": [8, 20],
"minDays": 2
}
minDays: Minimum days between posts. After the gap is met, there's a 50% chance each day — so actual spacing varies naturally (2, 3, 4+ days).
Link placeholders
Use <placeholder> in your prompt instructions. The AI generates the tweet with the placeholder, then the bot replaces it with the real URL:
{
"prompt": "Write a tweet. End with <link> on its own line.",
"links": {
"link": "https://example.com"
}
}
Multiple placeholders work too:
{
"prompt": "Mention <site> and end with <cta>.",
"links": {
"site": "https://mysite.com",
"cta": "https://mysite.com/signup"
}
}
Multi-account
Each prompt specifies which account to post from. You can run multiple accounts from the same instance:
[
{ "name": "account1-daily", "account": "firstaccount", "prompt": "...", "schedule": { ... } },
{ "name": "account2-promo", "account": "secondaccount", "prompt": "...", "schedule": { ... } }
]
Just add the corresponding credentials to .env for each account.
Files
| File | Tracked | Description |
|---|---|---|
bot.js |
Yes | Main bot — login, generate, post |
scheduler.js |
Yes | Picks random times, runs bot.js |
prompts.json |
No | Your prompt config (create from example) |
.env |
No | Your credentials |
history-*.json |
No | Per-prompt tweet history |
bot.log |
No | Cron output log |
License
MIT