YOUR BRAND. YOUR VOICE. YOUR STUDIO.
Extudio is a local-first content studio for X/Twitter that you configure for your brand.
Define your voice, terminology, and strategy in a single brand.json file — every AI prompt, content suggestion, and tone check reflects your brand. No accounts. No SaaS. No vendor lock-in.
If you want a personal, brand-aware content studio that feels fast, local, and completely yours, this is it.
Getting Started · Features · Brand Config · Project Docs
Runtime: Bun (package manager + runtime).
Node: 20+ (.nvmrc included).
git clone https://github.com/owklama/extudio.git
cd extudio
bun install
bun run devOpen localhost:5173. The onboarding wizard walks you through brand setup on first run.
- Bun — package manager
- AI text provider — one of:
- Local CLI (no keys, nothing leaves your machine): Claude CLI,
codex,opencode, orgeminiCLI - API key (configured in Settings): Anthropic, OpenAI, OpenRouter, DeepSeek, xAI, or Perplexity
- Local CLI (no keys, nothing leaves your machine): Claude CLI,
- Optional: OpenAI API key — for image generation via GPT Image 1
- Optional: Gemini API key — for image generation via Nano Banana (Gemini)
- Optional: fal.ai API key — for image generation via FLUX Pro 1.1 / FLUX Schnell
- Optional: X Developer App — for posting directly to X
cp .env.example .env
# Fill in your keys.env holds the X OAuth app and optional image-provider keys. Text-generation providers (CLI or API) are picked in Settings at runtime.
- Overview Dashboard — welcome screen with content status and quick-action cards to jump into any workflow.
- Compose Wizard — step-by-step AI tweet/thread editor with full brand context injection.
- Kanban Queue — 4-column drag-and-drop pipeline (Draft → Ready → Scheduled → Posted) via @dnd-kit.
- Calendar Grid — weekly schedule view with configurable posting slots.
- X-Faithful Preview — pixel-accurate tweet rendering at desktop, tablet, and mobile sizes.
- Article Wizard — long-form X article generation with audience, angle, and depth controls.
- Brand Dashboard — live overview of your glossary, tone guide, pillars, SEO keywords, and messaging — all editable in-app.
- Tweet Bank — pre-written tweet library with search, filtering, batch operations, and AI variations.
- AI Chat — multi-turn brand-aware chat with structured outputs (tables, suggestions, actionable insights).
- Reply Generator — paste a tweet URL, fetch the original, and generate brand-tone replies in CEO, Brand, or Casual voice.
- Image Studio — AI-generated visuals with 8 art styles, 5 aspect ratios, and multiple formats via OpenAI, Gemini, or fal (FLUX).
- Profile & Stats — content analytics dashboard with category distribution, pillar coverage, and schedule overview.
- X Integration — connect your X account via OAuth 2.0 and post directly from the app.
- Bring your own AI — swap between local CLIs (Claude, Codex, OpenCode, Gemini) and direct APIs (Anthropic, OpenAI, OpenRouter, DeepSeek, xAI, Perplexity). CLI mode keeps everything on your machine.
flowchart TB
brand["brand.json<br/>brand config + tweet bank"]
statefile["data/studio-data.json<br/>persisted studio state"]
chats["data/chat-sessions/*.json<br/>saved chat history"]
tokens[".x-tokens.json<br/>X OAuth tokens"]
local["localStorage<br/>fast boot cache"]
subgraph Browser["Browser — React SPA"]
views["13 views + app shell<br/>Compose, Queue, Calendar, Article, Brand, Preview, Overview, Settings, Reply, Bank, Profile, Imagine, Chat"]
store["StudioProvider<br/>global state + hydration"]
engine["Content engine + prompt builders<br/>brand-aware text generation"]
end
subgraph Server["Vite dev-server middleware"]
brandapi["/api/brand<br/>/api/brand-tweets"]
stateapi["/api/state"]
gen["/api/generate<br/>SSE streaming"]
chatapi["/api/chat-sessions"]
img["/api/generate-image<br/>/api/generate-cover"]
xapi["/api/x/*"]
end
subgraph Providers["Execution targets"]
cli["Local AI CLIs<br/>Claude Code · Codex · OpenCode · Gemini"]
textapi["Text APIs<br/>Anthropic · OpenAI · OpenRouter · DeepSeek · xAI · Perplexity"]
imgapi["Image APIs<br/>OpenAI · Gemini"]
xext["X API<br/>OAuth 2.0 + posting"]
end
brand -->|"imported via src/config/brand.ts"| views
views --> brandapi
brandapi <--> brand
views --> store
store <--> local
store <--> stateapi
stateapi <--> statefile
views --> engine
engine --> gen
gen -. "SSE stream" .-> views
gen --> cli
gen --> textapi
views --> chatapi
chatapi <--> chats
views --> img
img --> imgapi
views --> xapi
xapi <--> tokens
xapi <--> xext
brand.json is imported directly into the app via src/config/brand.ts, while runtime brand edits go through the Vite middleware at src/server/brand.ts. Studio state hydrates from data/studio-data.json through /api/state and is mirrored to localStorage for fast boot. Text generation runs through src/server/claude.ts: CLI mode stays local, API mode streams from the configured provider, and responses come back over Server-Sent Events.
Everything brand-specific lives in one file: brand.json at the project root.
Edit it and the entire app adapts — AI prompts, tone, content categories, glossary, tweet bank, and UI labels. The more context you provide, the better the AI matches your brand.
Full brand.json reference
| Section | What it controls |
|---|---|
app |
App name, localStorage keys, default X handle and display name |
brand |
Name, URL, tagline, positioning, audience, features, trust signals |
glossary |
Terms and plain-language definitions — AI uses these to simplify jargon |
contentPillars |
Your content strategy themes that guide AI generation |
tweetCategories |
Categories with accent colors for organizing tweet cards |
toneGuide |
Brand voice description + do/don't rules for AI tone |
contentPatterns |
Templates for social hooks, CTAs, hero copy, feature copy |
seoKeywords |
Keywords the AI weaves into generated content |
audienceSegments |
Target personas with motivations and blockers |
brandDifferentiators |
What makes you different — injected into AI prompts |
brandMessages |
Core messaging lanes with bullet points |
categoryPlaybooks |
Per-category mission, themes, proof points, and CTAs |
brandKit |
Personality traits, word lists, trust lines, social bios, headlines |
topicAngles |
Content angles: myth-busting, how-to, comparison, deep-dive, etc. |
tweets |
Pre-written tweet bank for reference and reuse |
Minimal brand.json to get started
{
"app": {
"name": "My Studio",
"storageKey": "my-studio",
"themeStorageKey": "my-studio-theme",
"exportFilename": "my-studio-backup.json",
"defaultHandle": "my_handle",
"defaultDisplayName": "My Brand",
"defaultAvatarUrl": "/favicon.ico"
},
"brand": {
"name": "My Brand",
"tagline": "Your tagline here",
"oneLiner": "What you do in one sentence",
"positioning": "How you're positioned in the market",
"problem": "The problem you solve",
"solution": "How you solve it",
"url": "https://yourbrand.com",
"platforms": [],
"features": [],
"trustSignals": [],
"audience": "Your target audience"
},
"glossary": [],
"contentPillars": [],
"tweetCategories": [
{ "id": "education", "label": "Education", "color": "#6ee7b7" },
{ "id": "discovery", "label": "Discovery", "color": "#67e8f9" },
{ "id": "data", "label": "Data / Tips", "color": "#fbbf24" },
{ "id": "engagement", "label": "Engagement", "color": "#c084fc" }
],
"toneGuide": { "voice": "Your brand voice", "do": [], "dont": [] }
}| Command | Description |
|---|---|
bun run dev |
Start dev server with HMR |
bun run build |
Production build |
bun run preview |
Preview production build |
bun run lint |
Run ESLint |
bun run test |
Run tests (Vitest) |
bun run format |
Format with Prettier |
bun run format:check |
Check formatting |
bun run storybook |
Start Storybook on localhost:6006 |
bun run build-storybook |
Build static Storybook to storybook-static/ |
The full UI stack is documented in Storybook — primitives in components/ui, tweet
rendering, foundations (colors, typography), and shared utilities. Stories live in
src/stories/ and the config is in .storybook/.
bun run storybookComponents that depend on the global studio store (sidebar, app-background, modals, view shells) are intentionally not storied — they only make sense inside the running app.
| Contributing | Security | Code of Conduct | License |
Contributing
Contributions are welcome.
- Read CONTRIBUTING.md for setup, workflow, and PR expectations.
- Run
bun run lint,npx tsc --noEmit,bun run test, andbun run buildbefore opening a PR. - Use the pull request template in .github/PULL_REQUEST_TEMPLATE.md.
Security
- Report vulnerabilities privately via SECURITY.md.
- Do not open public GitHub issues for exploitable security problems.
- Security contact:
security@extudio.dev
Code of Conduct
- Community expectations live in CODE_OF_CONDUCT.md.
- The project uses the Contributor Covenant.
- Report conduct issues privately to
security@extudio.dev.
License
- Extudio is released under the MIT License.
- Free to use, modify, and distribute — including for commercial purposes.