AI

Turning a book appendix into a prompt library

260 insurance prompts were stuck inside a Kindle book. A 60-line script and two Next.js routes made them a free, searchable library on FixMyPrompt.

Turning a book appendix into a prompt library

I published a Kindle book for insurance agents this month. The appendix has 260 prompts in it, sorted into 20 jobs an agent does every week: renewal calls, claims follow-ups, cross-sell emails, and so on. I spent more time on that appendix than on most of the chapters.

Then it sat inside a book, where nobody can copy and paste from it.

After a week of that bugging me I turned it into a page on FixMyPrompt. Here's how little work that took, and the one thing I got wrong.

The source was already structured

The appendix lives in my repo as a single markdown file. Each section is a heading with the category name and a numbered list of prompts under it. That's close enough to data that I didn't want to retype it or hand-maintain a JSON copy that would drift from the book.

So step one was a 60-line script that reads the markdown, splits on headings, pulls out the numbered items, and writes a TypeScript file:

export interface TemplatePrompt { n: number; text: string }
export const INSURANCE_PROMPTS: Record<string, TemplatePrompt[]> = {
  "renewal-calls": [ { n: 1, text: "..." }, ... ],
  ...
};

The key is the slug for each category. Twenty keys, 260 prompts, all generated. When I revise the appendix for a second edition I rerun the script and the site picks it up.

A second file, written by hand, holds the per-category copy: title, H1, meta description, a short intro, and which scoring goal the category maps to when a prompt gets sent to the grader. I kept that file small on purpose because it's the only part I want to touch manually.

Static pages from a data file

FixMyPrompt is a Next.js App Router site. The library is two routes: an index at /templates/insurance and a dynamic [category] route under it.

The category route runs generateStaticParams over the 20 slugs with dynamicParams = false, so every page builds at deploy time and any slug not in the list returns a 404 instead of an empty shell. Each page gets ItemList JSON-LD, a canonical URL, a breadcrumb, and a related-categories block that picks the two neighbors on either side in the ordered list.

Each prompt is a card with two buttons. Copy puts the text on the clipboard. The second button is the reason I built the page.

Prefilling the grader from a URL

The main tool on FixMyPrompt is /try: paste a prompt, get a score out of 100 and a rewrite. The template cards link into it like this:

/try?prompt=<encoded text>&goal=quality&src=tpl-renewal-calls

On the /try side a small client component reads useSearchParams, checks goal against the allowed values, caps the prompt at 4000 characters, and sets the form state once on mount. It sits inside <Suspense> so the page itself stays static. The src param goes into an analytics event so I can see which categories send people through to a report.

That's the whole integration. The template pages know one URL shape and nothing else about the grader.

What I got wrong

My first pass at the per-category intro copy mentioned things like binding restrictions and ACA subsidies. Sounded right for an insurance audience. None of it was in the appendix. I had written descriptions of prompts that didn't exist.

I caught it by reading every section of the source against every intro, and ended up rewriting 13 of the 20 strings. If you generate site copy from a source document, check the copy against the source and not against what the topic feels like it should say.

Where it landed

Twenty-one new URLs in the sitemap, a free resource that didn't exist the day before, and a path from a book page to a working tool. The book is AI for Insurance Agents if you want to see where the prompts came from. The library is at fixmyprompt.net/templates/insurance.

Adding another industry is one data file and one category file. That was the goal going in and it held up.

Comments

No comments yet. Be the first.

Leave a comment