agentleFS
greglas75greglas75/zuvo/skills/content-expand/SKILL.md

content-expand

Skill7 starsChanged 27 days agoMITView on GitHub

Expand and optimize existing articles. Adds new sections, deepens thin content, and applies the same quality pipeline as write-article (anti-slop, BLUF, GEO signals, humanization, multi-schema). Includes web search research about the topic and auto-discovery of internal links from your content collection. Replaces content-optimize. Flags: [file], --dry-run, --lang, --tone, --site-dir, --domain, --skip-research, --light.

The file

Show its rules and text

We split this skill into the rules it gives an agent

17 rules. About 0 are common, 5 are distinctive, and 12 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈5

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 12

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    If --site-dir has 3+ blog articles: extract voice profile per humanization-rules.md (rhythm, person, formality).

    line 95
  2. Very specific:

    If --site-dir provided: scan the content collection (Glob *.md + *.mdx), read titles/descriptions of 10-20 articles, identify 5 most …

    line 109
  3. Very specific:

    If web search unavailable: note research_limited: true, proceed with LLM knowledge only (clearly marked).

    line 139
  4. Distinctive:

    Add intro/conclusion: if missing

    line 158
  5. Distinctive:

    No throat-clearing (G12), BLUF per section (G9), max 300 words/section (G6)

    line 171
  6. Very specific:

    Do not build paragraph rhythm around repeated source lead-ins such as Według X (2025)

    line 173
  7. Very specific:

    Use a hard source-name budget: the same full institution/source name should appear no more than once per section and no more than 3 times …

    line 174
  8. Very specific:

    Use (odczyt: miesiąc rok) only for volatile practical facts, not for stable historical description

    line 175
  9. Very specific:

    Do not append a process-heavy research appendix such as Źródła wykorzystane przy aktualizacji

    line 176
  10. Very specific:

    Do not add filler closers like ## Na koniec if they only restate the article

    line 180
  11. Distinctive:

    Prefer practical expansion blocks (specific H2s, lists, route notes, local comparisons, FAQ at the end) over replacing the opening with …

    line 181
  12. Distinctive:

    Use these exact output shapes when applicable:

    line 184
  13. Very specific:

    Read domain-profile-registry.md for niche-appropriate schema:

    line 207
  14. Distinctive:

    Run anti-slop check on expanded content (same as write-article Phase 4):

    line 217
  15. Very specific:

    Record the verdicts: after triage: every finding is fixed, rejected (a false positive) or deferred — record each by its ID: in ONE call, …

    line 235
  16. Very specific:

    Append via wrapper (REQUIRED): Never >> directly to ~/.zuvo/runs.log — the wrapper is the gate that verifies a retro entry exists for this …

    line 263
  17. Very specific:

    Follow retrospective.md. Gate check → structured questions → TSV emit → markdown append.

    line 280

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

zuvo:content-expand — Expand & Optimize Articles

Take an existing article, research the topic, add what's missing, and optimize the result — all in one pass. Same quality standards as zuvo:write-article.

Scope: Expand thin content, add missing sections, research and integrate new facts, optimize prose quality, update SEO/schema. Out of scope: Encoding/markdown fixes (zuvo:content-audit + content-fix), writing from scratch (zuvo:write-article), CMS API, PDF/Word.

Mandatory File Loading

Phase 0 (always):

  1. ../../shared/includes/env-compat.md -- Agent dispatch
  2. ../../shared/includes/run-logger.md -- Run logging
  3. ../../shared/includes/banned-vocabulary/core.md -- Shared anti-slop rules, tone matrix, G12, fallback behavior
  4. ../../shared/includes/humanization-rules.md -- Writing constraints + voice matching
  5. ../../shared/includes/domain-profile-registry.md -- 17 niche profiles
  6. ../../shared/includes/seo-page-profile-registry.md -- SEO profiles
  7. ../../shared/includes/no-pause-protocol.md -- HARD: no mid-loop pauses (batch/multi-section)

Lazy-loaded (Phase 2 only):

  1. ../../shared/includes/prose-quality-registry.md -- PQ1-PQ18 (scoring)
  2. ../../shared/includes/adversarial-loop-docs.md -- Cross-model review (end of Phase 2)
  3. ../../shared/includes/article-output-schema.md -- JSON output
  4. ../../shared/includes/retrospective.md -- RETRO PROTOCOL

Print CORE FILES LOADED: for items 1-7. After language detection, print LANGUAGE FILE: with the resolved banned-vocabulary language file and whether English fallback was used. Lazy items loaded inline when needed.

Safety Gates

GATE 1 — File Type

.md, .mdx supported. .html tolerated (tag-stripped, WARNING). Binary → STOP.

