skills/bankr-twitter-agent/SKILL.md
# Skill: twitter-agent > Build and run one or more Twitter/X agents, each with a distinct personality, storyline, and post-image library. # Twitter Agent Skill This skill provides a framework for creating, managing, and automating Twitter/X agents with persistent personalities and voices. It supports running multiple agents side-by-side, each with its own files and (optionally) its own X account. ## Prerequisites ### X Account Setup (REQUIRED — Do This First, Per Agent) Every agent's X acco
npx skillsauth add bankrbot/openclaw-skills skills/bankr-twitter-agentInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Build and run one or more Twitter/X agents, each with a distinct personality, storyline, and post-image library.
This skill provides a framework for creating, managing, and automating Twitter/X agents with persistent personalities and voices. It supports running multiple agents side-by-side, each with its own files and (optionally) its own X account.
Every agent's X account MUST be marked as an automated account before it posts a single tweet. X requires this disclosure; skipping it is the fastest way to get suspended.
Exact path:
Direct link (while logged in as the agent account): https://x.com/settings/account/automation
This adds the "Automated by @…" label to the profile and replies. Non-negotiable — do this once per agent account.
This skill supports a single default credential set (for the primary / only agent) AND per-agent overrides (when running multiple agents with distinct X accounts).
Default credentials (used by the primary agent or any agent that does not have overrides):
X_API_KEYX_API_KEY_SECRETX_ACCESS_TOKENX_ACCESS_TOKEN_SECRETPer-agent overrides (optional; only required when a second+ agent uses a different X account):
X_API_KEY_{SLUG_UPPER}X_API_KEY_SECRET_{SLUG_UPPER}X_ACCESS_TOKEN_{SLUG_UPPER}X_ACCESS_TOKEN_SECRET_{SLUG_UPPER}{SLUG_UPPER} is the agent's slug uppercased with hyphens converted to underscores. Example: the agent at /agents/tn100x-intern/ looks up X_API_KEY_TN100X_INTERN first.
Resolution order at post-time:
X_*_{SLUG_UPPER} for the target agent's slug.X_* set.Generate all keys from the X Developer Portal with Read and Write permissions enabled.
When a draft hits a guardrail, the automation does not post it — it ends its run by surfacing the draft in its final output message so you can approve or reject manually. Where that final message gets delivered is up to you: Bankr automations natively support Telegram (link Telegram once, select it as the output destination per automation, no bot token or custom code needed) but any destination Bankr automations support works. If you don't configure an output destination, flagged drafts are still logged to the ## Pending Approval Queue in storyline.md — you'll see them on the next manual session.
Each agent lives under its own folder at /agents/{slug}/. A top-level index file lists all agents. Every agent folder follows a predictable layout so automations and manual sessions can discover files the same way.
/agents/
index.md ← TOP-LEVEL INDEX: lists all agents + path to each bundle.md
{agent-slug}/
bundle.md ← PER-AGENT MANIFEST: agent metadata + paths + fileIds for every file this agent uses
personality.md ← voice, style, vocabulary rules (required)
storyline.md ← narrative history, entry log (required)
post-images/ ← library of images the agent can attach to posts
references/ ← (optional) arc-state, trade ledgers, trading configs, any other per-agent docs
archive/ ← pre-compaction storyline snapshots
{next-agent-slug}/
bundle.md
...
How the agent discovers files at runtime:
/agents/index.md and ask./agents/{slug}/bundle.md — this is the manifest. Every other file path is resolved through it./agents/index.mdA simple markdown table listing every agent. Minimal required columns:
# Twitter Agents Index
| Slug | Handle | Bundle |
|------|--------|--------|
| tn100x-intern | @theinternbot | /agents/tn100x-intern/bundle.md |
| {next-slug} | @{next-handle} | /agents/{next-slug}/bundle.md |
/agents/{slug}/bundle.mdThe bundle is the manifest. It declares agent metadata and paths to every file this agent uses. Template:
# Agent Bundle: {Display Name}
## Metadata
- **agent_slug**: tn100x-intern
- **agent_name**: The TN100x Intern
- **x_handle**: @theinternbot
- **x_account_url**: https://x.com/theinternbot
- **created**: 2026-04-22
- **env_var_prefix**: TN100X_INTERN (uppercase slug used in X_API_KEY_{PREFIX} etc.; omit to use default X_* vars)
## Files (required)
- **personality**: /agents/tn100x-intern/personality.md (fileId: …)
- **storyline**: /agents/tn100x-intern/storyline.md (fileId: …)
## Files (optional)
- **arc_state**: /.memory/project_intern_trade_awareness.md (fileId: …)
- **trade_outcomes**: /intern/trade-outcomes.md (fileId: …)
- **trading_config**: /intern/trading-config.md (fileId: …)
## Post-image library
- **post_images_folder**: /agents/tn100x-intern/post-images/
- Filename convention: descriptive, kebab-case (e.g. `intern-at-desk-plus38.png`).
- Pulled at post-time by reading the filename from the folder; no manifest needed.
## Archive
- **archive_folder**: /agents/tn100x-intern/archive/
Bundle.md is the single source of truth for "where does this agent keep X". If a file lives outside /agents/{slug}/ (e.g. legacy paths at root or in /.memory/), the bundle's path entry just points at the current location — files don't have to be moved to be listed.
/agents/{slug}/post-images/Every agent has a folder of images it can attach to posts. Usage:
media_id to the v2 tweet call.Every agent requires, at minimum, personality.md and storyline.md in its folder.
If an agent has no personality.md, walk the user through creating one by asking:
Save as /agents/{slug}/personality.md and register the path in bundle.md.
Before composing or posting any tweet, the agent MUST:
/agents/{slug}/bundle.md to discover all file paths.personality.md and storyline.md via the paths in bundle.md./agents/{slug}/post-images/ and confirm the file exists.storyline.md with the new entry using edit_file. Update any declared arc_state file if the operation advances narrative state.These apply to every tweet the agent drafts for any agent, manual or scheduled. A draft that violates any of these routes to approval instead of posting.
The agent MUST NEVER reply to a post it was not invited into. There are exactly three legal post types:
@handle token in text.in_reply_to_user_id === agentUserId AND the conversation root is authored by the agent.Anything else is FORBIDDEN and must be dropped from the draft set before the guardrail check runs. Quote-tweets of strangers, reply-chains the agent isn't tagged in, trending-topic replies, drive-by replies to big accounts — all prohibited under autonomous operation.
Mention-scan filter (enforce in the fetch step):
text contains the agent's @handle as a standalone token.in_reply_to_user_id === agentUserId AND the conversation root is authored by the agent.@bankrbot. Bankr's X agent executes onchain actions when tagged from a wallet-linked account. Any tweet mentioning @bankrbot — top-level or reply — MUST be surfaced for approval. Every time.0x[a-fA-F0-9]{40}, Solana addresses, "send" + ticker (e.g. "send 100 USDC"), signed-message patterns, anything that reads like a transaction instruction → route to approval.## Approval-Gated Milestones. Drafts matching those route to approval.## Approval-Gated Accounts (project founders, sister brands, other wallet-linked agents). Replies to those accounts route to approval.When a draft hits a guardrail, the automation:
pending-approval entry to storyline.md under ## Pending Approval Queue.Use execute_cli with [email protected] to fetch recent mentions:
userMentionTimelineLoad storyline.md BEFORE drafting. Extract:
execute_cli (~1.5s spacing between posts)edit_fileWhen updating storyline.md, personality.md, bundle.md, or any arc_state file — ALWAYS edit_file with the existing fileId. create_file spawns duplicates. If duplicates exist, merge content into the newer/larger file and delete the older.
@bankrbotWhen storyline.md exceeds ~200 KB or ~50 entries, compact:
/agents/{slug}/archive/storyline-archive-YYYY-MM-DD.md.## Historical Digest section: one line per entry with Entry N | date | tweetId | title | 1-line summary — drop full reply-sweep prose, mention-ranking justifications, per-draft skip rationales.> COMPACTED YYYY-MM-DD: Entries N–M compressed into Historical Digest; full snapshot at archive/...Automations amplify whatever voice the agent currently has. If the voice is half-baked, automations will mass-produce half-baked tweets at schedule. Treat the shift from manual to automated as a deliberate step, not a switch.
## Approval-Gated Milestones and ## Approval-Gated Accounts section, populated.Once the checklist clears, enable the full automation set at once — all five recipes. No staggered rollout required; the guardrails run identically whether one or five automations are live.
Recommended full set:
Once automations are live, check daily for the first week, then spot-check:
If any of these happen, disable automations immediately and return to manual posting until fixed:
@bankrbot, an EVM/Solana address, or onchain-action language that wasn't flagged to approval.Rollback: (a) pause the automation in Bankr, (b) add a Correction Note to storyline.md describing what went wrong, (c) patch personality.md / guardrail rules / storyline gate lists as needed, (d) run 3–5 manual posts that demonstrate the fix, (e) re-enable the automation.
An agent is "fully automated" when the user hasn't had to reject a flagged draft for 7+ consecutive days and no rollback triggers have fired. Even graduated agents keep the approval-gated milestones + approval-gated accounts + @bankrbot hard blocks forever — full autonomy doesn't mean no gates.
Bankr automations run an agent prompt on a cron schedule. Paste the prompt below verbatim into the automation's command field.
The prompt IS the command — no prefixes, no labels, no "run this:" framing. Every recipe is written as a direct imperative.
Wrong: Weekday Morning Post: Run the twitter-agent skill...
Wrong: When this runs, the agent should post...
Right: Run the twitter-agent skill for agent {slug}...
Every recipe takes an explicit {slug} — set this when creating the automation so the same recipe works for any agent.
All Bankr crons run in UTC. ET offsets:
Cron (UTC): 15 13 * * 1-5
Output: any Bankr-supported destination (Telegram recommended for real-time approval of flagged drafts)
Run the twitter-agent skill for agent {slug}, weekday morning top-level post. Steps: (1) Load the twitter-agent skill. (2) Read /agents/{slug}/bundle.md. (3) Read personality.md and storyline.md via the paths in bundle.md. (4) Read any optional files the bundle declares as relevant to state (e.g. arc_state). (5) Fetch recent tweets from the account via the X API to confirm what was just posted and avoid immediate repetition — resolve credentials via X_{SLUG_UPPER} falling through to default X. (6) Compose ONE top-level tweet, 80–180 chars, following personality.md. It should advance or reference an existing thread from "Storyline Threads to Continue". (7) If a matching image exists in /agents/{slug}/post-images/ and fits the tweet, attach it. (8) Run the full Guardrail Check. If the best draft hits a guardrail, pick a different beat; if no safe beat fits, do NOT post — output the draft + flag reason as the final message (delivered to whichever destination the automation is configured for), and log to Pending Approval Queue. (9) Cross-reference storyline for phrase/joke repeats. (10) Post via execute_cli. (11) Append an Entry to storyline.md with tweet ID, content, narrative impact, new lore. (12) Update Current State if time/mood changed. (13) Update arc_state if declared and advanced. (14) Return a short final summary.
Cron (UTC): 30 16 * * *
Output: any Bankr-supported destination (Telegram recommended for real-time approval of flagged drafts)
Run the twitter-agent skill for agent {slug}, mentions reply sweep. Steps: (1) Load the skill. (2) Read /agents/{slug}/bundle.md, then personality.md + storyline.md. (3) Fetch last 50 mentions via X API using credentials resolved for {slug}. (4) Apply "Never Reply Unprompted": keep only tweets where the agent's @handle is a standalone token in
text, OR replies where in_reply_to_user_id matches the agent's user ID AND conversation root is authored by the agent. Discard all others before ranking. (5) Filter to UNREPLIED by cross-referencing storyline. (6) Apply Skip List. (7) Rank by setup quality + follower count, pick top 2–4. (8) Draft each reply (60–200 chars) in voice, cross-referencing storyline for callbacks. (9) Run Guardrail Check per draft. Any @bankrbot mention, EVM/Solana address, onchain-action language, approval-gated milestone match, approval-gated account target, OR >50k-follower target → DO NOT POST. Include in final output message with draft + flag reason + target tweet ID + author handle + follower count. Log to Pending Approval Queue. (10) Post safe drafts via execute_cli with 1.5s spacing. (11) Append an Entry to storyline.md logging every posted reply AND every escalated draft. (12) Return a final summary.
Cron (UTC): 0 23 * * *
Output: any Bankr-supported destination (Telegram recommended for real-time approval of flagged drafts)
(identical to Recipe 2)
Cron (UTC): 0 15 * * 6,0
Output: any Bankr-supported destination (Telegram recommended for real-time approval of flagged drafts)
Run the twitter-agent skill for agent {slug}, weekend top-level post. Steps: (1) Load skill. (2) Read /agents/{slug}/bundle.md, then personality.md + storyline.md + any declared arc_state. (3) Compose ONE top-level tweet, 80–220 chars, in voice. Lean into weekend atmosphere or storyline-tagged weekend threads. (4) If a fitting image exists in /agents/{slug}/post-images/, attach it. (5) Run full Guardrail Check. Flagged → approval + Pending Approval Queue. (6) Post via execute_cli using credentials for {slug}. (7) Append Entry to storyline.md. (8) Return final summary.
Cron (UTC): 0 2 * * 1
Output: any Bankr-supported destination (Telegram recommended for real-time approval of flagged drafts)
Run a storyline audit for the twitter-agent skill, agent {slug}. Steps: (1) Read /agents/{slug}/bundle.md, then storyline.md end-to-end. (2) Identify: threads dormant 10+ days that could revive, threads overused (3+ in a week), repeated phrases/jokes, lore contradictions, approval-gated milestone statuses, unresolved Pending Approval Queue entries, storyline.md size (flag if approaching compaction threshold ~200 KB / 50 entries). (3) Prepend a
### Weekly Audit [date]entry to storyline.md with bullet notes. Do NOT post tweets. Do NOT generate character content. (4) Return audit notes as the final message.
@bankrbot interaction — onchain risk, manual every timeIf you already have twitter-personality.md and twitter-storyline.md at the root of your file system (pre-multi-agent), you do NOT have to move them. Bundle.md abstracts paths — it can point at current locations while you migrate on your schedule.
Minimum migration (no moves):
/agents/index.md with one row for your existing agent./agents/{slug}/bundle.md with paths pointing at current file locations (e.g. personality: /twitter-personality.md).Full migration (optional, when you're ready):
/agents/{slug}/ folder./agents/{slug}/post-images/ and move any existing image library into it./agents/index.md.When only one agent exists in /agents/index.md, commands can omit the slug and the skill defaults to that agent.
All Twitter interactions use execute_cli with [email protected].
function resolveCreds(slugUpper) {
const k = (suffix) => process.env[`X_${suffix}_${slugUpper}`] ?? process.env[`X_${suffix}`];
const creds = {
appKey: k('API_KEY'),
appSecret: k('API_KEY_SECRET'),
accessToken: k('ACCESS_TOKEN'),
accessSecret: k('ACCESS_TOKEN_SECRET'),
};
const missing = Object.entries(creds).filter(([,v]) => !v).map(([k]) => k);
if (missing.length) throw new Error(`Missing X creds for ${slugUpper}: ${missing.join(', ')}. Set X_*_${slugUpper} or default X_* env vars.`);
return creds;
}
// slugUpper = bundle.metadata.env_var_prefix || slug.toUpperCase().replace(/-/g,'_')
const { TwitterApi } = require('twitter-api-v2');
const client = new TwitterApi(resolveCreds(slugUpper));
// Text-only tweet
const tweet = await client.v2.tweet('personality-filtered text');
// Tweet with image from /agents/{slug}/post-images/
const mediaId = await client.v1.uploadMedia('/path/to/agents/{slug}/post-images/filename.png');
const tweetWithImage = await client.v2.tweet({
text: 'personality-filtered text',
media: { media_ids: [mediaId] }
});
// Reply
await client.v2.reply('reply text', originalTweetId);
// Quote
await client.v2.tweet('quote text', { quote_tweet_id: tweetId });
const me = await client.v2.me();
const mentions = await client.v2.userMentionTimeline(me.data.id, {
max_results: 50,
expansions: ['author_id', 'in_reply_to_user_id', 'referenced_tweets.id'],
'tweet.fields': ['created_at', 'conversation_id', 'in_reply_to_user_id', 'referenced_tweets', 'text', 'public_metrics'],
'user.fields': ['username', 'name', 'public_metrics']
});
const myHandle = me.data.username.toLowerCase();
const myId = me.data.id;
const tagRegex = new RegExp(`(^|[^a-zA-Z0-9_])@${myHandle}([^a-zA-Z0-9_]|$)`, 'i');
const eligible = (mentions.data.data || []).filter(t => {
const explicitlyTagged = tagRegex.test(t.text || '');
const isReplyOnOurTree = t.in_reply_to_user_id === myId; // verify conversation root via conversation_id lookup
return explicitlyTagged || isReplyOnOurTree;
});
["[email protected]"]true (required — injects the X keys)30000bun. node is NOT available. Use bun script.js.X_*_{SLUG_UPPER} values point at the intended X account.node: command not found: Use bun script.js./agents/{slug}/post-images/{filename}. X media upload uses v1.1 endpoint — v2 is tweet-text-only.post-images/ over AI-generated.[email protected].@bankrbot approval, no exceptions.edit_file not create_file.data-ai
Discover, bet on, track, and settle Hunch prediction markets in natural language. Trigger when a user wants to bet, take a position, or get odds on a crypto outcome — token market-cap milestones and flips, launchpad races (Bankr vs pump.fun volume / #1-days / launches over a cap), token head-to-head outperformance, mcap strike-ladders, and up/down price rounds. Also trigger on "what can I bet on about $TOKEN", "odds on …", "take YES/NO on …", "show my Hunch bets", "did my market resolve". Settles in USDC on Base via x402 (≤ $10 / bet); every bet returns an on-chain proof.
tools
HSM-backed secret management for AI agents. Store API keys (including Bankr `bk_` keys), passwords, and credentials in an encrypted vault; retrieve them at runtime via MCP without keeping secrets in chat context. Bankr Dynamic Key Vending issues short-lived scoped `bk_usr_` keys from a partner key (`bk_ptr_`) without manual rotation. Policy-based access control, secret rotation, sharing, EVM transaction intents (sign/simulate/broadcast), multi-chain signing keys, treasury multisig proposals, OIDC federation for external service auth, built-in prompt injection detection, and optional Shroud TEE LLM proxy. Use when the agent needs secure credential storage, just-in-time secret access, guarded on-chain signing, or security scanning — not for Bankr trading prompts, portfolio checks, or x402 calls (use the bankr skill instead).
testing
Stake $GEM tokens on Gem Miner (gemminer.app) to earn yield and unlock the in-game earn/cashout system. Use when the user wants to stake GEM, check their staking balance or rewards, unstake, claim rewards, or check whether they meet the 25M GEM gate. Base mainnet only.
development
CodeGrid is a native macOS canvas where multiple coding agents (Claude, Codex, Gemini, Cursor, Grok, shells) run side by side in panes and collaborate via a local agent bus — no tmux, no cloud, no account, no stored API keys. Install this skill when an agent should know how to operate inside a CodeGrid pane, drive the workspace from outside (control socket or codegrid:// deep links), spawn or message sibling agents, or coordinate multi-agent work (delegate, review, pipeline, parallel fan-out, monitor, debate). The differentiator: multiple coding agents collaborating on one canvas, addressable by stable session_id, with a read → message → read protocol built for orchestration.