How OpenTwins Works: Architecture Deep Dive
A technical walkthrough of the systems behind OpenTwins. How agents decide what to engage with, how browser automation works and how everything connects.
- OpenTwins is an open-source Node.js application that orchestrates AI-powered social media engagement using Claude, browser automation and a configurable scheduler.
- Each platform gets its own agent instance running a loop of feed scanning, post scoring, comment generation, browser execution and action logging.
- Browser automation uses Chrome CDP with semantic element targeting rather than fragile CSS selectors, making it resilient to platform UI changes.
- The identity system builds a voice profile from 10-20 real writing samples, capturing vocabulary, sentence structure, tone and opinions.
- Typical daily API costs range from $1-3 for moderate activity across 3-5 platforms, using Haiku for scoring and Sonnet for content generation.
System Overview
OpenTwins is an open-source AI agent platform for social media engagement, built as a self-hosted Node.js application that runs locally on your machine. At its core, it's an orchestrator that coordinates three things: an AI model (Claude) for decision-making and content generation, a browser automation layer for platform interaction and a scheduler that determines when agents should run. Unlike SaaS tools like Buffer or Hootsuite that handle content scheduling, OpenTwins focuses on reactive engagement: reading posts, understanding context and generating original responses in your voice.
The high-level architecture looks like this:
┌─────────────────────────────────────────┐
│ Dashboard (React) │
│ localhost:3847 │
├─────────────────────────────────────────┤
│ Core Orchestrator │
│ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
│ │ Scheduler│ │ Identity │ │ Strategy│ │
│ │ │ │ System │ │ Engine │ │
│ └────┬─────┘ └────┬─────┘ └────┬────┘ │
│ │ │ │ │
│ ┌────▼────────────▼────────────▼────┐ │
│ │ Agent Loop │ │
│ │ (one per platform) │ │
│ └────┬──────────────────────┬───────┘ │
│ │ │ │
│ ┌────▼──────┐ ┌─────▼────────┐ │
│ │ Browser │ │ Claude │ │
│ │ (Chrome CDP)│ │ (API/CLI) │ │
│ └───────────┘ └──────────────┘ │
└─────────────────────────────────────────┘
Everything runs in a single process (with child processes for browser instances). There's no database server, no cloud dependency beyond the Claude API and no Docker required. Configuration lives in ~/.opentwins/ as JSON files.
The Agent Loop
Each platform gets its own agent instance running an identical loop. The loop executes once per configured interval (default: every 60 minutes during active hours). Here's the sequence:
- Wake - the scheduler triggers the agent for this platform
- Feed scan - the browser navigates to the platform feed and extracts visible posts
- Scoring - Claude evaluates each post against the user's content strategy: topic relevance, engagement level, recency, author reputation
- Selection - the top N posts are selected for engagement (N is configurable, default 3-5)
- Generation - for each selected post, Claude generates an appropriate action: comment, like, share or skip
- Execution - the browser performs the action with human-like timing (random delays between keystrokes, natural scroll patterns)
- Logging - every action is recorded with timestamp, platform, post URL, action type and generated content
- Sleep - the agent waits for the next scheduled cycle
The loop is intentionally simple. Complexity lives in the Claude prompts and the browser automation, not in the orchestration logic. This makes it easy to debug: if an agent is misbehaving, you can inspect the prompt that was sent and the response that came back.
Error Handling
Browser automation is inherently fragile. Pages load slowly, elements change position, captchas appear. The agent loop handles this with a layered retry strategy:
- Element not found: Wait 2 seconds, retry once, then skip the action
- Page load timeout: Refresh, wait, retry once
- Captcha detected: Pause the agent, notify the user through the dashboard
- Session expired: Pause the agent, prompt the user to re-authenticate
- Rate limit detected: Back off exponentially, reduce activity for the rest of the day
If an agent encounters 3 consecutive failures, it pauses itself and sends a notification through the dashboard. No silent failures.
Browser Automation Layer
OpenTwins uses Chrome CDP for browser automation. Chrome CDP is an open-source browser control library built on Chromium that provides a higher-level API than raw Playwright or Puppeteer. This is a key architectural difference from tools like Expandi and PhantomBuster, which rely on API-based methods that carry higher detection and account suspension risk.
The key difference between Chrome CDP and traditional browser automation is the abstraction level. Instead of targeting specific CSS selectors (which break whenever a platform updates their UI), Chrome CDP uses a combination of visual recognition and DOM analysis to interact with elements semantically. "Find the comment input field" rather than "find element with class .comment-box-v2__input".
Session Management
When you connect a platform through the OpenTwins setup wizard, the system opens a browser window and lets you log in manually. Your session cookies are then stored locally in an encrypted profile at ~/.opentwins/browsers/. Each platform gets its own browser profile, completely isolated from the others.
~/.opentwins/
browsers/
linkedin/ # LinkedIn browser profile
twitter/ # Twitter browser profile
reddit/ # Reddit browser profile
config.json # Main configuration
identity.json # Your voice and identity settings
logs/ # Action logs
Sessions are reused across agent cycles. When a session expires (typically every few weeks), the agent detects the login page, pauses and notifies you to re-authenticate. Your actual passwords are never stored - only the session cookies.
Human-Like Behavior
Platform detection systems look for behavioral patterns that distinguish bots from humans. OpenTwins incorporates several anti-detection measures:
- Variable typing speed: Characters are typed with random delays between 50-200ms, with occasional "pauses" mid-word that mimic thinking
- Natural scrolling: Pages are scrolled at varying speeds with occasional pauses, not instant jumps to specific elements
- Mouse movement: The cursor moves in natural curves rather than teleporting between elements
- Reading time: Before engaging with a post, the agent "reads" it by pausing for a duration proportional to the post's length
- Session noise: Agents occasionally browse unrelated pages, check notifications or visit profiles without engaging
For a broader discussion of safe automation practices, see our guide on social media automation that doesn't get you banned.
Claude Integration and Prompt Architecture
OpenTwins uses Claude as its "brain." Every decision an agent makes - what to engage with, what to say, whether to skip a post - is made by Claude based on a carefully structured prompt.
The integration supports two modes:
- Claude Code mode: Uses the Claude Code CLI (requires a Claude Code subscription, ~$20/month). The agent spawns Claude Code as a subprocess and communicates through stdin/stdout.
- API mode: Uses the Anthropic API directly (requires API credits). This is the default mode and offers more granular control over model parameters.
Prompt Structure
Every Claude interaction follows a consistent prompt structure:
System prompt:
- Identity context (who the user is, their expertise)
- Voice guidelines (writing style, vocabulary, tone)
- Platform-specific rules (LinkedIn vs Twitter conventions)
- Safety constraints (what not to say, topics to avoid)
User prompt:
- The specific post content being evaluated
- Existing comments (to avoid repetition)
- Action request (score, generate comment, etc.)
- Output format specification (JSON)
The system prompt is assembled once per agent cycle from the user's identity configuration. The user prompt changes for each post. All prompts include a JSON output format specification so responses can be reliably parsed.
Cost Optimization
AI model calls are the primary cost driver. OpenTwins minimizes costs through:
- Batch scoring: Multiple posts are scored in a single Claude call rather than one call per post
- Prompt caching: The system prompt (which includes identity context) is cached across calls within a cycle
- Model selection: Scoring uses Claude Haiku (cheap and fast) while content generation uses Claude Sonnet (better quality)
- Skip early: Posts that clearly don't match the user's topics are filtered before reaching Claude
Typical daily costs range from $1-3 for moderate activity across 3-5 platforms. The dashboard tracks token usage and estimated costs in real time.
The Identity System
The identity system is what makes agent output sound like you rather than generic AI. It's stored in ~/.opentwins/identity.json and includes:
{
"name": "Jane Chen",
"role": "CTO at Acme Corp",
"expertise": [
"distributed systems",
"engineering management",
"developer tools"
],
"voice": {
"tone": "technical but accessible",
"formality": "professional-casual",
"humor": "dry, occasional",
"sentence_length": "medium, varied",
"avoid_words": ["synergy", "leverage", "disrupt"],
"signature_phrases": ["the tricky part is", "in my experience"]
},
"writing_samples": [
"Had a great discussion with the team about...",
"One thing I've learned about scaling..."
],
"opinions": {
"remote_work": "strongly pro, with caveats about async communication",
"ai_in_development": "optimistic but realistic about current limitations",
"microservices": "right tool for the right job, not a default"
}
}
The setup wizard builds this through a conversational interface. You don't need to fill out a JSON file manually. The wizard asks questions like "How would you respond to someone praising microservices for a small startup?" and uses your answers to populate the configuration.
Content Strategy Engine
The content strategy engine determines what agents engage with. It's a scoring system that evaluates posts along multiple dimensions:
- Topic relevance (0-10): How closely does this post match the user's defined topics?
- Engagement potential (0-10): Is this post getting traction? A post with moderate engagement (50-500 likes) is ideal - visible enough to matter but not so popular that your comment gets buried.
- Author value (0-10): Is this someone worth building a relationship with? The system considers follower count, posting frequency and whether the user has engaged with them before.
- Recency (0-10): How old is the post? Commenting on a 2-hour-old post is more valuable than a 2-day-old one.
- Action type fit: Should this be a comment, a like, a share or nothing?
Posts that score above the configured threshold (default: 6.0 out of 10) are selected for engagement. The threshold is adjusted automatically based on feed volume - if there are many high-scoring posts, the bar rises to keep action counts within configured limits.
The Scheduler
The scheduler controls when agents run. It's built around two concepts: active hours and intensity levels.
// Default schedule configuration
{
"timezone": "America/New_York",
"weekdays": {
"activeHours": [
{ "start": "07:00", "end": "09:00", "intensity": "high" },
{ "start": "09:00", "end": "12:00", "intensity": "medium" },
{ "start": "12:00", "end": "14:00", "intensity": "high" },
{ "start": "14:00", "end": "18:00", "intensity": "medium" },
{ "start": "18:00", "end": "21:00", "intensity": "low" }
]
},
"weekends": {
"activeHours": [
{ "start": "09:00", "end": "12:00", "intensity": "low" },
{ "start": "14:00", "end": "17:00", "intensity": "low" }
]
}
}
Intensity levels map to action frequency:
- High: Agent runs every 30 minutes, up to 8 actions per cycle
- Medium: Agent runs every 60 minutes, up to 5 actions per cycle
- Low: Agent runs every 120 minutes, up to 3 actions per cycle
The scheduler adds random jitter (up to 15 minutes) to avoid running at perfectly predictable intervals. It also respects per-platform daily limits, stopping an agent for the day once it hits its configured maximum.
Dashboard Architecture
The dashboard is a React application served at localhost:3847. It communicates with the core orchestrator through a WebSocket connection for real-time updates and a REST API for historical data.
Key dashboard features:
- Live feed: Real-time stream of agent actions as they happen
- Activity log: Searchable history of all actions with full content
- Analytics: Engagement metrics, growth trends, per-platform breakdowns
- Cost tracker: Real-time token usage and estimated API costs
- Agent controls: Start, stop, pause individual agents
- Platform setup: Browser authentication flow for each platform
- Identity editor: Modify voice settings and topic configuration
The dashboard requires no separate installation. It's bundled with the main package and starts automatically when you run opentwins start --ui.
Data Flow and Storage
OpenTwins stores everything locally. No data leaves your machine except for Claude API calls (which send post content and your identity context to Anthropic's API).
Local Storage
- Configuration: JSON files in
~/.opentwins/ - Action logs: SQLite database at
~/.opentwins/logs/actions.db - Browser profiles: Chromium user data directories per platform
- Analytics cache: Computed metrics cached in SQLite for dashboard performance
What Goes to Claude
Every Claude API call sends:
- Your identity configuration (name, role, expertise, voice settings)
- The content of the post being evaluated
- Existing comments on that post (for context)
- The action request (score, generate, etc.)
Claude API calls are subject to Anthropic's data retention policy. If privacy is a concern, you can use Claude Code mode (which routes through your Claude Code subscription) or self-host a compatible model.
Extending OpenTwins
OpenTwins is designed to be extensible. The two most common extension points are:
Adding a New Platform
Each platform is implemented as a module in src/platforms/. A platform module needs to implement four functions:
// src/platforms/my-platform.ts
export interface PlatformModule {
// Navigate to the feed and extract posts
scanFeed(browser: BrowserContext): Promise<Post[]>
// Perform an engagement action
executeAction(browser: BrowserContext, action: Action): Promise<void>
// Check if the session is still valid
checkSession(browser: BrowserContext): Promise<boolean>
// Open the login page for authentication
authenticate(browser: BrowserContext): Promise<void>
}
The platform module handles all platform-specific browser interactions. The core orchestrator, Claude integration and scheduling work identically across all platforms.
Custom Scoring Functions
If the default scoring model doesn't fit your needs, you can register custom scoring functions that run before or after Claude's evaluation:
// ~/.opentwins/plugins/my-scorer.js
module.exports = {
name: 'my-custom-scorer',
score(post) {
// Boost posts from specific authors
if (post.author.followers > 10000) {
return { bonus: 2.0, reason: 'high-follower author' };
}
return { bonus: 0, reason: null };
}
};
Plugins are loaded from ~/.opentwins/plugins/ at startup. They can modify post scores, filter posts before they reach Claude or add post-processing to generated content.
The full source code is available on GitHub. The codebase is TypeScript throughout, with minimal dependencies. If you want to contribute or fork, the README has a development setup guide that gets you running in under 5 minutes.
For a non-technical overview of what OpenTwins can do, check out the main site. For practical usage guides, see our articles on LinkedIn growth with AI agents and AI-powered social media engagement.
Want to try it yourself?
OpenTwins is free, open source and sets up in under 5 minutes.
Get Started with OpenTwins