GATE 2 — Dirty File Check

git status --porcelain -- <file>. Uncommitted changes → STOP. Require commit or stash. --dry-run mode: proceed with WARNING (no file mutation).

GATE 3 — Write Scope

Allowed: input file, <file>.content-expand-backup, zuvo/reports/, memory/backlog.md and memory/findings/ (written by backlog-add; under --dry-run make no backlog-add call). FORBIDDEN: everything else.

Arguments

ArgumentBehavior
[file]Required. Path to .md/.mdx file to expand
--dry-runShow proposed changes without writing. Print before/after diff
--lang <code>Language override (default: auto-detect)
--tone <value>casual / technical / formal / marketing (default: auto-detect from existing text)
--site-dir <path>Content collection root — enables internal link discovery + voice matching
--domain <niche>Override domain detection (one of 17 niche IDs from domain-profile-registry.md)
--skip-researchSkip web search; expand using existing content + LLM knowledge only
--rewriteAllow rewriting existing sentences that have concrete defects (factual errors, grammar, outdated info). Without this flag, existing text is never modified.
--lightSkip reporting, recording findings through backlog-add, knowledge curation. Just expand and write.

Phase 0 — Read & Score

0.1 Validate + Extract

  1. File type validation (GATE 1). Dirty file check (GATE 2).
  2. Parse frontmatter. Mark mutable fields (title, description, keywords, author). All others immutable.
  3. Extract protected regions: fenced code blocks, MDX components. Store with position markers.
  4. Language detection: --lang → frontmatter → content analysis → fallback structural-only.
  5. Resolve the active language file from ../../shared/includes/banned-vocabulary/languages/ using the normalized base code. If missing: load en.md and emit WARNING: banned-vocabulary fallback -> en.

0.2 Domain Detection

Cascade: --domain → scan --site-dir articles for niche signals per domain-profile-registry.md → fallback general. YMYL niches emit credentials WARNING.

0.3 Voice Profile

If --site-dir has 3+ blog articles: extract voice profile per humanization-rules.md (rhythm, person, formality). Inconclusive → default rules only.

0.4 Score

Dispatch follows ../../shared/includes/execution-policy.md through env-compat. Reuse existing authorization within that policy; session restrictions take precedence. Run each required gate and report its actual independence or an unmet requirement.

Dispatch prose-quality-scorer + structure-analyst agents in parallel per env-compat.md. Score across 6 dimensions (PQ1-PQ17 from prose-quality-registry.md). Short articles get the same scrutiny as long ones — every sentence matters more when there are fewer of them.

Record: before-scores, tier, weak sections, thin sections (<100 words), missing elements per niche profile.

0.5 Internal Link Discovery

If --site-dir provided: scan the content collection (Glob *.md + *.mdx), read titles/descriptions of 10-20 articles, identify 5 most related by topic overlap. These become internal link candidates for Phase 2.

Print:

SETUP: [file] | [lang] | [tone] | Domain: [niche] | Voice: [matched|default]
SCORE: [composite]/100 ([tier]) | Weak: [N sections] | Thin: [N sections]
LINKS: [N candidates found | no site-dir]

Phase 1 — Research

Skip if --skip-research set. Print: "Research skipped. Expanding from existing content + LLM knowledge."

1.1 Topic extraction

From article content + frontmatter, identify: primary topic, subtopics covered, subtopics missing (from Phase 0 scoring).

1.2 Web search

Perform 2-4 targeted web searches about the topic — NOT competitor analysis, but factual research for expansion:

  • Facts, statistics, recent developments about the topic
  • Specific details the article is missing (from Phase 0 thin-section analysis)
  • Named sources, dates, version numbers for entity grounding

1.3 Fact sheet

Assemble research into a structured fact sheet (same format as write-article topic-researcher output). Each fact has source attribution + year. Tag conflicts as [CONFLICT].

If web search unavailable: note research_limited: true, proceed with LLM knowledge only (clearly marked).


Phase 2 — Expand + Optimize

This is the core phase. Expand THEN optimize in one pass — no separate faz.

2.1 Backup

Copy original to <file>.content-expand-backup. All work on temp copy. --dry-run: skip backup, work in memory only.

2.2 Expand (PRESERVE ORIGINAL TEXT)

DEFAULT: Do not rewrite existing text. Rewriting human prose with AI prose triggers detection on the entire article. Expand by ADDING content around what exists.

What you CAN always do:

  • Add new paragraphs between or after existing ones
  • Add new H2/H3 sections for missing subtopics
  • Add intro/conclusion if missing

