A self-hosted marketing department for one local service business: a Content Factory gated by a Brand Brain, a Speed-to-Lead responder that books at night, ads rebuilt weekly under your cap, a 90-day publishing gate, attribution where every number is a link, and one Director running it each morning.
What you build
| Part | What it is | What it does |
|---|---|---|
| Eyes | A Next.js ops-center dashboard, dark, dense, ledger-style numbers | Marketing Director, Content Factory, Paid Demand, Speed-to-Lead, Radar, Local SEO, Publishing, Attribution, Brand Brain, Calendar. Four KPI cards per page, each with a plain-language subtitle. |
| Brain | Claude Code, then an LLM through OpenRouter or Ollama | Claude builds it. The runtime model drafts content, extracts fields from a lead's message, and writes the morning note behind a fallback chain and a validator that rejects any claim not in the data. |
| Memory | Postgres, about thirty tables, money in cents | Brand Brain, pieces, leads, conversations, slots, campaigns, change orders, signals, keywords, reviews, publish queue, attribution events, runs, approvals. Five guards live in Postgres, not the UI. |
| The gate | A deterministic claims gate over every generated sentence | Banned phrases, prices, promises and credentials are held unless the exact claim is on the owner's approved list. The UI shows the sentence and the rule. The model cannot add a claim. |
| Nervous system | One intake door, one event bus, one socket pattern for the outside world | POST /api/leads/submit takes every future channel in one shape. Ads, social, GBP and senders are sockets: CSV in, signed webhook out, nothing counts as done until the outside system confirms back. |
| The human boundary | Hold / Approve on everything that leaves the building | Offers, prices, promises, budget changes above your cap and every post inside a channel's 90-day gate wait for a click. Speed-to-Lead replies only from approved templates. No auto-approve exists. |
Where this comes from
Structure Webworks published "How a Local Business Runs Marketing With AI Agents": a marketing department for one home-services company where a Marketing Director sits over seven modules — a Content Factory, a Paid Demand Engine, a Speed-to-Lead responder, a Market Signal Radar, Local SEO & Listings, a Publishing Engine, and Attribution & Reporting — and stops at the gates. The link is in the files box. It is a good map. The part worth copying exactly is the set of gates: nothing publishes unapproved for the first ninety days on a channel, budget changes above the cap are held, and any sentence that sounds like a guarantee or a price waits for the owner.
Their article says fourteen modules replaced three salaries and two retainers. Nobody here has measured that, so this pack does not repeat it, and the dashboard it builds has no "saved vs the old team" card. What it builds instead is the honest version of the same shape: deterministic code does the gathering, one LLM call writes the sentences, a validator throws out any line that cites a piece, a campaign or an amount that is not in the data, and the Brand Brain is a table in Postgres with a gate in front of it — not a paragraph in a prompt.
What you build
When it runs, it feels like a marketing manager who read every review, every lead and every campaign before you got in. The Content Factory writes the week from a brief and the Brand Brain; any sentence with a guarantee, a price or a credential the owner never approved is held, and the screen shows you the sentence. A form fills at 11:40 on a Sunday; Speed-to-Lead qualifies the job, the address, the timeline and the insurance using replies assembled only from templates you approved, and books a tentative inspection into a slot you opened. The moment someone asks "how much", it stops and hands off to you. The Paid Demand Engine proposes on Monday, monitors on Wednesday and proposes kills on Friday, with the arithmetic in every proposal, and Postgres refuses to approve anything that crosses your weekly cap.
Then the Director runs six stages every morning and leaves a "Waiting on you" list with Hold and Approve on each line, and a note whose every number opens into the rows that made it. The one thing it deliberately does not do: publish, spend, or promise on its own. There is no setting for that, a script fails the build if a column named auto_approve ever appears, and the prompts tell Claude not to add one.
Do you need this? Be honest first
If you run a one-person trade and your marketing is a Google Business Profile you update when you remember, you do not need seven modules; you need to reply to your reviews. This is for the local service business — roofing, HVAC, plumbing, remodeling, cleaning, landscaping — with enough lead flow that nights and weekends are being lost, where ad spend is a number nobody can tie to a booked job, and where the owner is the only person who knows what the company is allowed to promise. It is also for the builder who wants to sell that business a system it owns instead of a retainer.
You are building software that drafts marketing, not a licence to say anything. The approved-claims list starts nearly empty on purpose. What a platform allows and what advertising rules apply where you are is the business's call and its advisers' job. If you are not comfortable saying that to a client, close the tab.
What you need
Pick the machine first:
| Option | Good for | Runtime model |
|---|---|---|
| Any laptop — Windows with WSL, Mac, or Linux with Omarchy | Learning and building | OpenRouter free models |
| A Mac mini with 64 GB or more | Running it in the office with local AI; customer data never leaves | Ollama with qwen3:32b or llama3.3:70b |
| A small VPS | Reachable from anywhere, awake at 11:40 on a Sunday | OpenRouter |
Every option needs Claude Code logged in (Pro, Max or Team), Docker, Node and git. The
pack assumes none of them are installed: the setup guide starts at "open a terminal"
(or install one — Windows Terminal, Tabby, PuTTY, Terminal.app, or Super + Return on
Omarchy) and ends when claude, docker and node all answer. It covers the
OpenRouter account (free models first, $10 of credit when the note goes to a real
owner), Ollama on a 64 GB Mac, and a VPS if you go that way. No ad-platform keys, no
social tokens, no Google Business Profile access: every outside platform is a socket in
this lesson, and demo mode ships a fake one that confirms by itself. Nothing of the
author's is in it; every credential is yours.
The setup guide is one HTML file you open in a browser. Every command has a copy button, every step has a checkbox, and a progress bar at the top shows how far along you are. Your progress is saved in that browser.
What is in the zip
local-marketing-os/
README.md the document: what, why, hosting, the accounts, the folder map
index.html the clickable setup guide with all fourteen prompts (same as the browser link above)
COSTS.md every cost, with the date it was read
CREDITS.md where the idea comes from, the as-is notice, what was verified, terms
paths/ one README per platform: Windows WSL2, Mac Apple Silicon, Linux Omarchy
prompts/ 00-project-brief ... 13-tests-and-smoke
assets/ the cover art
What was verified and what was not
This pack is distributed as is, as a proof of concept. The setup guide was opened in a real browser and driven by a script on 2026-08-30: the three platform tabs, the progress bar, the checkboxes, the saved progress, and the copy buttons all work — including from a downloaded file, where the modern clipboard API silently fails and the guide falls back to the older method. The install commands are the current official ones for WSL, Homebrew, Docker, nvm, pacman and Claude Code as of that date; they were not executed end to end on three fresh machines for this release.
The fourteen prompts were written against a reviewed design, read twice by a separate model session for contradictions and missing steps, and have not been run as a sequence. Every prompt ends with a "how you know it worked" check that you can see without reading code — Postgres refusing to approve a held sentence, the dispatcher sitting still on a gated channel, the engine refusing to spend past your cap. Prompt 13 makes Claude break the code on purpose to prove the tests can fail. If a prompt breaks on your machine, paste the full error into Claude Code and ask it to fix it, then post what broke and the platform in the community.
Read the prompt before you run it
Hand each prompt to Claude first and ask what it plans to build. Compare that to what the prompt says. A prompt costs a minute to fix. A wrong build costs an afternoon.



