blog-writer — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited blog-writer (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Channel-master skill for long-form blog content. Owns ideation → beats → draft → image → publish.
Architecture: beats-first (v0.5.0) + plugin-backed publish (v0.4.0). Each post lives in its own container with two sibling docs: a Beats doc (the structural commitments — beat list + title/preview/slug as B0) and a Draft doc (the voice-poured prose). Beats reshape regularly; draft re-pours via /authors-voice against a per-site anchor (voice/anchor-<site-slug>.md). Publish is a single post_to_blog MCP call against a site registered via add_blog_site. Mirrors book-writer's discipline at post scale.
Format rules for blog documents (title, blogContext fields, slug, cover, body, what `post_to_blog` needs) arrive from OpenWriter when the document is opened. This skill keeps voice, beats, titling, SEO and editorial judgment, and the pipeline.
This skill obeys the shared writer contract at WRITER-CONVENTION.md. Brief shape and return shape match that doc. Sub-form values: long | short | tutorial | announcement.
OpenWriter's own editing rules arrive with its tools and documents.
Blog posts ship SEO-complete in the FIRST pass. A blog post almost always carries SEO — internal/cluster links, meta + slug + tags, snippet-targeted headings, FAQ/schema-eligible content all go into the initial draft (the minion brief + first populate_document), never bolted on after. Bolting SEO on later forces an edit (→ write_to_pad, never a 2nd populate). SEO-strategy-led posts (pillar / landing / comparison) front-end through /seo-writer if you have it installed (not bundled with OpenWriter).
Cover image is a publish gate (Firm rules). Placement rules: no bottom-band text (the platform renders og:title there), keep the subject center-safe, ≤5–7 words of overlay text, do not echo the title/description. Palette / brand skin comes from the project's style_doc (e.g. recipebox.md). Generation, canonical size, and the tmp-first rule for text-overlay covers: docs/images.md.
ABOUT TO HAND-EDIT A PUBLISHED POST'S `.md`, ITS `image:` FRONTMATTER, OR DROP A COVER INTO THE REPO'S `public/`? STOP. The OpenWriter doc is the single source of truth, and post_to_blog is the ONLY writer to the blog repo. Edits flow doc → Accept → Publish — never doc and repo in parallel, because Publish rewrites the post file wholesale and your hand-edits vanish. Never hand-name a cover; never side-channel an image; never git push the post yourself. Publish flow: docs/integrate.md.
| Mode | Trigger | What it does | Sub-doc |
|---|---|---|---|
setup | /blog-writer setup, "register blog repo", "add blog site" | One-time per blog: inspect_blog_repo clones the target, auto-proposes frontmatter_defaults + frontmatter_field_map from existing posts; add_blog_site persists the site config | docs/setup.md |
brainstorm | /blog-writer brainstorm, "brainstorm blog topics" | Open a Blog Ideas doc; propose 3-5 candidate angles with tone + length labels; hand off to beats when user picks | docs/brainstorm.md |
beats | /blog-writer beats, "extract beats", "blog beats" | Query-first beat extraction with 3-pass (short/announcement, 3-5 beats) or 5-pass (long/tutorial, 8-15 beats); 9 blog category tags (CLAIM/REFRAME/MECHANISM/EVIDENCE/DEMO/SCENE/OBJECTION/APHORISM/PIVOT) + HOOK/CTA positional roles; locks title + preview + slug as B0; dopamine arc layered with conversion arc | docs/beats.md + docs/titling.md |
draft | /blog-writer draft, "draft this post", "pour the beats" | Per-beat dispatch to /authors-voice Apply Protocol with site-specific anchor; cross-beat coherence pass; supports beat-level reshape loop (re-pour only the affected beats) | docs/draft.md + docs/voice-anchor.md |
images | /blog-writer images, "blog image", "featured image" | Read style doc, craft prompt, generate the cover; optional inline images | docs/images.md |
integrate | /blog-writer integrate, "publish", "post to blog" | post_to_blog against the registered site once the writer has accepted every pending change; verify the live URL | docs/integrate.md |
pipeline | /blog-writer pipeline, "full blog workflow", "write and publish" | 7-step sequence (Setup → Brainstorm → Beats → Draft → Images → Accept → Publish → Verify) with explicit gates; reshape loop returns to Beats step | docs/pipeline.md |
Modes can chain (pipeline runs them in sequence) or stand alone. Beats reshape → draft re-pour is the inner loop the architecture is designed around.
Per-session. Read the project's CLAUDE.md and extract the optional ## Blog section. It can carry writing_rules, style_doc, content_driven, aspect_ratio. Used by images mode + as defaults for beats/draft. Schema: docs/project-config.md. If absent, defaults apply and the skill still runs.
Per-blog (one-time). Each blog repo must be registered with the github plugin via add_blog_site before integrate can publish to it. Run /blog-writer setup once per blog. The setup mode uses inspect_blog_repo to auto-propose frontmatter_defaults (layout, author, prerender — fields constant across the site's existing posts) and frontmatter_field_map (e.g. date → publishedDate for Astro sites). Sub-doc: docs/setup.md.
Per-post container structure (Beats + Draft sibling docs), the 10-step OpenWriter call-order for building one post, and the return/output contract live in docs/architecture.md. Two facts ride every build:
Beats — <Title> (content_type document) holds structure; <Title> (content_type blog) is the publishable Draft — one per container. Reshape beats → re-pour only the affected beats, never the whole post.docId; the user watches the activity feed and navigates themselves. Only switch_document on an explicit user instruction ("open the Draft", "show me the Beats") or when publishing needs the post open.beats first. Pouring prose without committed beats produces shapeless drafts that need full structural rework downstream.Beats — <Post Title> (content_type: document) and <Post Title> (content_type: blog — the publishable doc). Beats reshape → draft re-pour. Don't mix prose into the Beats doc; don't put structural commitments in the Draft doc.beats mode. When draft mode runs they mirror onto the Draft doc. See docs/titling.md. The first paragraph of the draft must echo the title — can't echo what isn't locked.draft mode reads voice/anchor-<site-slug>.md where <site-slug> is the slugified site label from list_blog_sites. Silent fallback to voice/anchor.md if not present. Discovery is convention-based, NOT in plugin config. See docs/voice-anchor.md.add_blog_site before integrate can publish. Check list_blog_sites at session start — if the target repo isn't there, run /blog-writer setup first.## Blog in CLAUDE.md is for writing_rules, style_doc, content_driven, aspect_ratio. Frontmatter shape lives on the site registered with the github plugin, NOT in project config./authors-voice Apply Protocol with the site-specific anchor. The skill owns shape; voice owns diction. Per-beat dispatch is the default for long/tutorial; collapse to single dispatch for short/announcement under 1000w.create_document (spinner) → populate_document (content). Never inline a 30s generation into one tool call.America/Los_Angeles).integrate tells the user "click Accept All in the right rail, then I'll publish" rather than silently posting incomplete content.integrates without a cover/OG image — a gate, not optional. Design per the Convention above (placement rules + style_doc palette; docs/images.md mechanics).draft without first running beats for the post — fails with "no Beats doc found in container".md file directly into the target repo via Write/Edit tools — that's post_to_blog's jobdraft mode reads conventionally; no opt-in required/blog-pipeline, /blog-images, /blog-integrate, /blog-feature-images as separate skills (deprecated stubs that redirect here)mcp__openwriter__insert_image — Gemini image generation in OpenWriter (primary path).webp (the github plugin copies PNGs unchanged; conversion is a project-specific concern before publish)Delegated / required:
draft delegates every beat dispatch).NOT covered (use your own tooling instead): project deploy pipelines · cross-channel announcements (Discord, X, etc.) · /newsletter-writer (different channel) · /x-writer (different channel) · /book-writer (multi-chapter books — global beat sheet, workspace management).
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.