Ship a blog in one prompt

Engineering

Most SDK documentation is written for a human reading it at 2pm on a Tuesday. Increasingly the first reader is a coding assistant, and it has a different problem: it needs to be certain, and prose does not make it certain.

We used to solve this by publishing the entire SDK reference as a single plain-text file for an assistant to fetch in one go. It was a reasonable idea that aged badly. A flat dump of prose is still prose — the assistant reads it, compresses it, and a few hundred lines later writes a method name that was never in the file. And a document maintained alongside the code drifts from the code, which is the one failure a reference cannot afford.

Two things replaced it, and both are stricter.

The types are the reference

@kookee/sdk ships TypeScript declarations. Install the package and the reference is on disk, in the assistant's context, in a form it cannot misremember:

Bash
npm install @kookee/sdk

Now the prompt is short, because the precision lives in the types rather than the prompt:

Build a blog with the @kookee/sdk package, which is already installed. A listing page (/blog) with tag filtering, search and pagination, and a detail page (/blog/:slug) with rendered HTML content and emoji reactions. Next.js App Router, fetching in server components. Read the key from process.env.KOOKEE_API_KEY.

The assistant writes kookee.blog.list({ page, limit, tags, search, locale }) because that is the signature, not because it recalled a paragraph. And when we change a method, the declarations change in the same release — there is no second artifact to forget to update. That was the actual argument against the text file: it could be wrong, and a reference that can be wrong is worse than no reference, because it is trusted.

The response shape it writes against is the one you get:

TypeScript
const response = await kookee.blog.list({ page: 1, limit: 10, tags: ['engineering'] });

response.data;       // BlogEntryListItem[]
response.total;      // 25
response.totalPages; // 3

If you would rather drop in ready-made pages than generate them, @kookee/react ships server-rendered blog components: see Build a blog with the React components.

The content is the other half

Types tell an assistant what it can call. They say nothing about what is in your project — and half of the mistakes in a first integration come from that gap: a category slug that does not exist, a field the code never reads, an empty page that turns out to be an empty project.

So connect the assistant to the real thing:

Bash
claude mcp add --transport http kookee https://api.kookee.dev/api/mcp \
  --header "Authorization: Bearer $KOOKEE_MCP_TOKEN"

Now the prompt changes character. "Build a changelog page" becomes:

Read my changelog entries, then build a page that renders them the way they are actually structured.

And it does read them. It finds that the release type lives in a fields array rather than on the entry, that two entries have no version set, that your categories are named one way and your tags another. The page it writes matches your data instead of a generic example — and it can write back, so the first thing it notices being missing, it can fix.

What you still need

  1. A Kookee project with at least one published post. An empty project produces an empty page, and that is hard to tell apart from a bug.

  2. An API key from Connect → API keys for the application. It only reaches published content, so it is safe in a client bundle.

  3. A personal MCP token from Connect → MCP server, if you want the assistant reading your real content. Read only is enough for that. Keep it out of your code all the same — it reads your drafts.

Beyond the blog

The same shape works for each surface:

Build a help center with category navigation, semantic search and article pages.

Build a changelog page grouped by release type, with emoji reactions.

Build them one at a time. Three at once produces a diff nobody reviews carefully, which is how a plausible bug ships.

The through-line: stop asking an assistant to remember your API, and give it something that cannot be misremembered. The types, and the data itself.