← back to Abrams
scripts/swot-gen.js
277 lines
#!/usr/bin/env node
// swot-gen.js — generates one fresh SWOT per tick across all projects.
// Round-robins through projects.json so coverage builds out over hours.
// No external API calls — uses heuristics + Steve's catalog patterns.
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '..');
const PROJECTS = path.join(ROOT, 'data', 'projects.json');
const IDEAS = path.join(ROOT, 'data', 'ideas.json');
const LOG = path.join(ROOT, 'data', 'build-log.jsonl');
const log = (type, payload) => fs.appendFileSync(LOG, JSON.stringify({ ts: new Date().toISOString(), type, ...payload }) + '\n');
const read = (p, fb) => { try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch { return fb; } };
const projects = read(PROJECTS, { projects: [] }).projects || [];
const ideas = read(IDEAS, { ideas: [] });
const existing = new Set((ideas.ideas || []).map(i => i.slug));
// Pick first project that doesn't have a SWOT yet
const target = projects.find(p => !existing.has(p.slug)) || projects[Math.floor(Math.random() * projects.length)];
if (!target) { console.log('no projects to SWOT yet'); process.exit(0); }
const swot = buildSwot(target);
const idea = {
slug: target.slug,
name: target.name,
tagline: swot.tagline,
summary: swot.summary,
stage: target.status === 'live' ? 'live' : (target.status === 'dev' ? 'dev' : 'idea'),
category: target.category || 'misc',
domain: target.domain || null,
port: target.port || null,
strengths: swot.strengths,
weaknesses: swot.weaknesses,
opportunities: swot.opportunities,
threats: swot.threats,
revenue_lines: swot.revenue,
competitive_moat: swot.moat,
next_3_moves: swot.next3,
generated_at: new Date().toISOString(),
};
ideas.ideas = (ideas.ideas || []).filter(i => i.slug !== target.slug);
ideas.ideas.push(idea);
ideas.updated_at = new Date().toISOString();
ideas.count = ideas.ideas.length;
fs.writeFileSync(IDEAS, JSON.stringify(ideas, null, 2));
log('swot', { slug: target.slug, name: target.name });
console.log(`SWOT generated for ${target.name} → ${ideas.ideas.length} ideas total`);
// ─── heuristic SWOT builder (per-category templates) ───
function buildSwot(p) {
const cat = p.category || 'misc';
const base = {
'panel': {
tagline: 'One screen for the empire.',
strengths: [
'Only umbrella view across every Abrams asset — competitors run isolated dashboards.',
'Live SSE build log = transparency-as-marketing (Bloomberg Terminal vibe).',
'Lead capture happens on the highest-trust surface (the founder umbrella).',
'Sort + density + Gucci chrome — same UX language as the rest of the DW fleet so users move freely.',
],
weaknesses: [
'Single founder. Bus-factor 1.',
'No multi-tenant story yet — every visitor sees Steve\'s personal dashboard.',
'Trademark not yet registered → competitors could squat ABRAMS in adjacent classes.',
],
opportunities: [
'Sell white-label "Panel" SaaS to other multi-domain operators ($299/mo).',
'Pitch deck for VC — "I built a 20-vertical conglomerate, here\'s the live operating system."',
'Acquisition vehicle — every new project automatically tiles in.',
'Press story — "the indie operator with a Bloomberg terminal of his own businesses."',
],
threats: [
'Notion / Airtable could rebuild this as a template in a weekend.',
'If hourly-email cron leaks PII, ops trust evaporates.',
'pm2 process death = panel goes dark = customers think empire is dead.',
],
revenue: [
'White-label Panel SaaS — $299/mo × 50 operators = $179k ARR.',
'Sponsored project tiles — $500/mo per slot × 8 slots = $48k ARR.',
'Lead-routing fees — 10% of any partnership closed via /api/lead.',
],
moat: 'Network effects from cross-linking every Abrams property + the founder-brand halo. Bloomberg\'s moat isn\'t the terminal, it\'s the fact every Wall Street person already has one.',
next3: [
'Wire pm2-keep-alive watchdog (panel must never go dark).',
'Add LinkedIn OAuth on /api/lead so we know who\'s knocking.',
'Ship Stripe checkout at /api/subscribe for white-label SaaS waitlist.',
],
},
'media': {
tagline: 'Distribution before product.',
strengths: [
'Drudge-style aggregator (Abrams Report) is a 1-person operation that scales linearly with curation, not engineering.',
'mp3 / video assets compound over time — every file added grows the moat.',
'Curation = taste = irreplaceable by AI.',
],
weaknesses: [
'No newsletter / no email capture loop yet — readers leave and never return.',
'Pure-aggregator legal risk (hotlinking, scraped headlines).',
'No revenue model wired in.',
],
opportunities: [
'Sponsored "slot" on the Report front page — $200-$2000/week (Drudge does $35k/wk).',
'Premium newsletter — top 20 design-industry stories curated weekly, $15/mo.',
'Original commentary track on top of curation — converts media to publisher.',
'Audio version (mp3.agentabrams.com) — turn each daily report into a 4-min podcast.',
],
threats: [
'Source sites block the scraper.',
'X/Bluesky kills RSS access (already happening on Reddit).',
'AI summary engines (Perplexity, Arc Max) eat the click-through layer.',
],
revenue: [
'1 sponsored slot × 4 weeks × $500 = $2k/month.',
'500 premium newsletter subs × $15 = $7.5k/month.',
'Affiliate links on design products = $1-2k/month at modest volume.',
],
moat: 'Curator-brand + first-mover in the design-industry aggregator niche. Drudge\'s moat is exactly this — taste + trust.',
next3: [
'Add ConvertKit/Beehiiv newsletter capture above-the-fold on Abrams Report.',
'License agreements with top 5 source sites (or robots.txt-allowed scrape).',
'Generate Daily Brief audio via clone-voice → mp3.agentabrams.com.',
],
},
'household-os': {
tagline: 'Your house is a portfolio. Manage it.',
strengths: [
'No competitor owns "household rights" as a category — Quicken/YNAB do money, no one does warranties + recalls + receipts as one graph.',
'Gmail-connector is a high-trust on-ramp — once connected, retention is sticky.',
'AI-extractable receipts from email = zero data-entry UX.',
],
weaknesses: [
'Single-user local app — no SaaS revenue path yet.',
'Recall feeds are scattered (NHTSA, CPSC, FDA) — integration burden is high.',
'Trust required: connecting Gmail is a big ask.',
],
opportunities: [
'Insurance partnership — link AbramsOS recall data to home/auto policy holders ($5/user/month from insurer).',
'Class-action sniper — surface eligible class actions from receipt data (15% of payouts, $50-500/user/year).',
'Estate / probate tool — when a parent dies, AbramsOS exports the household graph for executors.',
'B2B for landlords / property managers — track warranties across 50 units.',
],
threats: [
'Google could ship this as a Gmail feature in 18 months.',
'Privacy backlash on Gmail-scoped OAuth.',
'A bad recall miss (e.g. an unsafe car seat) creates legal liability.',
],
revenue: [
'Freemium → $9/mo Pro × 5000 = $540k ARR at year 2.',
'Insurance partnership rev share = $5 × 10k users = $600k/year.',
'Class-action commission = highly variable, $0-$2M/yr.',
],
moat: 'First-mover + Gmail trust + AI extraction quality. Network effect via household sharing.',
next3: [
'Ship Stripe billing on AbramsOS — Pro tier at $9/mo.',
'Add NHTSA + CPSC recall feed ingestion.',
'Land 1 insurance pilot partner (Lemonade, Hippo, Branch).',
],
},
'directory': {
tagline: 'Pay-to-be-found beats SEO every time.',
strengths: [
'Already #1 on Google for some long-tail "California bar attorney {practice}" queries.',
'Lawyer-directory pattern fork-able to doctor / NPH / restaurants / animals — every vertical has the same shape.',
'No content liability — directory data sourced from public bar records.',
],
weaknesses: [
'Free directory = low monetization until claim-flow ships.',
'Bar §6155 compliance gate (CA-specific) — small operator risk.',
'Cold-start problem: no traffic on day 1 of a new vertical.',
],
opportunities: [
'Claim-flow at $49/mo per listing → 1% claim of 50k attorneys = $25k MRR.',
'Lead-routing add-on — pay $X per qualified lead routed to a claimed listing.',
'Multi-vertical SaaS — license the directory engine to other states / verticals.',
],
threats: [
'State bar rule changes (§6155 in CA).',
'Avvo / Martindale / Justia spend > Steve.',
'Yelp-style hostage extortion accusations if review policy isn\'t clean.',
],
revenue: [
'Claim flow @ $49/mo × 500 claims = $24.5k MRR.',
'Sponsored listings (top-of-search) @ $199/mo × 100 = $20k MRR.',
'Lead routing fee = $20/qualified lead × 2000/month = $40k/month.',
],
moat: 'Long-tail SEO + claim-flow inertia. Once 500 lawyers pay $49/mo, switching cost is real.',
next3: [
'Wire Stripe-claim button on every lawyer profile.',
'Generate 50 city-pair sitemaps (e.g. "{city} {practice} attorneys") for SEO.',
'Pilot doctor / NPH version with the same engine.',
],
},
'umbrella': {
tagline: 'Build in public is the cheapest marketing.',
strengths: [
'Founder-brand consolidation — one URL, every signal.',
'Existing audience (memo signups, newsletter, LinkedIn).',
'Content-as-asset: every shipped project becomes a post.',
],
weaknesses: [
'Build-in-public can leak strategy to competitors.',
'No tier-up path for the audience (no membership, no Slack).',
],
opportunities: [
'Paid community (Circle / Slack) at $20/mo.',
'Sponsored-update slots on the public timeline.',
'Cohort-based course on multi-vertical operator playbook.',
],
threats: [
'Twitter/LinkedIn algorithm change kills distribution.',
'Audience burns out on yet-another-build-in-public founder.',
],
revenue: [
'Community @ $20/mo × 500 = $10k MRR.',
'Course @ $500 × 50 students/cohort × 4 cohorts/yr = $100k/yr.',
'Sponsorships @ $1000/post × 4/month = $4k MRR.',
],
moat: 'Personal brand. Inexpensively cloneable in form, structurally impossible to clone in trust.',
next3: [
'Launch private Slack at agentabrams.com/community.',
'Convert 6 best build-in-public posts into a paid mini-course.',
'Schedule weekly Friday-recap email.',
],
},
'saas': {
tagline: 'Charge from day one.',
strengths: [
'Butlr already has Twilio + ElevenLabs integration shipped.',
'AI-dialer category has no dominant winner yet.',
'Founder is the target user — feedback loop is fast.',
],
weaknesses: [
'Compliance burden (TCPA, AI-disclosure preamble per FCC Feb-2024).',
'Twilio + ElevenLabs costs eat margin without pricing power.',
],
opportunities: [
'B2B small-business tier — every dentist / restaurant / clinic needs hold-time recovery.',
'White-label for property managers, law firms.',
'Marketplace of pre-built "personas" (sweet abuela, stern attorney, friendly receptionist).',
],
threats: [
'Twilio own Conversations product launches AI version.',
'TCPA suit from a bad dial.',
'ElevenLabs price hike (already happened once).',
],
revenue: [
'Solo @ $19/mo × 1000 = $19k MRR.',
'Pro @ $99/mo × 200 = $20k MRR.',
'Enterprise @ $999/mo × 20 = $20k MRR.',
],
moat: 'Compliance moat (the call-once rule, DNC scrub, disclosure preamble) — bigger competitors can\'t move as fast on the legal side.',
next3: [
'Ship Stripe pricing page at butlr.agentabrams.com/pricing.',
'Add call-once-per-person rule to public docs (compliance moat).',
'Pitch first 10 dental offices / hair salons in Encino.',
],
},
};
const tpl = base[cat] || base['panel'];
return {
tagline: tpl.tagline,
summary: `${p.name} — ${p.description?.slice(0, 200) || 'no description'}\n\n${tpl.tagline}`,
strengths: tpl.strengths,
weaknesses: tpl.weaknesses,
opportunities: tpl.opportunities,
threats: tpl.threats,
revenue: tpl.revenue,
moat: tpl.moat,
next3: tpl.next3,
};
}