Architecture — v0.1 Companion to the requirements sketch

A folder, not an app

The lightest thing that satisfies the requirements is one directory on your laptop: a SQLite file, a folder of prompts, a folder of generated sites, and Claude Code as the only runtime. No server, no database service, no dashboard, no framework. Everything that looks like an application is a static HTML file generated on demand and thrown away.

The load-bearing decision: Claude Code is the application. Not a thing that helps you build the application — the thing that runs it. Every module below is a prompt file and a skill, not a service. That is what makes "no code, no hires, free" achievable rather than aspirational.

Which Claude does what

Short answer: Claude Code runs the whole pipeline unattended and fills the site and deck templates. Claude Design builds those templates — and makes the ad creative, every day. Code is the factory, Design is the workshop, and the factory calls the workshop nightly: it leaves an ad brief per prospect and waits for the creative to come back.

Claude Design — here, 15 minutes a day

Everything that needs taste: the templates, the deck design, the approval screen, these documents — and the ads, every day. Session-based by nature; it cannot be woken by a cron job, so it becomes a station you visit rather than a step that runs.

The daily loop: Code leaves the night's ad briefs in briefs/. You paste them here, I build the real creative, you drop the file back. Fifteen minutes.

Claude Code — nightly, alone

Everything else, because it is the only one with a filesystem, a database, a browser, git and a clock. Finds prospects, resolves decision makers, researches, scores, writes messages, fills the templates, publishes, sends, logs replies.

It generates the sites and decks by pouring content into templates you approved — those are structural, so filling them is safe. It does not make the ads. It writes the brief: ten angles from the research, five formats each, the competitor evidence. The creative is made here.

Why the ads are the exception. A landing page has a template that fixes its layout — Code fills it and the result looks made, because your WOWCube prompt pins the section order, the DOM and the persuasion mechanics and lets only brand and copy move. Fifty ads have no such skeleton: each one is a layout decision, and fifty layout decisions made unattended look like fifty generated images. That is why the ads come here, and why fifteen minutes a day is the right price for the single most visible artefact in the set.

The whole thing

outreach/ ├── outreach.db one SQLite file — the entire state of the system ├── prompts/ your templates: landing page · ad base · deck · messages ├── skills/ the pipeline steps, one markdown file each ├── profile.md who I am — read by every step ├── sites/ │ └── acmecorp/ generated: index.html · ads/ · deck.html ├── review/ generated approval page, regenerated on demand └── run.sh cron entry point

That is the deployable surface. sites/ is what gets deployed to Cloudflare, and a local git repository for its own history; everything else never leaves the machine.

Five layers

1

Store — one SQLite file

Six tables and nothing else: company, person, opportunity (pool, hiring status, score), artifact (what was generated, where it lives, approved or not), message (sent, channel, hook used), event (replies, opens, role closed). Insaight already writes into SQLite, so this extends what exists rather than replacing it. One file means backup is a copy and there is no service to pay for.

2

Collectors — insaight, plus four small ones

Insaight is not an input to this system — it is layers 1 through 3 already built. Its 18 MCP tools and 8 skills are the store, the LinkedIn collector and the research skills, MIT-licensed, local, already writing into SQLite. Everything else here extends its schema rather than standing beside it: Meta Ad Library read straight off its public web page — no developer account, no API key, no ID check, job boards for the hiring flag, a plain fetch of the company's own site, and email discovery. Collectors only append rows — if one breaks, everything downstream still runs on yesterday's data.

3

Skills — the pipeline, as markdown

One file per step: qualify (score against profile.md, assign a pool) · find-decision-maker · research · make-site · make-ads · make-deck · write-messages. Each reads the store, does one job, writes back. Editing the system means editing a paragraph of English — which is what "I can change it by chatting" actually reduces to.

4

Review — one generated page, one keystroke

A static HTML file built from the store: one prospect per card, showing the message, the site preview, the ad sheet and the deck side by side. Approve, reject, or type a note and regenerate. It writes decisions to a local file the next run reads — no server, no login, no hosting. Regenerated fresh each session and disposable.

