Skill: lobstergeneralintelligence/x-api (version 0.1.0)

--- name: x-api description: Post to X (Twitter) using the official API with OAuth 1.0a. Use when you need to tweet, post updates, or publish content. Bypasses rate limits and bot detection that affect cookie-based approaches like bird CLI. --- # x-api 🐦 Post to X using the official API (OAuth 1.0a). ## When to Use - Posting tweets (cookie-based `bird tweet` gets blocked by bot detection) - Official API access is needed for reliability For **reading** (timeline, search, mentions), use `bird` CLI instead — it's free and works well for reads. ## Setup ### 1. Get API Credentials 1. Go to https://developer.x.com/en/portal/dashboard 2. Create a Project and App 3. Set App permissions to **Read and Write** 4. Get your keys from "Keys and tokens" tab: - API Key (Consumer Key) - API Key Secret (Consumer Secret) - Access Token - Access Token Secret ### 2. Configure Credentials **Option A: Environment variables** ```bash export X_API_KEY="your-api-key" export X_API_SECRET="your-api-secret" export X_ACCESS_TOKEN="your-access-token" export X_ACCESS_SECRET="your-access-token-secret" ``` **Option B: Config file** at `~/.clawdbot/secrets/x-api.json` ```json { "consumerKey": "your-api-key", "consumerSecret": "your-api-secret", "accessToken": "your-access-token", "accessTokenSecret": "your-access-token-secret" } ``` ### 3. Install Dependency ```bash npm install -g twitter-api-v2 ``` ## Post a Tweet ```bash x-post "Your tweet text here" ``` Or with full path: ```bash node /path/to/skills/x-api/scripts/x-post.mjs "Your tweet text here" ``` Supports multi-line tweets: ```bash x-post "Line one Line two Line three" ``` Returns the tweet URL on success. ## Limits - Free tier: 1,500 posts/month (requires credits in X Developer Portal) - Basic tier ($100/mo): Higher limits ## Reading (use bird) For reading, searching, and monitoring — use the `bird` CLI: ```bash bird home # Timeline bird mentions # Mentions bird search "query" # Search bird user-tweets @handle # User's posts bird read <tweet-url> # Single tweet ``` ## Troubleshooting **402 Credits Depleted**: Add credits in X Developer Portal → Dashboard **401 Unauthorized**: Regenerate Access Token (ensure Read+Write permissions are set first) **No credentials found**: Set env vars or create config file (see Setup above)

path: README.md
content: # x-api 🐦

A Clawdbot skill for posting to X (Twitter) using the official API.

## Why This Exists

The excellent [bird CLI](https://github.com/steipete/bird) is great for **reading** Twitter — timeline, mentions, search, etc. But **posting** through bird gets blocked by Twitter's bot detection:

```
❌ Failed to post tweet: Authorization: This request looks like it might be automated.
To protect our users from spam and other malicious activity, we can't complete this action right now.
```

Twitter's internal GraphQL API (what bird uses) aggressively blocks automated posts. The only reliable way to post is through the **official X API** with OAuth 1.0a.

## The Catch

The X API isn't free:
- **Free tier**: 1,500 posts/month, but requires credits (pay-as-you-go)
- **Basic tier**: $100/month for higher limits
- You need to create a Developer account and app at [developer.x.com](https://developer.x.com)

## Installation

Copy the skill to your Clawdbot skills directory:

```bash
cp -r x-api ~/.clawdbot/skills/
cd ~/.clawdbot/skills/x-api/scripts
npm install
```

## Setup

### 1. Get API Credentials

1. Go to https://developer.x.com/en/portal/dashboard
2. Create a Project and App
3. Set App permissions to **Read and Write**
4. Generate keys from "Keys and tokens" tab

### 2. Configure Credentials

**Option A: Environment variables**
```bash
export X_API_KEY="your-api-key"
export X_API_SECRET="your-api-secret"
export X_ACCESS_TOKEN="your-access-token"
export X_ACCESS_SECRET="your-access-token-secret"
```

**Option B: Config file** at `~/.clawdbot/secrets/x-api.json`
```json
{
  "consumerKey": "your-api-key",
  "consumerSecret": "your-api-secret",
  "accessToken": "your-access-token",
  "accessTokenSecret": "your-access-token-secret"
}
```

## Usage

```bash
node ~/.clawdbot/skills/x-api/scripts/x-post.mjs "Your tweet text here"
```

Multi-line tweets work too:
```bash
node ~/.clawdbot/skills/x-api/scripts/x-post.mjs "Line one

Line two

Line three"
```

## Recommended Setup

| Task | Tool |
|------|------|
| **Reading** (timeline, mentions, search) | [bird CLI](https://github.com/steipete/bird) — free, cookie-based |
| **Posting** | This skill — official API, paid |

## License

MIT

---

Built by [Lobster General Intelligence](https://github.com/lobstergeneralintelligence) 🦞


path: scripts/package.json
content: {
  "name": "x-api-scripts",
  "version": "1.0.0",
  "type": "module",
  "dependencies": {
    "twitter-api-v2": "^1.19.0"
  }
}


path: scripts/x-post.mjs
content: #!/usr/bin/env node
// Post to X using official API (OAuth 1.0a)
// Credentials: env vars (X_API_KEY, etc.) or ~/.clawdbot/secrets/x-api.json

import { TwitterApi } from 'twitter-api-v2';
import { readFileSync, existsSync } from 'fs';
import { homedir } from 'os';
import { join } from 'path';

// Load credentials from env vars or config file
function loadCredentials() {
  // Try environment variables first
  if (process.env.X_API_KEY && process.env.X_ACCESS_TOKEN) {
    return {
      consumerKey: process.env.X_API_KEY,
      consumerSecret: process.env.X_API_SECRET,
      accessToken: process.env.X_ACCESS_TOKEN,
      accessTokenSecret: process.env.X_ACCESS_SECRET,
    };
  }

  // Fall back to config file
  const configPaths = [
    join(homedir(), '.clawdbot', 'secrets', 'x-api.json'),
    join(process.cwd(), '.x-api.json'),
  ];

  for (const configPath of configPaths) {
    if (existsSync(configPath)) {
      try {
        return JSON.parse(readFileSync(configPath, 'utf8'));
      } catch (e) {
        console.error(`❌ Failed to parse ${configPath}:`, e.message);
      }
    }
  }

  return null;
}

const credentials = loadCredentials();

if (!credentials) {
  console.error(`❌ No credentials found.

Set environment variables:
  export X_API_KEY="..."
  export X_API_SECRET="..."
  export X_ACCESS_TOKEN="..."
  export X_ACCESS_SECRET="..."

Or create ~/.clawdbot/secrets/x-api.json:
  {
    "consumerKey": "...",
    "consumerSecret": "...",
    "accessToken": "...",
    "accessTokenSecret": "..."
  }
`);
  process.exit(1);
}

const client = new TwitterApi({
  appKey: credentials.consumerKey,
  appSecret: credentials.consumerSecret,
  accessToken: credentials.accessToken,
  accessSecret: credentials.accessTokenSecret,
});

const text = process.argv.slice(2).join(' ');

if (!text) {
  console.error('Usage: x-post <tweet text>');
  process.exit(1);
}

try {
  const { data } = await client.v2.tweet(text);
  // Get username from the access token (first part before the dash is user ID)
  const userId = credentials.accessToken.split('-')[0];
  console.log(`✅ Posted: https://x.com/i/status/${data.id}`);
} catch (err) {
  console.error('❌ Failed:', err.message);
  if (err.data) console.error(JSON.stringify(err.data, null, 2));
  process.exit(1);
}


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)