Public
Auto-generates weekly permit blog posts for ConstructPermits.com
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.

Permit Blogs — Auto-Generated Blog Engine

Automated blog post generator for constructpermits.com/permit-blogs.

How It Works

  1. generate.ts (interval/cron) — Fires daily, randomly skips ~50% of days for an organic every-other-day cadence. Uses Claude to generate a blog post in Chase Morrow's voice, auto-selects relevant images (hero + 2 inline), and stores everything in blob storage.

  2. api-list.ts (HTTP) — Returns paginated blog index with hero images. Supports ?limit=N&offset=N. Posts include category for tab filtering.

  3. api-post.ts (HTTP) — Returns a single full blog post by slug (/slug or ?slug=slug). Includes hero image, inline images embedded in markdown, and full metadata.

  4. shared/config.ts — System prompt, rotating category prompts (7-week cycle), TypeScript types.

  5. shared/images.ts — Curated Unsplash image library with keyword-based matching. Auto-selects contextually relevant hero and inline images per post.

Blog Categories (match website tabs)

CategoryDescription
Statutory EnforcementPermit dispute war stories with statute citations
Building DepartmentBehavioral patterns across FL jurisdictions
Statute Deep-DivePlain-English breakdowns of specific statutes
Common MistakesCostly errors expediters/contractors make
Legislative UpdateHB 683 and other recent FL legislation
Private ProviderTactical guidance on private provider workflows
Contractor AdviceWhat your permit expediter wishes you knew

Images

Every post includes:

  • Hero image — wide banner at top of post, returned in both list and post APIs as heroImage: { url, alt }
  • 2 inline images — embedded in the markdown content at logical section breaks, also returned as inlineImages[]

Images are auto-selected from a curated Unsplash library based on the post's category, tags, and Claude-provided imageHints.

API Endpoints

  • List: GET /{ posts[], total, limit, offset, hasMore }
  • Post: GET /slug → full BlogPost object

Environment Variables

KeyDescription
ANTHROPIC_API_KEYClaude API key for blog generation

Force a Post

To trigger a post outside the normal schedule:

import { blob } from "https://esm.town/v/std/blob"; await blob.set("blog-force-post", "1");

Then wait for the next cron tick, or manually run generate.ts.