PorchlightAgency Site Engine
What it does for you
Fill in one form, get a full agency website.
One intake form becomes a full, SEO-ready, compliance-checked home care agency website; a CSV of agencies becomes one ZIP per agency.

Who it's for
Small non-medical home care agencies that need a full website without writing every page by hand. It can also build one site per row of a spreadsheet, for someone setting up several agencies.
Screenshots



In more detail
Porchlight turns one intake form into a complete website for a small non-medical home care agency: a home page, one page per service, one page per town, a careers page with an application form, an FAQ, and a contact page. Feed it a spreadsheet of agencies and it builds one finished site per row. Every site gets audited for search basics, accessibility, and copy that stays away from medical claims.
Honest limits
The optional Claude polish call was never made live; no key was used, by design. The downloaded ZIPs were not opened on a real host. The forms post by mailto, so there is no real form backend.
How I built it
This was on the Claude Code list on the tandem day with Codex. I set the scope (a product, not one landing page), the niche rules (non-medical, no clinical claims, license lines only when a number exists), and the order: pure core, then 100+ tests, then server, then UI. Claude Code wrote 25 core modules, 14 test parts, and the UI modules, including a hand-rolled ZIP writer and reader, the structured-data builders, and the audit.
The problem with cheap templates is that every town page says the same paragraph. So town copy comes from copy banks with staggered sizes (7, 6, 5, 8, 5, 7), which means towns rarely share the same combination of variants. Then we measured it instead of assuming it: 3-word shingles and a Jaccard distance score between every pair of town pages, with a test that fails below 60%. The demo's worst pair scores 84%.
Claude verified the UI by loading the app in headless Chrome inside a throwaway page that typed into the intake, clicked links in the preview, and ran the batch. No clicks were done by hand.
Every file went out in writes under about 4 KB because the API connection kept dropping long responses. That forced small modules, which made the code easier to test anyway.
What I learned
- Near-duplicate pages are measurable. Shingles plus Jaccard gave me a number I could put in a test and show as a heatmap, which beats "the copy looks different enough."
- A compliance linter has to watch its own boilerplate. The default disclaimer and FAQ had to be worded so the linter would not flag the agency's own safety language, and every catalog and copy-bank string is now linted in a test.
- Relative links pointing at
index.htmllet one link format serve the exported ZIP, the preview's click routing, and the orphan-page check. - Screenshots catch what tests miss. They showed service names in odd casing ("alzheimer's") mid-sentence and breadcrumbs stuck to the edge, both missed by 245 tests.
- A unicode escape typed into a write landed as a literal em dash, so a test now scans every file for them.
What carried forward
It follows the sprint's pattern of pure core first, tests second, UI last, with small ui-*.js modules. One side effect on naming: #80 was first going to be called Porchlight too, and it was renamed to Trellis to avoid clashing with this one. With builders running in parallel, app names needed checking like everything else.
If I took it further
I would add a real form backend option and publish-to-host straight from batch mode.
#079 Built with Claude Code September 23, 2026 245 automated checks