Building VibeBlaster
Automating Side Project Launches from Idea to Marketing
The Problem: Death by a Thousand Manual Tasks
As a serial side-project builder, I found myself trapped in a frustrating cycle. Every new idea followed the same tedious pattern:
- Research the market using ChatGPT (copy-paste, manual prompting)
- Brainstorm domain names, check availability one by one
- Register domain on Namecheap
- Point nameservers to DigitalOcean
- Create DNS records manually
- Set up Amazon SES for transactional emails
- Configure Microsoft 365 email alias
- Generate marketing content for each platform
- Schedule and post across Twitter, LinkedIn, Instagram, Facebook, Reddit
- Track engagement metrics manually
This process took 2-3 hours per project before I even wrote a single line of product code. I was building 5-10 side projects simultaneously, which meant spending 15-30 hours on infrastructure and marketing instead of building features.
I needed automation. Not just for one piece—for the entire workflow.
The Vision: A Local-First Automation Platform
I set out to build VibeBlaster: an Electron desktop app that would orchestrate every step of launching and marketing side projects. The core principles:
Local-First Architecture
All data lives on my machine. No cloud sync, no SaaS subscriptions. SQLite handles persistence, JSON stores workflows.
Multi-Project Support
Manage multiple projects simultaneously with isolated contexts—separate credentials, strategies, calendars.
Intelligent Automation
AI-powered workflows that understand context, remember previous posts, maintain brand voice consistency.
External Services as Tools
OpenAI, Namecheap, DigitalOcean, AWS SES, social platform APIs—orchestrated while keeping user data local.
The Tech Stack: Choosing the Right Tools
Electron + React + TypeScript
Desktop app requirements demanded Electron. React provides a familiar component model, TypeScript catches errors before runtime. The multi-process architecture (main process, renderer process, preload script) requires discipline—I'll get to that.
SQLite with better-sqlite3
PostgreSQL would be overkill for a local app. SQLite is perfect: single file database, zero configuration, excellent TypeScript support via better-sqlite3. The synchronous API is actually an advantage—no async/await ceremony for simple queries.
Vite for Build Pipeline
Electron Forge + Vite provides hot reload during development and optimized production builds. Three separate Vite configs handle main process, renderer process, and preload script compilation. Fast builds, small bundles.
shadcn/ui + Tailwind CSS
I didn't want to build UI components from scratch. shadcn/ui provides accessible, customizable components built on Radix UI primitives. Tailwind for styling—utility classes keep everything consistent without writing custom CSS.
OpenAI SDK (GPT-5 + GPT-Image-1)
Content generation is the heart of the system. OpenAI's GPT-5 handles text generation with advanced reasoning capabilities, while GPT-Image-1 generates high-quality images for social posts. The challenge: maintaining context across multiple calls while staying within token limits.
The Architecture: Multi-Process Coordination
Electron's security model enforces process isolation:
- Main Process: Node.js environment, runs
main.ts, manages app lifecycle and windows - Renderer Process: Browser environment, runs React UI, can't access Node APIs directly
- Preload Script: Sandboxed bridge, exposes safe IPC channels to renderer
IPC Communication Pattern
Every feature follows a strict IPC contract:
// Renderer → Main
window.api.projects.create({ name, description, domain })
// Main → Renderer (with progress events)
window.api.workflows.onDomainSetupProgress((progress) => {
console.log(`Step ${progress.currentStep}: ${progress.status}`)
})This keeps the renderer isolated while enabling the main process to call external APIs, manipulate files, and manage credentials securely.
Service Layer Architecture
The main process is organized into 60+ service modules, each responsible for a single integration or workflow:
- ProjectService: CRUD operations for projects
- OpenAIService: Chat completions and image generation with usage tracking
- NamecheapService: Domain availability checks and registration
- DigitalOceanService: DNS zone and record management
- AWSSESService: Email domain setup and verification
- TwitterService: OAuth, posting, engagement metrics via Twitter API v2
- LinkedInService: OAuth, posting, article publishing
- RedditService: OAuth, subreddit posting, comment threads
- GhostService: Blog CMS integration with Kubernetes deployment automation
- AnalyticsService: Cross-platform engagement tracking and aggregation
Each service is a failure boundary—if Twitter's API is down, LinkedIn posting continues unaffected.
The Database Pattern That Saved My Sanity
SQLite has one critical limitation: file-level locking. Multiple connections cause "database is locked" errors. The solution: singleton connection pattern.
I spent hours debugging mysterious database locks before codifying this rule:
// ALWAYS do this
import { getDatabase, generateId } from '../database/connection';
const db = getDatabase();
// NEVER do this
import Database from 'better-sqlite3';
const db = new Database(path); // BREAKS EVERYTHINGEvery service imports the singleton. One connection, zero lock conflicts. This pattern is now documented prominently in the project's AI instructions—I never want to debug that again.
The OpenAI Integration: Context-Aware Content Generation
Content generation isn't just "write a Twitter post." It requires:
- Project context: What is this product? Who's the target audience?
- Marketing strategy: Brand voice, messaging pillars, content themes
- Content history: Previous posts to avoid repetition
- Platform constraints: Twitter's 280 characters, LinkedIn's article format, Instagram's visual focus
The Prompt Engineering Challenge
I built a MarketingStrategyService that generates a comprehensive strategy document on project creation:
const strategy = await openai.chat.completions.create({
model: 'gpt-5',
messages: [
{ role: 'system', content: 'You are a marketing strategist...' },
{
role: 'user',
content: `Project: ${project.name}
Description: ${project.description}
Generate a comprehensive marketing strategy...`
}
]
})Then, every content generation call references this strategy:
const twitterPost = await openai.chat.completions.create({
messages: [
{ role: 'system', content: strategy.brandVoice },
{
role: 'user',
content: `Previous posts: ${recentPosts.join('\\n\\n')}
Generate a new Twitter thread announcing feature X`
}
]
})This keeps all content cohesive while avoiding repetitive AI-generated slop.
Cost Tracking: Every API Call Logged
OpenAI isn't free. I wrapped every API call with withTrackedAPICall() to log usage with project ID, operation, duration, model used, and token counts. Now I have a full audit trail of AI spend per project.
The Domain Setup Workflow: Orchestrating 5 APIs
Registering a domain and configuring email involves multiple external services. The workflow:
- Namecheap: Check availability → register domain → set nameservers to DigitalOcean
- DigitalOcean: Create DNS zone → add A/AAAA records
- Amazon SES: Register domain → fetch verification DNS records → add to DigitalOcean DNS → wait for verification
- Microsoft 365: Add domain as alias (via Graph API or manual instructions)
Each step can fail independently. The WorkflowStepService tracks progress with status (pending, running, completed, failed) and metadata. Progress events stream back to the UI via IPC so users see real-time updates.
The Social Media Challenge: OAuth in an Electron App
OAuth flows expect web browsers with localhost redirects. Electron desktop apps break this assumption.
Twitter's OAuth 2.0 PKCE Flow
Twitter deprecated OAuth 1.0a in favor of OAuth 2.0 with PKCE (Proof Key for Code Exchange). The standard flow redirects to http://localhost:3000/callback, but Electron can't reliably listen on port 3000—another app might be using it.
Solution: Custom protocol handler
I registered vibeblaster:// as a custom protocol:
// In main.ts
app.setAsDefaultProtocolClient('vibeblaster')
// Authorization URL redirects to vibeblaster://callback?code=...
const authUrl = `https://twitter.com/i/oauth2/authorize?${params}&redirect_uri=${encodeURIComponent('vibeblaster://callback')}`
// Listen for protocol URLs
app.on('open-url', async (event, url) => {
if (url.startsWith('vibeblaster://callback')) {
const code = extractCode(url)
await exchangeCodeForToken(code)
}
})When Twitter redirects to vibeblaster://callback, macOS/Windows routes it directly to the app. No localhost needed. LinkedIn, Meta, and Reddit follow similar patterns with platform-specific quirks.
The Ghost CMS Integration: Kubernetes Deployment Automation
I wanted blog content hosted on Ghost CMS, not WordPress. But Ghost requires MySQL, persistent storage, and HTTPS ingress. Manually deploying Ghost to Kubernetes for each project would defeat the automation purpose.
Solution: BlogInfrastructureService
This service generates Kubernetes manifests and deploys Ghost automatically:
async deployBlog(projectId: string, domain: string) {
const namespace = `blog-${domain.replace('.', '-')}`
// Generate MySQL StatefulSet with persistent volume
const mysqlManifest = this.generateMySQLManifest(namespace)
await kubectl.apply(mysqlManifest)
// Wait for MySQL to be ready
await this.waitForPodReady(namespace, 'app=mysql')
// Generate Ghost Deployment
const ghostManifest = this.generateGhostManifest(namespace, domain)
await kubectl.apply(ghostManifest)
// Create Ingress with Let's Encrypt TLS
const ingressManifest = this.generateIngressManifest(namespace, domain)
await kubectl.apply(ingressManifest)
}One button click in the UI deploys a fully functional Ghost blog with TLS certificates. The GhostService then publishes blog posts via Ghost's Admin API.
The Challenges and Trade-Offs
1. The Async State Management Nightmare
Electron's IPC is asynchronous. React's state is synchronous. This mismatch creates race conditions. I standardized on cleanup functions in useEffect hooks to prevent state updates after component unmounts.
2. The Token Context Window Problem
GPT-5 has a 128K token context window. Feeding entire marketing strategies + 50 previous posts blows past this limit. I implemented sliding window context: only the 10 most recent posts are included. Older posts contribute to the marketing strategy document, not individual content generation calls.
3. The OAuth Token Expiration Dance
Access tokens expire. Refresh tokens sometimes expire. Users switch projects mid-OAuth flow. The CredentialService handles all of this with automatic refresh token exchange before every API call. Zero expired token errors in production.
4. The Rate Limit Gauntlet
Every platform has different rate limits (Twitter: 50 tweets per 24 hours, LinkedIn: 100 API calls per day, Reddit: 60 requests per minute). I built a RateLimitService with per-platform buckets that checks limits before publishing and reschedules if exceeded.
Inside VibeBlaster: A Visual Tour
Multi-Project Command Center
The Global Dashboard provides real-time visibility across all projects—tracking AI costs, engagement metrics, agent activity, and posting queues from a single interface.