5

Publish — wrangler is the deploy

Claude Code deploys each approved folder to Cloudflare Pages directly through wrangler, Cloudflare's CLI — no GitHub, no CI workflow, no build step. A wildcard *.danilovicioso.com record maps each folder to its subdomain. Git still runs locally as version history; it just isn't in the deploy path. Approval and publication are the same act.

Why publishing stays on your own domain

Design tools stop at producing the code, and the one-click publish they offer puts the page on their own sandboxed URL under an "unverified content" banner. That banner is deliberate — it is how a public-publishing button in an AI tool avoids becoming a phishing kit. It is also fatal here: a prospect opening their own landing page under a third-party warning strip is worse than never receiving the link.

This system's shape makes that sharper. A hundred and fifty generated pages reproducing other companies' branding, published unattended, used for cold outreach — that is a profile any hosting provider's abuse team reads twice, however genuine the intent. Somebody else's platform can pull all of it because one recipient complained.

What your own domain buys
No banner and no third-party chrome · a URL that reads as yours, which is the entire persuasive move · no kill switch outside your control · free, on infrastructure you already have.
What it costs
You own the accountability. Every page carries noindex, uses only public material, and never claims to be the company's own site — that is your discipline to keep, not a platform's to enforce.

Finding email without paying

Vendors charge per lookup because they sell coverage and confidence. At 150 addresses over weeks — not 150,000 — you can buy neither and still land most of them. Run these in order and stop at the first hit.

#MethodHit rate
1Just look. Team pages, press releases, contact pages, conference bios, podcast show notes, PDFs on their own domain~20%
2Public commit history — anyone technical has leaked a real address into a git log~10%, near-certain when it hits
3Site-wide search for the domain pattern to learn the company's format, then apply it to the name~30%
4Generate the eight standard patterns and verify by MX lookup plus SMTP handshake~20%
5Free vendor tiers as the last resort, ~25 lookups a month each, rotatedthe remainder

The catch, stated plainly. Google and Microsoft no longer answer SMTP verification honestly, so step 4 gives you a plausible guess, not a verified address. The real verifier is the first send — and every bounce now lands on nilovicioso@gmail.com, a real aged inbox whose reputation you are relying on. So: keep guessed-pattern addresses to two or three of the day's thirty sends, and drop an address after one bounce rather than working through the other seven patterns. Expect 65–75% coverage free against 90% paid, and treat the missing quarter as LinkedIn-only prospects.

Pools E and F invert this: legacy and owner-operated businesses publish a real address on their own contact page, so step 1 alone covers most of them. The hard pool is C, where everyone is on Google Workspace behind a catch-all.

Sending — email

Fully automatable and genuinely free. nilovicioso@gmail.com is the sender — an aged, real, human-looking inbox, forwarding replies to where you actually read. No domain to buy, no SPF/DKIM to configure, no three-week warm-up: at this volume an old Gmail outperforms a new domain, because the thing that gets filtered is newness.

Setup, five minutes
Turn on forwarding from nilovicioso@gmail.com to your main inbox, and generate an app password so the machine can send and poll. That is the whole configuration, and it costs nothing.
The ceiling
Under ~30 a day, human-shaped gaps, never a burst, never the same body twice. Google tolerates low-volume personal mail and suspends anything that looks bulk — crossing that line costs the inbox, not just the campaign.
Replies close the loop
The same API polls the inbox, matches replies to the message row by thread, classifies them and writes an event. That is what turns "which hooks get replies" from a guess into a number — and it needs no extra service.
Where I stay in the loop
A real reply stops all automation for that prospect immediately. The machine opens conversations; it never holds one.

Sending — LinkedIn

This is the one place I would not fully automate, and the reason is not squeamishness. LinkedIn detects and restricts automation aggressively, and the account it would restrict is the same account that carries your professional identity, your Tabs history and every warm connection you have. There is no second one.

What I'd build instead — a loaded gun, not a robot. The machine prepares everything: the right person, the connection note, the follow-up, in order, in a queue. It opens each profile in your own logged-in browser with the note already written. You press send.