What you CANNOT do without --rewrite:

  • Rephrase existing sentences
  • Merge or reorder existing paragraphs
  • Change existing word choices or headings

With --rewrite: Rewrites are allowed ONLY for sentences with a concrete defect: factual error, grammatical mistake, nonsensical claim, or outdated information. Each rewrite must state the reason (e.g., "Fixed: claimed population is 5M, actual is 8.3M per 2025 census"). Style preferences ("sounds better") are NOT a valid reason.

For ALL new content, apply humanization-rules.md constraints:

  • Sentence variation (fragments + long), contractions, parenthetical asides
  • Entity grounding (specific versions, dates, names from research)
  • Voice matching if profile available — match the existing article's voice, not your default
  • No throat-clearing (G12), BLUF per section (G9), max 300 words/section (G6)
  • Stats and volatile practical facts must remain traceable to the fact sheet (G11)
  • Do not build paragraph rhythm around repeated source lead-ins such as Według X (2025)
  • Use a hard source-name budget: the same full institution/source name should appear no more than once per section and no more than 3 times in the whole article body, excluding a compact ## Źródła section
  • Use (odczyt: miesiąc rok) only for volatile practical facts, not for stable historical description
  • Do not append a process-heavy research appendix such as Źródła wykorzystane przy aktualizacji
  • End public articles with a compact ## Źródła section unless the host project explicitly forbids visible sources
  • In ## Źródła, keep 3-6 grouped bullets max: source title + link only
  • Group repeated institutions into one bullet whenever possible, e.g. - **APSARA National Authority:** [Temple page](...), [Restoration update](...)
  • Do not add filler closers like ## Na koniec if they only restate the article
  • Prefer practical expansion blocks (specific H2s, lists, route notes, local comparisons, FAQ at the end) over replacing the opening with smoother narrative prose
  • For practical/service-intent articles, add or preserve a short ## W skrócie block immediately after the italic lead and before the first image or H2. Keep 3-5 bullets max.

Use these exact output shapes when applicable:

## W skrócie
- [Najważniejsza decyzja / odpowiedź]
- [Najważniejszy wymóg / koszt / limit]
- [Najważniejsza opcja / wyjątek]
- [Najważniejszy warunek praktyczny]
## Źródła
- **[Instytucja / grupa źródeł]:** [Tytuł 1](...), [Tytuł 2](...)
- **[Instytucja / grupa źródeł]:** [Tytuł 3](...)
- **[Instytucja / grupa źródeł]:** [Tytuł 4](...)

2.3 Internal Links

Insert 2-5 contextual internal links from Phase 0 candidates. Validate each via Glob. Unverified → [UNVERIFIED LINK], not auto-inserted.

2.4 SEO + Schema

Read domain-profile-registry.md for niche-appropriate schema:

  • Detect existing @type. If specific (Recipe, HowTo, Event) → preserve and merge. If BlogPosting only → upgrade per niche.
  • FAQ: if article now has Q&A content + niche allows FAQ → add FAQPage schema.
  • Inspect the local content schema/config before mutating frontmatter. Treat the schema as the source of truth for allowed fields.
  • OG tags: write og:title, og:description, og:type, og:image only if those fields are clearly accepted by the local schema. If not, inherit layout-level OG behavior and record OG: inherited-from-layout.
  • dateModified / modifiedDate / updatedDate: Find the exact modification-date field already accepted by the collection schema (common names: modifiedDate, updatedDate, dateModified, lastmod, updated) and update that field. If no such field exists and schema support is unclear, do not invent modifiedDate; leave frontmatter unchanged and record Date field: unchanged (schema-blocked). Never touch publishDate / date / publishedDate — that's the original publication date.
  • Meta title/description: only update if currently MISSING. Never rewrite existing meta that the author wrote.

2.5 Anti-slop Review

Run anti-slop check on expanded content (same as write-article Phase 4):

  • Hard/soft banned vocabulary per banned-vocabulary/core.md + active language file + --tone
  • G12 anti-patterns (throat-clearing, superlatives, keyword density)
  • BLUF compliance (G9), chunkability (G6), citation compliance (G11)
  • Dispatch anti-slop-reviewer agent (read ../../skills/write-article/agents/anti-slop-reviewer.md) for all articles regardless of length.

Apply this review to human-facing prose only. Do not count frontmatter keys, schema-only metadata, file paths, URLs, image names, JSON-LD/schema, code, or raw source lists as banned-vocabulary violations unless the task explicitly asks to audit those zones as prose.

Fix all CRITICAL violations. Fix WARNINGs if localized.

2.6 Re-score + Rollback

Score expanded article (same 6 dimensions). If ANY dimension regressed → revert that section's changes. Never deliver a lower composite score.

