← 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,
  };
}