Twenty-five of those is about eight minutes a day. That is the entire manual cost of the system — and it sits comfortably inside the single-approve constraint, because approving the package and firing the queue are the same sitting.

ActionSafe ceilingNote
Connection requests~20/day, 100/weekLinkedIn enforces a weekly invite cap regardless of pacing
Messages to connections~50/dayFar more headroom than invites; the bottleneck is who accepts
Profile views~100/dayFree and useful — a view before a request measurably lifts acceptance
Withdraw stale invitesWeeklyPending invites count against the cap; clear anything over 21 days

If you decide the risk is acceptable later, the same queue can drive the browser directly with human-paced timing — the architecture doesn't change, only who presses the key. Start with your hand on it.

What actually runs, and when

CadenceJobTouches me
NightlyCollectors refresh: new roles, filled roles, new ads, new postsNo
NightlyRe-score the pool, top it back up to 100 opportunitiesNo
NightlyGenerate the site and deck; write the ad brief for each prospectNo
Daily, ~15 minBuild the day's ad creative in Claude Design, drop it back inYes
When I sit downRebuild the review page; approve or reject a queue in one passYes
On approveCommit and push the site; queue the email; load the LinkedIn queueNo
Daily, ~8 minFire the LinkedIn queue by hand — 20 invites, notes pre-writtenYes
DailySend 20–30 emails on human-shaped intervals; poll for repliesNo
ContinuousLog replies and outcomes back to the storeNo

Cost, honestly

PieceCostNote
SQLite, git, cronFreeAlready on the machine
Cloudflare Pages + wildcard DNSFreeUnlimited sites on the free tier; domain already owned
Meta Ad LibraryFreeRead off the public page directly — no developer account needed
Claude CodeSubscription you haveNot incremental, but it is the real dependency
InsaightFreeMIT, local, no telemetry — the largest single piece, already built
LinkedIn scraping (Apify)PaidReplaceable with a logged-in browser session; slower, more fragile
Email findingFreeThe five-step cascade, at ~70% coverage instead of 90%
Email sending + reply trackingFreenilovicioso@gmail.com, forwarded — no domain, no warm-up
LinkedIn sendingFreeQueued by the machine, fired by hand — 8 minutes a day

Apify is now the only paid line, and it is dodgeable. A logged-in browser session can do the fetching itself — slower and more fragile than paying, and the single remaining place the "free" constraint actually costs anything. Everything else on this list is genuinely zero.

Day zero — the part nobody automates

Yes. A system that runs itself still has to be handed its keys, and no amount of architecture avoids that. The honest number is about ninety minutes of clicking, plus the two hours that actually matter — and with the Gmail sender and no Meta developer account, nothing on this list has a waiting period. After that it never repeats.

The split is clean: you do anything that requires being you — a password, a payment, a consent screen, an ID upload. I do everything else, including all the configuration on the far side of each login.

#What you do by handTimePainful?
1Forward nilovicioso@gmail.com to your main inbox, generate an app password5 minNo
2Cloudflare: wildcard record on danilovicioso.com, connect Pages to the repo30 minNo
3Log into LinkedIn in a dedicated browser profile the machine can reuse15 minNo
4Install insaight, decide Apify key vs. browser-session fallback20 minNo
5Drop the templates into prompts/ — landing page, ad base, deck, message voice10 minDone already
6Write profile.md — your background, wins, numbers, what you want1–2 hrsThe real work

Step 9 is the only one that matters. Everything else is plumbing you do once and forget. profile.md is read by every scoring pass, every hook, every deck and every message — a thin version of it produces a thin machine, forever. Spend the two hours. I can interview you through it if that's easier than writing it cold.

Nothing here blocks anything else. With no domain to warm and no ID check to clear, the list can be done in any order, in one sitting.

Credentials live in one local file and never leave the machine — the same local-first posture insaight already takes. Nothing here is a subscription you have to remember to cancel.

What I deliberately left out

Where this breaks

Architecture — v0.1 Internal working document