name: zbeam-content-writer description: "Creates new Z-Beam YAML page files from research briefs. Trigger on 'write a page about X' or 'create a page for [topic]'."
Z-Beam Content Writer
Pipeline position: zbeam-editorial-brief → YOU → zbeam-voice-polisher → zbeam-content-validator → (zbeam-content-revisor → zbeam-section-executor if FAIL) → zbeam-adversarial-reviewer
Note: citation-builder and crosslinker are called by the generation-loop after final PASS, not between write and validate.
Implementation scripts: skills/writing/zbeam-content-writer/references/writer-utils.py
Section mode — token-efficient per-section authorship
When called with a section: argument (e.g., section:characteristics), operate in focused mode:
- Load only the editorial brief — do NOT load the research briefs
- Write only the specified YAML block
- Merge into the existing file rather than rewriting from scratch
- Skip full post-write self-check and post-gen report until all sections are done
Available sections (material pages):
| Section arg | YAML path written |
|---|---|
characteristics |
body.characteristics.heading.description + body.characteristics.fields{} |
laserInteraction |
body.laserInteraction.heading.description + body.laserInteraction.fields{} |
machineSettings |
body.machineSettings.heading.description + cleaningParameters block |
industryApplications |
panels.industryApplications.heading.description |
regulatoryStandards |
panels.regulatoryStandards.heading.description + panels.regulatoryStandards.items[] |
faq |
panels.faq.items[] |
problems |
panels.problems.items[] — exactly 3 entries with title, description (≥40 words), bottomLine |
howToProceed |
howToProceed.title + howToProceed.steps[] — exactly 3 steps; last step = Z-Beam rental/on-site CTA |
page |
page.title, page.description, page.metaDescription, page.keywords — always write last |
Section mode workflow:
1. Load editorial-brief-[slug]-*.json
2. Extract editorialBrief.sectionDirectives.[section]
3. Context read existing YAML fields (do NOT cat the full file):
python3 skills/writing/zbeam-content-writer/references/writer-utils.py context_read [slug] [content_type] [section]
4. Write the target section using directives + prose rules
5. Merge back with Python string replacement or ruamel.yaml
6. Validate: python3 -c "import yaml; yaml.safe_load(open('[path]'))" && echo valid
7. Report what was written and any FAIL items found
Merge pattern: use Python str.replace() for prose blocks (>- scalars); use yaml.safe_load() + yaml.dump(sort_keys=False) for structured fields (dict/list).
page section is always last. Write after all other sections are complete and validator has passed.
After all sections are written: run the full post-write self-check and post-gen report once.
Step 0 — Prose constraints (read before writing any field)
Read skills/shared/writing-constraints.md. Apply all rules to every prose field you write.
The structural validator checks these mechanically after writing — violations route back to revisor.
Before writing anything — check these three things
1. Research briefs exist?
ls data/research/content-brief-[slug]-*.json
ls data/research/differentiation-brief-[slug]-*.json
If either is missing: stop. Writing from training knowledge guarantees a Dimension 2 failure.
2. Editorial brief exists?
ls data/research/editorial-brief-[slug]-*.json
If missing: stop. Run zbeam-editorial-brief first.
3. Page doesn't already exist?
ls frontmatter/applications/ | grep -i [keyword]
ls frontmatter/locations/ | grep -i [keyword]
If a page exists, use zbeam-page-updater instead.
What every page must contain — non-negotiable
| Requirement | Where it comes from | Where it goes |
|---|---|---|
| Quantitative figures — minimum 2, target 3 | content-brief.quantitativeDataPoints |
Each figure must appear INSIDE a sentence that states a claim; never as the opener, never bolted onto an unrelated sentence. Write the claim first, then integrate the figure into it or the sentence immediately after. |
| All tier-1 findings (score ≥ 8) | differentiation-brief.findings[score>=8] |
Same sentence-position rule applies — claim first, figure in support. Zero drop tolerance for tier-1 findings. |
| 1 unusual/obscure fact | differentiation-brief.obscureFacts |
content.observations or properties description |
| 1 cross-topic relationship | differentiation-brief.crossTopicRelationships |
Any prose section |
Dense page.description |
Synthesized last from densest findings | page.description (v7) |
| Commercial handoff | Bay Area service/rental CTA in context section or FAQ | content.context or FAQ |
| Topic sentences | All prose sections | Every section opens with a topic sentence stating the main point. No throat-clearing openers. |
| FAQ specificity | faq.items[*].answer | Every FAQ answer: direct first sentence + ≥1 number or named standard + material/application-specific (not interchangeable) |
| Human-like prose | See prose rules | All sections |
Note: Failure to include ≥1 specific number in an FAQ answer causes dim_4 FAQ_THIN flag.
About Z-Beam
- 9-county SF Bay Area, on-site laser cleaning + Netalux Kamino 300 rentals
- Differentiators: European equipment, Cal/OSHA + BAAQMD compliance, no chemicals/blast media, 47+ demo videos
- Audience: contractors, fabricators, facilities managers, property owners
Machine specs — load references/netalux-kamino-300.md only when the page involves machineSettings, cleaningParameters, or specific operating parameters. Skip for application pages focused on regulatory compliance, historic preservation, or process context.
Step 1: Load inputs
Section mode: Load data/research/editorial-brief-[slug]-*.json only. Extract sectionDirectives.[section] as your task brief.
Full-page mode: Load all three brief files. Check dataDensityAssessment.meetsMinimumThreshold — if false, use qualification language in limitations instead of inventing confident claims.
Check for User Intent Brief at data/ai-search/intent-briefs/[query-id]-*.json — use its followUpQuestions as FAQ sources if present.
GSC query signal (application pages — FAQ sourcing): Read data/search-console/latest-page-queries.json. For /applications/[slug], extract queries with impressions ≥ 1 containing "how", "what", "can", "cost", "why", "when", "difference". Use verbatim as FAQ question titles where they match.
Prose patterns load:
python3 skills/writing/zbeam-content-writer/references/writer-utils.py load_prose_patterns
These rules apply to every prose field — derived from pages where real visitors stay longest. Apply humanVoiceRules from output as positive guidance; treat avoidPatterns as machine-authorship signals to avoid.
Step 2: Identify required sentences from the editorial brief
From editorialBrief.sectionDirectives, for each field with a non-empty requiredSentences[] array: note sentences and their target fields. These must appear verbatim — paraphrasing breaks citation potential.
Also check: if the editorial brief carries aiSummaryCandidate.sentence, it must appear verbatim in aiSummary.
Step 2b: Load and stage tier-1 findings — MANDATORY
python3 skills/writing/zbeam-content-writer/references/writer-utils.py load_tier1_findings [slug]
Extracts all findings with score >= 8 from data/research/differentiation-brief-[slug]-*.json. Every tier-1 finding must appear in the generated YAML — zero drop tolerance.
Writing sequence for each prose section (follow this order, every time)
Do not write prose and then insert figures. Instead:
- Draft the topic claim — one sentence, subject + finite verb + specific assertion. No figure yet.
- Select the supporting figure from
tier1_findingsorquantitativeDataPointsthat best grounds that claim. - Integrate the figure into the claim sentence (preferred) or into the sentence immediately after it.
- Check: does the figure appear before the claim? If yes, reorder — claim always comes first.
DO:
Claim: "Aluminum weld porosity drops from 10–80% to under 1% when laser cleaning replaces manual degreasing."
Figure: already integrated into the claim — nothing more needed.
Claim: "Copper busbars begin forming Cu₂O oxide within hours of air exposure."
Support: "At 500 A load, a 1 mΩ joint dissipates 0.25 W (P = I²R) — enough to accumulate as heat across a 200-connection pack."
DON'T:
"10–80% porosity reduction is achievable. Laser cleaning is the recommended approach." ← figure before claim
"Laser cleaning cuts chemical handling steps entirely — the process window is 0.2 J/cm²." ← figure bolted to unrelated sentence
Field assignment (after sequencing is correct):
- If the finding maps to a specific field per
sectionDirectives, place it there. - Otherwise:
content.observationsor the equivalent application prose field. - If that field is full: most relevant FAQ answer.
Before saving, confirm all tier-1 findings are present:
python3 skills/writing/zbeam-content-writer/references/writer-utils.py check_tier1_placement [slug] [path_to_yaml]
Fix any MISSING findings before Step 5.
Step 2c: Load the correct page-type template
If contentType is application: Read references/template-application.md now. Follow exactly — defines required section structure (3 problems with function labels, 3 FAQs). Do NOT use content.introduction, content.observations, content.processNotes, or content.limitations.
If contentType is location: Use san-jose-laser-cleaning.yaml as structural template.
If contentType is material: Read a sibling material file as structural template. The sibling wins over these instructions on schema conflicts.
- Historic/masonry →
heritage-architectural-laser-cleaning-applications.yaml - Industrial/weld/fabrication →
weld-prep-laser-cleaning-applications.yaml - Manufacturing/EV →
automotive-ev-laser-cleaning-applications.yaml
Step 3: Write the YAML
Frontmatter v7 (canonical on disk)
All new/updated pages use document.schemaVersion: 7.0.0 per docs/01-core/frontmatter-v7.md.
| Layer | Keys |
|---|---|
| Shell | document, routing, page (title, description, subject, keywords) |
| Substance | body.* (material science blocks, application prose, video youtube + enhancements) |
| Material property fields | body.characteristics.fields{} and body.laserInteraction.fields{} — each field has value, unit, confidence (0–100); sourced fields add source + citation. Never place at top level. Minimum: density, meltingPoint in characteristics; thermalDestruction, laserAbsorption, laserDamageThreshold, ablationThreshold in laserInteraction. |
| UI sections | panels.<key> with heading.title, heading.description, presentation, and prose / items / refs |
| Application problems | panels.problems.items[] — exactly 3 entries with title + description |
| FAQ items | question + answer (not title / content) |
| Cross-links | panels.relatedMaterials.refs, panels.relatedApplications.refs, etc. — not relationships.discovery |
panels.industryApplications |
heading.description: short plain sentence only — never embed technical parameters |
Do not author sectionTitle, sectionDescription, top-level pageTitle/pageDescription, relationships.discovery, sections.problems, or top-level technicalNotes on applications.
Universal prose rules
- Read
skills/shared/writing-constraints.mdbefore writing. Every structural rule has a DO and DON'T example. This is the single source of truth — do not load prose-rules.md or its sub-files.
Critical inline checks:
- page.title outcome phrase must be non-specialist-readable — no bare standard codes; include plain-language equivalent.
- page.description must not open with specialist notation — no chemical formula, wavelength, or bare unit as first word.
- page.description video links must not include YouTube IDs in display text — ID in URL path only.
- Banned openers: "For decades,", "Both work but", "The question is", "Bay Area [role] ask"
- FAQ heading description: leave blank (
description: ""). The FAQ items themselves carry all context. - Regulatory section heading descriptions: state compliance outcome, not just standard names.
After writing each prose field, run:
python3 skills/writing/zbeam-content-writer/references/writer-utils.py check_prose [field_name] "[text]"
Fix every issue before moving to the next field.
Per-section standards
content.introduction — material pages only. Open with the surface problem. Include 1064nm wavelength reference if research supports it.
content.context — name specific Bay Area industries/building types/regulatory jurisdictions. At least one Northern California-specific sentence. Must include commercial handoff — direct reference to Z-Beam's on-site service or equipment rental.
content.observations — primary location for quantitative data. Include ≥1 finding from quantitativeDataPoints with source, the obscure fact, and any wavelength-specific finding.
content.processNotes — where hazardous materials are involved, include BAAQMD/Cal/OSHA rule numbers and thresholds.
content.limitations — be honest and specific. Name failure modes. If data was sparse, say so.
faq items — 35–95 words per answer. Open each answer with consequence or direct answer. At least two answers must contain quantitative detail with source. No absolute language.
enhancements.summary (application pages) — 2–4 dense sentences. Specific materials, measurable outcomes, Bay Area context.
citations[] (application pages — MANDATORY, ≥3 entries) — every specific number, regulatory threshold, or documented finding cited inline in any prose field must appear as a structured citation entry. Each entry requires:
citation: author, publication, year — plain texturl: verifiedhttps://URL (no placeholders)shortName: 2–5 word label used for inline referenceclaim: the exact finding the page relies on — ≤40 words, verbatim from source where possible
Source the url and claim from the differentiation brief's findings[*].source. Every inline (ShortName, Year) reference in prose must have a matching citations[] entry. Missing citations[] block = Dim 3 FAIL.
Step 4: Write SERP fields last
4a. page.description
After all other sections complete, write page.description. 2–4 sentences, every sentence contains a measurement/regulatory reference/documented finding. Include one claim from obscureFacts or crossTopicRelationships. No marketing language.
4b. pageTitle and metaDescription (CTR-first)
Use the sectionDirectives.serp targets from the editorial brief. Both must match editorial brief targets unless a stronger formulation exists from research briefs.
Rules:
pageTitlemust be ≤60 characters. Count manually.metaDescriptionmust be ≤155 characters AND a complete sentence. End on a word boundary.
Step 5: Save, crosslink, validate
python3 -c "import yaml; yaml.safe_load(open('[path]'))" && echo "valid"
Read references/post-write-check.md and run the full script. Fix every FAIL before proceeding.
Then run zbeam-crosslinker on the saved page — mandatory.
Then run zbeam-content-validator.
MANDATORY: Source fields must be real URLs
Every source: field must contain a verified https:// URL. Non-URL strings are forbidden. If no real URL exists, omit source: entirely.
Declare run (after YAML is saved)
python3 skills/writing/zbeam-content-writer/references/writer-utils.py declare_run [slug] [content_type] [section]
Report to the user
- File path saved; briefs consumed (filenames)
- Quantitative data points: count and which sections they appear in
mustAnswerItemsfrom differentiation brief: addressed yes/no per item- Required sentences placed: which field each
requiredSentencelanded in (or flag if omitted) aiSummaryCandidateused: yes/no; cross-links added by crosslinker
── Invocation (volatile — set once per run, referenced throughout) ──────────
# PROMPT-CACHE NOTE: All stable instructions above this section are cacheable.
slug = '[slug]' # ← fill at call time
content_type = 'material' # ← 'material' | 'application'
section = None # ← section name if section mode, else None