Automated Domain Setup Workflow
Watch as VibeBlaster orchestrates Namecheap, DigitalOcean, AWS SES, and Microsoft 365—turning hours of manual configuration into minutes of automated execution.

Marketing Strategy Planning
AI-generated strategies with content ideas, timelines, and execution tracking.

Content Calendar
Schedule posts across all platforms with visual calendar and status tracking.

Social Media Monitoring & Auto-Responses
The Twitter Agent monitors mentions, generates context-aware responses with GPT-5, and queues them for approval—maintaining authentic engagement at scale.

Unified Inbox
All social mentions and comments aggregated in one place.

Analytics Dashboard
Track engagement, performance, and trends across all platforms.

Posting Queue
Monitor and manage the automated publishing pipeline.

AI-Powered Asset Generation
Generate complete brand asset libraries using GPT-Image-1—logos, social media images, and profile graphics in every size and format.

AI Cost Tracking
Every OpenAI call logged with tokens, cost, duration, and model—full transparency and budget control.

Platform API Monitoring
Monitor all external API calls, rate limits, and success rates across social platforms.

Content & Campaign Management
Manage blog campaigns and social posts from a unified interface—see what's published, scheduled, or in draft across all platforms.

The Results: Hours to Minutes
Before VibeBlaster
- • Domain setup: 45 minutes
- • Content generation: 90 minutes
- • Scheduling: 30 minutes
- Total: 2.75 hours per project per week
After VibeBlaster
- • Domain setup: 5 minutes
- • Content generation: 10 minutes
- • Scheduling: 2 minutes
- Total: 17 minutes per project per week
That's a 90% time reduction. With 5 active projects, I save 13+ hours per week.
The Developer Experience Lessons
1. Codify Your Patterns Early
The database singleton pattern should have been documented on day one. Instead, I rewrote the same bug fix in 5 different services. Now the project has strict architectural rules documented for AI assistants.
2. IPC Contracts Are Your API Spec
I treated IPC channels like REST APIs—documented contracts with request/response schemas, error conditions, and progress event payloads. This prevented mismatches between main and renderer processes.
3. Progress Indicators Change Everything
Long-running operations without feedback feel broken. I added progress events to every workflow. Users now understand the system is working, even when operations take 30+ seconds.
4. Security by Default, Not as an Afterthought
Electron's safeStorage API encrypts credentials using OS keychains (Keychain on macOS, Credential Vault on Windows). I used this from the start. API keys never touch the filesystem in plaintext.
What I'd Do Differently
- Start with TypeScript Strict Mode: I enabled
strict: trueafter writing 10,000 lines of code. The refactor took days. - Build the Admin Interface First: I hacked together UIs as needed. Starting with the admin UI would have clarified data models earlier.
- Add E2E Tests for Critical Workflows: Manual testing works for solo projects, but critical workflows need automated tests. Playwright supports Electron.
- Consider a Hybrid Architecture: All-local works great for solo use. But for selling, I'd need cloud sync. Starting with local-first + optional cloud sync would future-proof the architecture.
Technical Highlights
Conclusion: Build Tools for Yourself
VibeBlaster started as a personal productivity tool. It's now 58,000+ lines of TypeScript orchestrating a dozen external services. I use it every day to launch and market side projects.
The lesson: build tools for problems you actually have. I knew every pain point intimately because I lived them. The requirements spec practically wrote itself.
If you're drowning in manual workflows, consider building your own automation. Desktop apps aren't dead—they're perfect for local-first, privacy-focused tools that integrate with external APIs.
VibeBlaster proves that a solo developer can build sophisticated automation in a few weeks. The tech stack matters less than understanding your own workflow deeply.
Now, instead of spending hours on infrastructure and marketing, I spend them building features. That's the whole point.
Tech Stack Summary
Frontend: React 18, TypeScript, shadcn/ui, Tailwind CSS, React Router
Backend: Electron 33, Node.js, better-sqlite3, Vite
External APIs: OpenAI (GPT-5, GPT-Image-1), Namecheap, DigitalOcean, AWS SES, Twitter v2, LinkedIn, Meta Graph, Reddit, Ghost Admin API
Infrastructure: Kubernetes (DigitalOcean), Ghost CMS, MySQL 8.0
Security: Electron safeStorage, OAuth 2.0 PKCE, encrypted credentials
Want to Build Something Amazing Together?
If you're looking for an engineer who can architect complex systems, automate workflows, and ship production-ready software, let's talk.
Get in Touch