Prompt Engineering - How Wire Assembles Prompts
You changed a styleguide rule and Claude still writes the same way. Or Claude produced something unexpected and you have no idea which file caused it.
Wire builds every prompt from three files stacked together. Your styleguide sits at the top, then the action prompt, then the data Claude needs to do the job. When output goes wrong, the cause is always in one of those three places. The hard part is knowing which one. Two situations come up most often: something is broken and you need to fix it, or you're setting up a new topic and want to control how Claude writes for it.
If the problem appears on every page regardless of topic or command, the styleguide is the likely cause. The styleguide is prepended to every prompt Wire sends. One missing rule, one vague role statement, and every page inherits the problem. Here's the complication: if `docs/_styleguide.md` doesn't exist, Wire silently falls back to its built-in version. Your custom rules may not be in the prompt at all.
Each Wire command loads a matching prompt file. `wire.content create` loads `content_create.md`. `wire.content refine` loads `content_update.md`. If a topic override exists at `docs/{topic}/_{action}.md`, Wire uses that file instead of the built-in entirely. It doesn't merge them. So if your override is missing the section structure, Claude won't produce it. The question is whether you have an override you forgot about, or whether you need to write one.
Variables are the data Wire injects at runtime: the existing page, web research, GSC keyword data, the site directory. Claude can only work with what's in the prompt. If `{research}` contained a page with wrong information, Claude didn't hallucinate. It extracted what was there. If internal links point to pages that don't exist, the site directory may be stale. The fix is usually upstream of the prompt, not in it.
The fastest way to isolate a prompt problem is `--dry-run`. Wire runs the full command, assembles the complete prompt, sends it to Claude, and writes the output to `index.md.preview` without saving. You see exactly what Claude produced from exactly the prompt it received. The complication: you still need to know which file contributed the bad instruction. Wire checks two locations for each layer, and the fallback behavior is silent.
Wire assembles every Claude call from three layers: a styleguide, an action prompt, and runtime variables. Understanding these layers is the difference between guessing why Claude wrote something and knowing exactly which line caused it.
This guide covers the technical system. For writing styleguide content (tone, banned words, section structure), see Writing for Wire.
The Three Layers
Every prompt Claude sees is assembled from these sources, in this order:
┌──────────────────────────────────────────┐
│ 1. STYLEGUIDE │
│ docs/_styleguide.md │
│ (or fallback: wire/prompts/_style.md)│
├──────────────────────────────────────────┤
│ 2. ACTION PROMPT │
│ docs/{topic}/_{action}.md │
│ (or fallback: wire/prompts/{action}.md)│
├──────────────────────────────────────────┤
│ 3. VARIABLES (injected at runtime) │
│ {current}, {news}, {research}, etc. │
└──────────────────────────────────────────┘
The styleguide is prepended to the action prompt. Claude sees one continuous document: your editorial rules first, then the task instructions, then the data.
What Claude Actually Sees
Here is a real example. When you run:
python -m wire.content create vendors/acme-ocr
Wire assembles approximately this prompt (simplified for clarity):
# Writing Style for SITE CompareStack ← from _styleguide.md
(or _style.md fallback)
comparestack.com compares enterprise software...
You are currently working in TOPIC Vendors
(Enterprise software vendor profiles).
## Citation Style (Inline Links)
Use inline links, not footnotes...
[... rest of styleguide rules ...]
## SEO Structure Rules
### Title
- 51-55 characters, dashes not pipes...
[... rest of SEO rules ...]
──────────────────────────────────────────── ← layer boundary
## Your Role: Vendors Expert for CompareStack ← from content_create.md
You are creating a new page about ITEM Acme OCR
for TOPIC Vendors on SITE CompareStack.
Use the RESEARCH below...
## RESEARCH [About: Acme OCR] ← {research} variable
https://acme.com/ocr - "Acme OCR processes
197 languages with 98.2% accuracy..."
https://techcrunch.com/2026/01/... - "Acme
announced Series C funding of $45M..."
## SITE DIRECTORY [Site: CompareStack] ← {site_directory} variable
- /vendors/abbyy/ - ABBYY
- /vendors/rossum/ - Rossum
- /capabilities/ocr/ - OCR Technology
[... other pages ...]
The prompt is typically 15-50KB depending on the action. Variables like {research} can contain entire web pages. Prompts over 50KB automatically stream to avoid timeouts.
Layer 1: Styleguide
The styleguide applies to every Claude call on your site. Place it at docs/_styleguide.md. If that file does not exist, Wire uses the built-in wire/prompts/_style.md.
The built-in styleguide covers:
- Citation style (inline links, first-mention linking)
- SEO structure rules (title length, heading hierarchy, H1 alignment)
- External link handling (first 3 pass, rest get nofollow)
- Anchor text rules (2-5 words, descriptive, no generic)
- Source requirements (external citations required)
To override it, create docs/_styleguide.md with your own rules. Wire uses your file instead of the built-in one. It does not merge them. Copy what you need from the built-in styleguide and add your own rules.
Annotated CompareStack Styleguide
Here is a complete styleguide for a SaaS comparison site, with annotations explaining why each section exists:
## Editorial Rules for comparestack.com
comparestack.com helps CTOs evaluate enterprise software
with independent, data-driven profiles.
You are a senior analyst writing for technical decision-makers.
Assume the reader manages 50+ software licenses and
understands concepts like TCO, API rate limits, and
SOC 2 compliance.
# ↑ The role statement is the highest-impact line.
# It sets vocabulary, assumptions, and depth.
## Banned Words
Never use: best-in-class, industry-leading, seamless,
cutting-edge, robust, next-generation, world-class,
turnkey, synergy, end-to-end, comprehensive, innovative
# ↑ Forces Claude to replace marketing fluff with specifics.
# "Robust API" becomes "REST API with 99.97% uptime (status page, 2026)."
## Citation Rules
For market size claims: cite Gartner, Forrester, or IDC.
For feature claims: cite vendor documentation or changelog.
For user sentiment: cite G2, Capterra, or TrustRadius.
Include publication date with every citation.
Never cite competitor marketing pages as neutral sources.
# ↑ Named sources prevent hallucinated citations.
# Claude either finds a real data point or omits the claim.
## Title Rules
- 51-55 characters
- Use dashes, not pipes
- No brackets or parentheses
- Title must match the H1 exactly
# ↑ Based on Zyppy's 80,959 title study: Google rewrites
# 61.6% of titles. These rules target every rewrite trigger.
Annotated AutoFix Styleguide
A shorter styleguide for a local service business:
## Redaktionelle Regeln für autofix-muenchen.de
Sie sind ein erfahrener KFZ-Mechaniker, der Reparaturen
für Autobesitzer erklärt. Schreiben Sie, als stünde der
Kunde vor Ihnen an der Werkstatttheke.
## Verbotene Wörter
erstklassig, führend, innovativ, modernste,
hochqualifiziert, langjährige Erfahrung, Leidenschaft
# ↑ German marketing filler. Without this list, Claude
# defaults to "erstklassige Qualität" on every page.
## Quellen
Für Sicherheitsaussagen: ADAC, TÜV, oder DEKRA mit Datum.
Für Kosten: eigene Erfahrungswerte, keine externen Quellen.
Für technische Daten: Herstellerangaben (Bosch, Continental).
# ↑ German car owners trust ADAC. Random blog citations
# would reduce credibility, not increase it.
This styleguide is 20 lines. Claude needs 15-30 rules, not 200.
Layer 2: Action Prompts
Each Wire command has a matching prompt template. When you run wire.content create, Wire loads content_create.md. When you run wire.content refine, it loads content_update.md.
Wire checks for topic-specific overrides first:
docs/vendors/_create.md ← checked first (topic override)
wire/prompts/content_create.md ← fallback (built-in)
If docs/vendors/_create.md exists, Wire uses it instead of the built-in. The styleguide is still prepended, so your editorial rules apply, but the task instructions come from your override.
Available Action Prompts
| File | Command | Key Variables |
|---|---|---|
content_create.md |
create |
{research}, {site_directory} |
content_update.md |
refine |
{news}, {search_terms}, {current}, {source_diversity} |
content_expand.md |
expand |
{research}, {expansion_topic} |
content_seo.md |
seo |
{target_keywords}, {search_terms}, {current} |
content_seo_light.md |
seo-light |
{target_keywords}, {search_terms}, {current} |
content_compare.md |
compare |
{page_a}, {page_b} |
content_consolidate.md |
consolidate |
{comparisons} |
content_crosslink.md |
crosslink |
{current_page}, {targets}, {site_directory} |
content_merge.md |
merge |
{keeper_page}, {donor_page}, {shared_keywords} |
content_differentiate.md |
differentiate |
{current_page}, {competing_page}, {shared_keywords} |
content_improve.md |
improve |
{amendment_brief}, {research}, {news}, {search_terms}, {site_directory} |
news_evaluate.md |
news (junior) | {article}, {source_type}, {from_date}, {to_date} |
news_combine.md |
news (senior) | {submissions} |
news_search.md |
news search | {hints}, {source_gaps} |
Auto-Injected Variables
Two variables are injected into every prompt automatically. Never pass these manually. Doing so causes a TypeError: got multiple values error.
{site}: Site object (site.title,site.url,site.description){topic}: Topic object (topic.title,topic.description)
Writing a Topic Override
A topic override replaces the entire action prompt, not just part of it. You must include all the variable placeholders the action needs. Here is a minimal docs/vendors/_create.md:
## Your Role: Vendor Analyst for {site.title}
Write an independent profile of {item.title} for the
{topic.title} section of {site.title}.
### Page Structure
1. ## Overview -- founding year, HQ, employee count, funding
2. ## Key Features -- top 5, with benchmarks or case studies
3. ## Pricing -- tiers, or "contact for pricing" with context
4. ## Recent Updates -- last 12 months, with dates
5. ## Verdict -- who should use this, who should not
### Data
Use the RESEARCH below. Prioritize third-party sources over
the vendor's own website.
## RESEARCH [About: {item.title}]
{research}
## SITE DIRECTORY [Site: {site.title}]
{site_directory}
Note: {item.title} refers to the Content object being created. Use {item.title} for Content objects, {item_name} for string names. Never mix them for the same entity.
Layer 3: Variables
Variables are data injected at runtime. Wire fills them in before sending the prompt to Claude. The most common:
{current}: The Existing Page
Contains the full markdown of the page being edited. Used by refine, seo, improve, and other commands that modify existing content.
{research}: Web Search Results
Contains fetched web pages (titles, URLs, extracted text). Used by create and expand. Typically 10-30KB.
{news}: Pending News Files
Contains news files that have not been integrated yet. Used by refine. Each file has frontmatter with title, source, date.
{search_terms}: GSC Keyword Data
Contains Google Search Console data: queries the page ranks for, positions, impressions, CTR. Used by seo and refine. Formatted as a markdown table.
{amendment_brief}: Local Analysis Results
Contains the pre-computed amendment brief from wire/analyze.py. Used by improve. Includes expand keywords, link targets, heading promotions, and create suggestions, all computed locally with zero API calls.
{site_directory}: Pages on the Site
A structured list of all pages, organized by topic. Used by create and crosslink to help Claude add internal links. The generate_link_context() function produces a focused ~15-20KB version for content operations (vs the full directory used by newsweek).
Debugging Prompt Issues
When Claude produces unexpected output, trace the problem to a specific layer.
Step 1: Identify the symptom
| Symptom | Likely Layer |
|---|---|
| Wrong tone on all pages | Styleguide (role statement) |
| Wrong tone on one topic | Topic override or missing override |
| Wrong structure | Action prompt (section list) |
| Missing citations | Styleguide (source rules) |
| Bad internal links | Variables ({site_directory} data) |
| Hallucinated facts | Variables ({research} quality) |
| Title too long/short | Styleguide (title rules) |
Step 2: Inspect with dry-run
Run the command with --dry-run to see Claude's output without saving:
python -m wire.content refine vendors/acme --dry-run
This writes to index.md.preview and shows a diff. Read the preview to see what Claude produced.
Step 3: Check what Claude received
The prompt is assembled by load_prompt() in wire/tools.py. To see the exact prompt:
- Check which styleguide Wire found:
docs/_styleguide.mdexists? Or falling back towire/prompts/_style.md? - Check which action prompt Wire used:
docs/{topic}/_{action}.mdexists? Or falling back towire/prompts/{action}.md? - Read both files. The styleguide is prepended to the action prompt.
Step 4: Fix one layer at a time
Change one rule, run --dry-run, check output. Repeat. If you change five rules at once and the output is wrong, you cannot isolate the cause.
Common Debugging Scenarios
Claude ignores your styleguide rules.
Check if docs/_styleguide.md exists. If not, Wire uses the built-in fallback. Your rules might not be in the prompt at all.
Claude uses the wrong structure.
Check if a topic override exists at docs/{topic}/_{action}.md. If it does, it replaces the built-in prompt entirely. Your override might be missing the section structure.
Claude hallucinates a citation.
The {research} variable contains whatever web search returned. If the source was unreliable, Claude may have extracted incorrect data. Check the research quality, not the prompt.
Claude links to pages that do not exist.
The {site_directory} variable might be stale. Rebuild the site to update the directory. The _sanitize_content() function catches broken internal links after Claude writes. It will either fix the slug or strip the link to plain text.
TypeError: got multiple values for argument 'topic'.
You passed topic= manually in a load_prompt() call. Remove it. Wire injects {site} and {topic} automatically.
Curly braces crash: "uses 'X' but caller didn't provide it."
Curly braces in your prompt text are parsed as template variables. If you write {Job Title} as a format example, Wire tries to resolve it and crashes. Use [Role Name] or backtick-quoted literals instead.
Internal links clustered in one paragraph. Claude defaults to dumping all links at the end. Your prompt must specify distribution: "Find the MOST relevant page and link to it in the section where it naturally fits. DISTRIBUTE links across sections. Never cluster all internal links in one paragraph."
Title with colon crashes YAML parser.
A title like Bookkeeper: Hire, Outsource, or Automate? without quotes causes mapping values are not allowed in this context. Tell Claude explicitly: "Single-quote titles containing colons in YAML frontmatter."
Refine dilutes your page's angle. If your create prompt says "reframe hiring as a project scope" but your update prompt just says "integrate news," every refine pass dilutes the angle. Put the business strategy in BOTH prompts, not just create.
Banned language reappears after refine. Claude defaults to generic terms unless explicitly banned. If your platform calls work "projects" and never "tasks," state it as a ban in both prompts: "NEVER use 'tasks' or 'gigs'. Always 'projects' or 'engagements'."
Re-refining pages with no pending news.
After improving a prompt, you want to re-run refine on existing pages. But Wire skips pages with no pending news files. Workaround: create a trigger news file with a note about what to focus on, then run wire.content refine topic/slug. The trigger file content tells Claude what to prioritize.
Output Formats
Wire tells Claude what format to return. You do not control this in your prompts. It is set by Wire's code.
| Format | Used By | What Claude Returns |
|---|---|---|
markdown_file |
create, refine, seo, improve | YAML frontmatter + markdown body |
decision |
merge/differentiate classification | Lines prefixed with WHY: |
none |
news evaluation | Raw text |
The Evidence Behind Wire's Built-In Prompts
Wire's default prompt rules are not opinions. Each rule traces to a specific study or confirmed signal.
Title rules (51-55 chars, dashes not pipes): Zyppy's 80,959 title study found Google rewrites 61.6% of titles. The rewrite rate reached 76% by Q1 2025. Wire's rules target every documented rewrite trigger.
H1 alignment (title must match H1): The 2024 Google API leak confirmed titleMatchScore as a ranking signal. SearchPilot's A/B test measured 28% traffic increase from proper H1 alignment.
Source diversity (no over-reliance on one domain): The LfM-Band 60 study observed 235 journalists and found only 0.9% of research actions were source checks. Wire's analyze_source_diversity() automates what journalists almost never do.
External citations required: The Reboot Online study ran a controlled experiment showing outbound links to authoritative sources improve rankings. Wire enforces this as a styleguide rule, not a suggestion.
When writing custom prompts, apply the same evidence hierarchy:
- Leak-confirmed signals. Hard rules in styleguide.
- A/B tested results. Specific instructions in action prompts.
- Correlation studies. Guidance, not requirements.
- "Google says". Ignore unless independently verified.