Skip to content

Part 3 · AI Content Generation

Now quill earns its name. In Part 3 the blog grows a writing assistant: ask it for a draft, a title, a summary, or tags, and watch the text stream into the editor as it’s generated. The base playbook’s askr called the Claude API from a CLI; here you do it from a server — which changes everything, because now the AI call is on a request path shared by many users, costs real money per token, and can fail slowly. Production AI is less about the prompt and more about the plumbing around the prompt.

editor ──POST /api/posts/{id}/draft──► quill ──HTTPS (stream)──► Claude API
▲ │ │
└──────── SSE: tokens as they arrive ────┘◄──── streamed tokens ──────┘
long jobs ──► worker (queue + retries)
  • Server-side generation: a Rust module that calls the Claude API with reqwest, with prompts for drafting, titling, summarizing, and tagging a post.
  • Streaming end-to-end: the model’s tokens flow over the SSE pipe you built in Part 2, so the writer sees text appear live instead of staring at a spinner.
  • Background jobs: longer generations run as async tasks off the request path, with retries, timeouts, and idempotency — so a slow model never ties up a web worker.
  • Guardrails & cost control: input limits, output caps, per-user rate limits, and a cache so the same request never pays twice.

Why this is a systems problem, not a prompt problem

Section titled “Why this is a systems problem, not a prompt problem”
Naive CLI approachWhat production forces
block until the full responsestream tokens; free the worker
one call, hope it workstimeouts, retries, circuit-breaking
ignore costtoken accounting, caps, caching
trust the inputvalidate size, strip injection, rate-limit
ChTitleYou addThe idea it teaches
1Calling Claude from the serverreqwest client, prompts, typed responsesserver-side API clients, secrets, structured output
2Streaming to the editormodel stream → SSE → browserwiring two streams, partial output, cancellation
3Background jobsa worker binary, a queue, retriesdecoupling the request path, idempotency, timeouts
4Guardrails & costrate limits, caps, response cacheprotecting a paid, abusable endpoint

Once it compiles, what does it take to run for real users? Part 3’s answer: treat every external call as hostile and expensive. The Claude API is fast and reliable — and you still design as if it will be slow, fail, and cost money, because at scale it eventually does all three. That mindset — timeouts, retries, caching, back-pressure — is the same whether the dependency is an LLM, a payment processor, or another team’s service.

Next: Part 4 · Production Infra →