2.7 Adversarial Review

Load adversarial-loop-docs.md now. Run: ~/.zuvo/adversarial-review --json --mode article --files "<temp-file>" (fallback: --json --mode audit + WARNING). CRITICAL → fix. WARNING → fix if localized. If the script returns status: "timeout" or exits 124, record Adversarial review: skipped (timeout) and continue without blocking the article.

Record the verdicts after triage: every finding is fixed, rejected (a false positive) or deferred — record each by its ID: in ONE call, ~/.zuvo/adversarial-review --record-disposition ID-1 fixed --record-disposition ID-2 rejected …, per ../../shared/includes/adversarial-loop.md Step 4.9 (the review lists its IDs on stderr).

2.8 Replace Original

Protected regions re-inserted. Frontmatter immutable fields preserved. Replace original with expanded temp copy. Delete backup. --dry-run: print diff only, no file changes.


Phase 3 — Output

Before/After Summary

CONTENT-EXPAND COMPLETE
-----
File: [path]
Words: [before] → [after] (+[N] added)
Score: [before]/100 ([tier]) → [after]/100 ([tier])
Domain: [niche] | Schema: [type(s)]
Sections added: [N] | Sections expanded: [N]
Internal links: [N] added ([N] verified)
FAQ: [N items | none] | OG: [present | inherited-from-layout | schema-blocked]
Voice: [matched | default] | Research: [N facts used | skipped | limited]

Run: <ISO-8601-Z>	content-expand	<project>	-	-	<VERDICT>	<TASKS>	3-phase	<NOTES>	<BRANCH>	<SHA7>	<INCLUDES>	<TIER>
-----

Append via wrapper (REQUIRED). Never >> directly to ~/.zuvo/runs.log — the wrapper is the gate that verifies a retro entry exists for this run. Order: retro bash executed → wrapper invoked → completion claimed.

printf '%b\n' "$RUN_LINE" | ~/.zuvo/append-runlog

Expected stdout: OK: appended to runs.log (retro verified for <skill> on <project>). If exit 2 with RETRO_REQUIRED — go execute the retro bash from retrospective.md first; never bypass with ZUVO_SKIP_RETRO_GATE=1. After the wrapper succeeds, print a Logs: evidence line (tail -1 ~/.zuvo/retros.log, grep -c "^<!-- RETRO -->" ~/.zuvo/retros.md, tail -1 ~/.zuvo/runs.log) before claiming completion. Printing the markdown retro section without executing the bash leaves all three log files empty.

VERDICT: PASS (expanded, no regressions), WARN (research_limited or voice delta MED+), FAIL (adversarial blockers), BLOCKED (dirty file, binary input). NOTES: [file basename] [before]->[after] +[N]words [tier] (max 80 chars).

Reporting (skip with --light)

Unless --light: write report to zuvo/reports/content-expand-YYYY-MM-DD.md. Write JSON per article-output-schema.md. Run knowledge curation per knowledge-curate.md. Record each finding this run reports and does not fix (an adversarial WARNING deferred because it is not localized, a validation WARNING left in the text), and nothing else, through backlog-add, one call per finding. A Generic write (backlog-protocol.md "Filing from a skill"): ~/.zuvo/backlog-add --repo "$R" --class <C> --conf <N> --source content-expand --file "$F" --line <n> [--anchor "$A"] --title "$T", F the expanded file. This skill files CQ or BUG only: <C> is CQ for a quality defect and BUG only when the finding names the input and the wrong output; BUG takes --anchor "$A", copied from the line that shows the defect ("The location rule"); a whole-file finding is --line 1 with a "Whole file: ..." title and no --anchor. Assign "$R", "$F" and "$T" before each call, "$A" only when you pass --anchor, as "Free text goes through a variable" in that section says; an empty value you pass is a bug, and backlog-add refuses a missing required field (REFUSED missing-field:<f>). Report the B- or F-id each call prints, plus each NOT PERSISTED (<reason>) by name; on a non-zero exit act on the protocol's exit table, and never append by hand. With --dry-run make no backlog-add call: list in the report what would be recorded. Recording findings through backlog-add commits and stages nothing. This skill lists the wrote= paths backlog-add printed as Backlog writes: <path>, ... (Backlog writes: none when there are none) in its final summary, whether it runs standalone or inside another skill, for the calling skill's closing commit to carry when there is one (backlog-protocol.md "Filing from a skill", Committing what backlog-add wrote).

Retrospective (REQUIRED)

Follow retrospective.md. Gate check → structured questions → TSV emit → markdown append.

Next steps: zuvo:review [file] | zuvo:content-audit [file] | zuvo:ship

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.