Markdown · llms.txt

Tweet generator in your voice

tweet-factory is a local private tweet generator and an AI tweet generator that writes in one account’s voice. It is a Bun and TypeScript CLI, tf. All rights reserved. Source: abhirupghosh/tweet-factory. It runs on the machine where you install it. Likes, bookmarks, and your posts go into tweets.db. Drafts go into drafts/. You publish them yourself. Local files stay the default. Optional cloud sync copies that checkout only after tf login and tf sync push.

People also search “AI tweet writer” and “AI tweet generator that sounds like me.” Those match this CLI only because the voice comes from your own posts and the model is one you already run. It is not a hosted scheduler, and it is not a claim that the drafts will rank. Claude Code is the default backend; the setup is on Using tweet-factory with Claude Code.

Where the voice comes from

src/prompts/voice.ts builds the system prompt from two files of your data:

  • persona/PERSONA.md, if it exists. The comment in that module calls it the source of truth for voice. tf onboard can write it. You can also edit the template.
  • Measured stats from tweets.db: the share of posts that start lowercase, the median word count, recurring markers, and the accounts you engage with most.

The instruction in that prompt is to match casing, length, phrasing, and stance, and not to flatten the voice into generic copy. Notion pages you tag, and the flush of new likes and bookmarks, can be attached as fenced reference data. The prompt tells the model that text is data, not instructions.

If there is no persona file yet, the same function says to infer voice from the measured signals.

Claude Code, or another provider

The default provider is claude-code. src/llm/claudecode.ts spawns:

claude -p <prompt> --output-format json --tools "" --disallowedTools "*,mcp__*" --permission-mode dontAsk

No API key is read for that path. It uses the claude login already on the machine. --tools "" removes built-in tools, so a tweet in the reference data cannot make it run a shell. If claude is not on PATH, the error tells you to install Claude Code or set TF_LLM_PROVIDER and a key.

The other providers, from src/llm/provider.ts:

TF_LLM_PROVIDERKeyDefault model in code
claude-codenonethe CLI’s own default
anthropicANTHROPIC_API_KEYclaude-sonnet-4-6
openrouterOPENROUTER_API_KEYanthropic/claude-sonnet-4.6
openaiOPENAI_API_KEYgpt-4o

Direct API calls use temperature 0.8. Claude Code gets a 240 second timeout. More on the LLM providers page.

What it will not do

OAuth scopes in src/x/auth.ts are tweet.read, users.read, like.read, bookmark.read, and offline.access. There is no write scope and no command that creates a post. tf notify posts a file to Slack when a webhook is set. Publishing on X is a step you take outside tf.

The 0–100 number on a draft is computed after the model returns text. src/rank/score.ts multiplies an editorial strength on each head by the published weight in src/rank/weights.ts (x-algorithm commit cb45b55). It is a local heuristic, not a live For You rank. How scoring works has the formula, the four-idea shape, and the calibration rules.

Install the release binary from Install. A checkout can still build with ./setup_x.sh. A coding agent can follow the runbook.

FAQ

What is a tweet generator that uses my own posts?

tf generate is that generator. It sends persona/PERSONA.md and measured stats from tweets.db to your LLM and writes four ideas, each with two or three variants, to drafts/YYYY-MM-DD.md. The 0–100 number is filled in locally after the model returns text. You post the variant you want.

Is there a private tweet generator that runs on your machine?

tweet-factory is proprietary. All rights reserved. Source is at github.com/abhirupghosh/tweet-factory. tf fetch stores your X activity in SQLite on that machine. tf generate writes drafts to drafts/YYYY-MM-DD.md. Nothing in the CLI creates an X post.

Can Claude Code write the tweets?

Yes, as the default backend. tf runs claude -p with your existing Claude Code login and with tools disabled. Set TF_LLM_PROVIDER to anthropic, openrouter, or openai if you want a direct API instead. You still publish the draft yourself.

Will the drafts sound like me and rank on For You?

The voice prompt is your persona file plus stats from your own posts, likes, and bookmarks. That is a writing constraint. The score beside a draft is the local per-head heuristic in src/rank/score.ts, using the published weights, with a calibration from your impressions when at least eight of your posts have them. The open-source ranker is a different system, described on the algorithm page. This CLI does not execute it.