Anatomy of the Claude prompt that writes this blog
A line-by-line look at the system prompt we use to make Claude write posts that don't sound like Claude. What worked, what didn't, and why the banned-word list keeps growing.
- ↳The biggest unlock was not better prompting, it was a long explicit list of banned words and phrases that Claude defaults to.
- ↳Anchoring rules ('every claim needs a number, name, date, or tool') kill more slop than tone instructions ever will.
- ↳Voice prompts work better when you describe a specific person ('tired senior engineer who has shipped a hundred apps') than when you list adjectives.
- ↳Forcing structured JSON output with separate fields for takeaways, FAQs, and sources removes the model's instinct to pad the body.
I have been writing the system prompt that produces these posts for about four months. It started at maybe 400 words. It is now around 1,800. Most of the additions are not clever new instructions. They are bans.
This post is the prompt, annotated. If you are building any kind of AI writing system (newsletters, docs, marketing pages, internal reports) you can steal the parts that work and skip the parts I already learned hurt.
Why a prompt at all, instead of fine-tuning
We ship a lot of small things at EdsDev. Custom AI agents for support and lead-gen, half-finished products we pick up and launch, the occasional internal tool. Blog posts are a side effect of the work, not the work. Fine-tuning a model on our voice would be a real project: dataset, eval harness, retraining cadence when Claude ships a new version. I did not want a project. I wanted a prompt.
Claude 3.5 Sonnet and now Sonnet 4.5 are good enough that a careful system prompt gets you 90% of the way to a custom voice. The other 10% is me editing before publishing. That is a trade I am happy with.
The voice section is a character, not a list of adjectives
The first version of the voice section said things like “professional but casual, technical but accessible.” Claude wrote exactly what you would expect from that. Mush.
The version that works opens with this:
Write like a tired senior engineer who has shipped a hundred apps.
That single line does more than the next twenty bullets combined. It gives the model a person to imitate. Tired engineers do not say “in today’s rapidly evolving landscape.” They say “yeah, this broke twice in production.” They have opinions because they have scars.
If you are writing a prompt for a different voice, pick a real person archetype. “A skeptical CFO reviewing a vendor pitch.” “A pediatrician explaining a diagnosis to a worried parent.” Not a vibe. A person.
The banned word list is the actual product
Here is the truth nobody wants to admit: most of the work in a good writing prompt is a denylist. Claude has defaults. Those defaults are why you can spot AI writing in two seconds.
A partial dump of ours:
delve, leverage, foster, garner, intricate, tapestry,
landscape (figurative), pivotal, crucial, vital, robust,
seamless, vibrant, profound, groundbreaking, transformative,
paradigm, ecosystem (figurative), holistic, journey (figurative),
unlock, empower, elevate, harness (verb), navigate (figurative)
And then the phrase bans, which matter more:
"a testament to", "stands as", "serves as",
"in today's rapidly evolving", "at the intersection of",
"is more than just", "it's not just X, it's Y",
"represents a paradigm shift"
Every one of these earned its place by appearing in a draft I had to rewrite. I add to the list every couple of weeks. It is never finished because Anthropic ships new model versions and the defaults shift.
The “not just X, it’s Y” construction was the worst. Claude loves it. It is the AI writing tic. Banning it explicitly cut my edit time by maybe 20%.
Anchoring rules beat tone rules
The single most useful instruction in the prompt is this:
Anchor every claim in a specific detail: a number, a name, a date, a tool, a price, a specific bug, a specific commit, a specific app.
This is the thing that separates a draft I can ship from one I have to rewrite. When the model has to name a tool (Cursor, Cloudflare Workers, FAL, Resend) it cannot retreat to abstractions. When it has to use a number, it has to commit. “We shipped a lot of versions” becomes “we shipped 12 versions of Photo AI Studio in 2024.” One of those is writing. The other is air.
The risk is hallucination. Claude will invent specifics if you push too hard. So the prompt also says:
When citing a study, claim, or statistic, name the source. If you don’t have a real source, don’t make the claim.
And the JSON output schema has a separate sources field with the explicit instruction that fabricated URLs are worse than an empty array. This works most of the time. I still check.
Structured output kills padding
The prompt does not ask for a blog post. It asks for a JSON object with separate fields for title, description, takeaways, body, FAQs, and sources.
{
"title": "...",
"description": "...",
"takeaways": ["..."],
"contentMarkdown": "...",
"faqs": [{ "question": "...", "answer": "..." }],
"sources": [{ "title": "...", "url": "..." }]
}
This sounds like a small thing. It is not. When the body is the only output, the model pads it with summary paragraphs, restated takeaways, and a closing “in conclusion” section. When the takeaways have their own field, the body does not need to repeat them. When the FAQs have their own field, the body does not need to anticipate every question. The structure removes incentive for filler.
It also makes the output usable. I pipe it straight into our CMS. No parsing, no regex, no “strip the markdown fence the model added anyway.”
What still does not work
A few things I have not solved.
Claude still defaults to a rule-of-three rhythm. “Faster, cheaper, better.” “Build, ship, iterate.” I ban specific instances and it finds new ones. The cadence is baked in deep.
It also hedges. Even with explicit instructions to have opinions, the model softens its strongest claims. I have to go in and turn “this might be useful in some cases” into “use this.” Every post.
And long-form structure is still mediocre. The model can write good paragraphs and decent sections but the overall arc of a 1,200-word piece is usually flat. The hook lands, the middle meanders, the ending is fine. I rewrite the ending of almost every post by hand.
What I would do differently if I started today
I would write the banned word list first, before any voice instructions. That is the lever.
I would put one example of the target voice in the prompt, not a description of it. A 200-word sample of writing in the voice I want beats 200 words describing the voice I want. I have not done this yet because I am lazy about updating it. I should.
And I would build the eval before the prompt. Right now I judge outputs by reading them. That works for a one-person operation. It does not scale to a team. If you are doing this at any volume, write down five things a good post has, score every draft against them, and iterate the prompt against the score. I have not done this either. I should.
If you are running into the same wall on your own AI writing or want help building agents that handle the boring parts of your business, say hi.
Common questions
▸Which model do you use to generate posts?
Claude Sonnet 4.5 through the Anthropic API. I tried GPT-4o and Gemini 1.5 Pro on the same prompt and Claude was the only one that respected the banned word list past the first few hundred tokens. The others would drift back to defaults like 'leverage' and 'robust' by the middle of the post.
▸How long did it take to get the prompt to a usable state?
About six weeks of writing posts, hating them, and adding rules. The first month was mostly negative feedback (banning words and phrases). The second month was positive instructions (anchoring rules, voice character, structured output). It is still changing. I edited it twice in the last two weeks.
▸Do you edit the output before publishing?
Yes, always. Usually 10 to 20 minutes per post. I rewrite the ending, sharpen the strongest claims the model softened, and check any specific numbers or tool names against reality. If a post needs more than 30 minutes of editing, the prompt failed and I update it instead of just fixing the draft.
▸Why JSON output instead of plain markdown?
Two reasons. First, separate fields for takeaways, FAQs, and sources stop the model from padding the body with restated summary content. Second, it pipes straight into our CMS without parsing. The schema also lets me enforce constraints (description must be 140 to 220 chars, takeaways must be 3 to 5 items) that catch lazy outputs before I read them.
▸Will you share the full prompt?
Most of it is in this post already. The character description, the banned word and phrase lists, the anchoring rule, and the structured output schema are the parts that matter. The rest is housekeeping (length, headings, internal link patterns) that you would write differently for your own site anyway.
Related posts
Anatomy of the Claude prompt that writes this blog
The actual system prompt we use to generate EdsDev posts, broken down section by section. Voice rules, forbidden words, JSON shape, and the parts that still don't work.
Shipping an MCP server so agents can email us
We built a tiny MCP server that lets Claude and Cursor send us email through Resend. Here's the actual code, the auth headaches, and what broke in production.
An AI lead generation agent that books meetings while you sleep
How we build AI lead gen agents that actually book meetings overnight: the workflow, the prompts we use, the guardrails that stop it from embarrassing you.