awesome-content-repurpose · git:20260910.f512a35 · 2026-09-10 · sha256 90c0557215e5f039

awesome-content-repurpose git:20260910.f512a35A

Immutable. This exact content never changes and is served at /api/v1/blob/90c0557215e5f039.

---
name: awesome-content-repurpose
description: "Turns one existing text — a URL, a file, or pasted notes — into platform-native posts for a canonical set of 26 platforms: source notes every claim traces back to and verifies, an interview for platforms, voice and length, an opener catalog and paragraph-shape rules that keep posts from reading as generated, hard character caps and a per-platform depth band each version is written to, a two-stage anti-slop audit, one dated file per platform in the format awesome-content-publisher reads. Use when asked to repurpose an article into posts, adapt a text for named platforms, or 'адаптируй статью под соцсети'. Do not use for a scheduled campaign from product sources (awesome-content-campaign), to publish (awesome-content-publisher), or to build the voice profile (awesome-content-voice)."
license: MIT
metadata:
  author: Khasky
  tags: ["content", "repurposing", "social-media", "writing", "publishing"]
  documentation: "https://github.com/khasky/awesome-agent-skills/tree/main/skills/awesome-content-repurpose"
---

# Content Repurpose

One text in, one post per platform out, each written to that platform's register rather than trimmed to its cap. Then the posts are filed, and publishing them is one more step the user chooses.

The rule that makes this skill different from writing posts from scratch: the source is the boundary. A repurposed post may sharpen, cut and reframe, but it may not add a claim, a number or an implication the source does not carry, and it may not invert the source's point by compressing it. The text arrives settled — where it came from and whether it may be published are the user's business, decided before this runs.

This skill owns the repurposing craft and orchestrates the rest. Two of its own reference files carry what every run is checked against, and both are read before a line is written:

- `references/authored-style.md` — the register, as countable patterns: the seven opening shapes that work, the five that are banned, how much first person a run may carry, and the paragraph-shape rules that keep a post from turning into a stack of one-line fragments.
- `references/platform-specs.md` — the 26-file output contract, the hard character caps, and the depth band each platform's version is written to.
- `scripts/gate.mjs` (Node 18+, no dependencies) — the mechanical gate: every check a script can settle, in one pass, with `--self-test` proving each check fires before it is trusted to pass anything. Phase 5 runs it first and the judgment passes only on what survives.

Two files persist across runs in the runtime's scratch root, beside the per-run `repurpose/<slug>/` folders and never in the invocation directory: `repurpose/defaults.md` (the interview answers from the last run) and `repurpose/platform-cache.md` (the last live platform check, dated). Both are the agent's own temporary files; when the runtime wipes them the run simply asks in full again.

It reuses the rest by reference rather than by restating:

- `references/platforms.md` (ships with `awesome-content-campaign`) — the canonical slug table: target detail per platform, media requirements, and which genre file governs each.
- `references/genre-micro-post.md`, `references/genre-long-article.md`, `references/genre-community-post.md` (same skill) — the register each genre demands.
- `awesome-content-graphics` — the whole image stage when a post needs a picture and none exists: the look inputs, the offline HTML/CSS renders, the headline gate and the pick gate. Nothing about making graphics is reimplemented here, including the chart craft it takes from `dataviz`.
- `awesome-humanize-en`, `awesome-document-style`, `awesome-slop-audit` — loaded only under `--deep-audit`. The part of their catalogs that applies to a feed post is written out as the Phase 4 checklist, so an ordinary run reads nine lines instead of three skills.
- `awesome-content-voice` — the author's voice, when a profile exists.
- `awesome-content-publisher` — everything about publishing: bridge, login, ledger, pacing, read-back.
- `awesome-translate-ru-en` — whenever the output language differs from the source, in either direction.

## Invocation

```
/awesome-content-repurpose <url | file | pasted text> [--platforms <slug,slug>] [--publish] [--recheck] [--deep-audit]
```

No source given → ask for one before anything else. `--publish` is a preference recorded in Phase 2, not a bypass of the publisher's own confirmation gate. `--recheck` forces the live platform check in Phase 3 without asking; `--deep-audit` loads the external humanity catalogs in Phase 4 instead of the inline checklist.

## Phase 1 — Read the source, write the source notes

Get the text onto disk first. Working state never lands in the invocation directory — it goes to the agent's own scratch or session directory for this run (whatever the runtime provides: a session scratchpad, a temp path under the agent's home such as `~/.claude/`, or `TMPDIR`), in a `repurpose/<slug>/` folder there. The user asked for posts, not for a folder appearing in whatever repository they happened to be standing in. Only the final deliverable moves to a place the user names (Phase 6), and the run states both paths.

- URL — a plain fetch first; a live browser when the page is a JS app that returns an empty shell, so rendered content is not silently missed. Driving a browser means driving one of the user's, so it is not a silent step: when the session exposes more than one browser bridge, ask which one before the first navigation and remember the answer for the run; either way, name the browser that was used and warn that it is busy while the read runs. A page that turns out to need a logged-in session is no longer a public read — run the full target gate in `references/browser-interaction.md` (ships with `awesome-content-publisher`) before touching it. Save the extracted text to `source/` inside the working folder.
- File — read it directly; a folder gets an inventory first, then the prose.
- Pasted text — save it to `source/` on arrival, like everything else. Long source text stays out of the conversation context.

Then write `source-notes.md` beside it, which every later phase is checked against:

- The point — one sentence: what this text argues or reports. Compression that contradicts this line is a defect, not an interpretation.
- Supporting claims — one line each, in the source's own terms.
- Numbers — verbatim, with the conditions the source attaches to them. A number without its condition is not repurposable.
- Provenance — what this text actually is and where it came from: which release, which changelog, whose announcement, what date. Two sentences at most, and every post needs one of them, because a reader who does not know what is being discussed cannot use the rest.
- Quotable lines — 3 to 5 verbatim excerpts worth keeping intact, with their location.
- Named things — people, products, versions, places the source names, spelled the way it spells them.
- What the source does NOT say — the tempting adjacent claims a shorter version would drift into. This section exists because compression invents.

A historical source stays historical. Where the text is a retrospective, the posts say so in their own words — `in the article I wrote at the time`, `by the 2023 update`, `this is a retrospective, not a current-state audit` — and an old product rule is never rewritten into a present-tense fact.

The link a post may carry is not automatically the link the source arrived on. A conversation with an assistant is a private artifact, so a share URL on an assistant's own domain never reaches a post: not in the body, not in frontmatter `links`, not as a "full thread" closer. The hosts this covers, and any other assistant's own domain that appears in a source: `chatgpt.com`, `chat.openai.com`, `claude.ai`, `gemini.google.com`, `aistudio.google.com`, `notebooklm.google.com`, `deepseek.com`, `chat.deepseek.com`, `grok.com`, `x.ai`, `copilot.microsoft.com`, `chat.mistral.ai`, `chat.qwen.ai`, `kimi.com`, `poe.com`, `perplexity.ai`, `hf.co/chat`, `you.com`, `phind.com`, `meta.ai`, `character.ai`. Three reasons, each sufficient: for most readers the URL does not open at all, a research transcript is the opposite of the author's own knowledge, and publishing a session is a decision the user never made. The URL stays inside `source-notes.md` as provenance and goes nowhere else.

So the run looks for the link the post deserves, and the search is bounded: one query for what the text is actually about (the release note, the changelog entry, the documentation page, the repository, the vendor announcement, the original article), the best public result opened once, and it counts only if it carries the claim the post will make. Nothing public in that one pass → the post ships with no link and an empty `links`, which is honest. A second query, a guessed URL, or a fall back to the chat share is not.

The point, the notes and the proposed link are shown on the interview screen in Phase 2 rather than in a gate of their own, so the user answers everything in one round. Every gate in this skill goes through the structured-question UI: a gate written as a closing sentence the user must answer in prose reads as narration and gets passed over.

## Phase 2 — Interview

One round, structured-question UI when available, custom answer always allowed. The round opens with the Phase 1 notes: the point in one line, the provenance, and the link the run proposes (or that none exists), with the options correct · the point is wrong, here is the right one · use this link instead · no link at all · stop.

Then the answers. When `repurpose/defaults.md` exists from an earlier run, the interview is one screen: the last run's answers summarised (platforms, every target detail, voice, language, shape, emoji and hashtags, what happens after the files exist) and three options — same as last time (recommended) · change something · start from scratch. "Change something" re-asks only the items the user names; "start from scratch" runs the full interview below. With no defaults file the full interview runs once, and its answers are written to `repurpose/defaults.md` at the end of the round so the next run opens on the one screen. The file records answers, never source material: no notes, no text, no links from the source.

The full interview, on a first run or a reset:

1. Platforms — the default is the canonical set of 26 in `references/platform-specs.md`, and the run asks whether the user wants all of them before it asks which ones. The realistic answer is "all", so the first question is a single one — write for the whole set, or trim it — with "all of them" the recommended option and the count stated (`All 26`). Only when the user chooses to trim does the checkbox pass run, split across several questions because the question UI caps options per question, and phrased as removing rather than adding (`Untick anything you do not want`). This ordering exists because the UI has no pre-checked state to give: a bare checkbox list makes the common answer the most laborious one, twenty-six ticks to say "everything", which is the shape that gets abandoned halfway.

   The remaining slugs on `awesome-content-campaign`'s table (`vk-wall`, `telegram`, `facebook-group`, `hackernews`, `write-as`, `telegraph`) are available on request and never added on the run's initiative. Keep one open option for a platform neither list carries.

   Never offer a shortlist, a bundle, a "recommended set", or a subset inferred from the source, the language, or what looks like a fit — narrowing the list is a decision the user did not delegate, and a platform missing from the question is a platform they cannot choose. Keep one open option for a platform the table does not carry.

   Then collect the target detail each selected platform requires, under the rule below. Two annotations, when the data exists: mark platforms where `publish-state/performance.md` shows the user's own median engagement, and mark platforms where the publisher's ledger already carries this source — repurposing into a feed that already has this piece is usually a mistake worth surfacing.

   A target question offers what the user actually has, and it is one question per platform. The Target column names a kind of thing (an instance, a community, a board, a squad, a client), and the failure to avoid is filling that in with plausible names the run made up — three Mastodon instances the user has never heard of, three Lemmy servers when their account lives on one, a menu of Nostr clients chosen from general knowledge. A user cannot answer "which of these three" when nothing in the question says why those three or which is theirs, and the honest reading of such a menu is that the run does not know either.

   So, in this order:

   - The default plus an escape hatch, and a third option that opens the account. The question offers the value from `defaults.md` or the table's canonical default, `another one, I will type it`, and `show me my options`. Only that third answer sends the run to the browser: then the real list is one read away and it is read — the communities their own instance carries, the squads they have joined, the boards on their profile, the client they are signed into — through `awesome-content-publisher`'s `references/browser-interaction.md`, as a read and never a write, and the options come back ranked by fit to this post's topic with the number that makes each choosable. Reading the account on every run, unasked, is a browser session and a target gate spent on a question the user usually answers from memory in two words.
   - Never a menu of guesses. `mastodon.social` and `another server` is a real choice; `mastodon.social · fosstodon.org · hachyderm.io` is a quiz.
   - Never re-ask what is already settled. When the user has said `lemmy.world`, the instance is decided and the only open question is which community there. Re-offering `lemmy.ml` and `programming.dev` reads as the run having forgotten, and it invites an answer that contradicts the account they actually have.
   - One platform per question. A question headed `lemmy target and daily-dev target?` forces one answer to cover two unrelated decisions, so neither can be answered properly. Give each its own, and say in the question what the detail is for.
   - A hazard is not a question. Where a platform has a dangerous path and a safe one, take the safe one by default and say so in one line; do not turn the danger into a gate the user clears on every run. `substack` is the worked example: publishing an Article from the personal profile sends no email at all, so the run takes that path and never opens with "publishing also sends email that cannot be recalled, which publication?" — a question that is unanswerable for an account with no publication, and that reappears every run because nothing about it can ever be settled. Ask only when the user wants the irreversible path.
2. Voice — first person, the author reporting their own experience with the thing (default) · first person plural · neutral third person, for a source the author has no standing to have used · a voice profile from `awesome-content-voice` (path; `voice/*.md` is where to look) · a style guide from `awesome-style-mimic`.
3. Output language — same as the source (default) · another language. A different language means the posts are written in it by someone who thinks in it, never carried across word by word; Phase 4 holds the rules, and for the Russian and English pair they come from `awesome-translate-ru-en`, applied in whichever direction this run needs.
4. Length and shape per platform — native to the platform (default) · deliberately short · thread or multi-part where the platform supports it and the content is genuinely sequential.
5. Emoji and hashtags — a light sprinkle, one or two per short post where they land naturally (default) · none · a rule the user states. Hashtags follow the platform's researched norm either way.
6. What happens after the files exist — publish now · publish at a time the user names · files only. Whatever the answer, the files are written first.

One image, and it goes everywhere the platform takes one. Ask for media once, with the cheap answers first: I will supply one (path) · no image, drop the media-required platforms · generate a set with `awesome-content-graphics`. Generation is the explicit third choice, never the default, because it opens a whole rendering stage and a second gate. On that yes, collect the look inputs in the same round — a brand palette, reference images or examples the run should sit next to, a render approved on an earlier run, or a description in words — because that skill builds the set out of them and asking later interrupts the run for nothing.

No image supplied means a whole set and a second gate, never one graphic chosen by this skill. The set size is the user's answer there (5, 25, 50, 100 or a number they type), and the variant rules, the spread of the set, the spread across the source's different facts, the gallery and the pick gate all belong to `awesome-content-graphics` and are not restated here; this phase hands it the facts from `source-notes.md`, that file's "What the source does NOT say" section as the boundary, `repurpose/<slug>/media/` as the output folder, the look inputs, the target ratio from Phase 3, and the output language the interview settled, so the words on the graphic match the posts and the user is not asked the same question twice. Then it takes back the chosen render, its alt text and the `graphics.md` receipt. That skill not installed → say so, and offer the same two options: the user supplies an image, or the media-required platforms are dropped. What belongs to this phase is the sequencing: the interview's media answer only settles *whether* a graphic is generated. Which one ships is a separate question, asked after the set is rendered and the user has a link to look at, and no post file declares an attachment until they have answered it. A user who supplied their own image never sees this gate. Whatever image the run ends up with — supplied or generated — is then attached to every selected platform whose Media column is `optional` as well as every platform where it is `required`, not only to the ones that cannot post without it. A run that renders a graphic for `instagram` and ships text-only posts everywhere else has done the work and thrown most of it away; the same picture earns its keep on `linkedin`, `x`, `mastodon`, `tumblr`, `patreon` and the rest, and on the article platforms it becomes the cover image.

Three exceptions, and only these: a platform whose Media column says media is not supported (`hackernews`) gets nothing; a platform whose requirement is video cannot be satisfied by a still, so it is dropped rather than given the graphic; and a post whose own text argues against the picture — the user says so, or the image contradicts what that version says — carries no attachment, with the reason recorded in `campaign.md`. Every attachment carries alt text describing what the image shows, the same text on every platform.

## Phase 3 — Platform check

The structural facts are already in the tables and do not expire: the hard caps are the floor in `references/platform-specs.md`, the hashtag norms and media requirements are in `awesome-content-campaign`'s `references/platforms.md`, editor types do not move. Live research may only lower a cap, never raise it; a number that cannot be verified stays at the table value, and a number that looks higher is treated as unverified. So this phase is off by default and the user turns it on.

Read `repurpose/platform-cache.md` and ask one structured question: *The last live format check for the selected platforms was YYYY-MM-DD (or: has never run). Check all selected platforms again?* — no, use the last references (recommended) · yes, check all of them · check only these. `--recheck` answers yes without asking. On "no", the whole phase is skipped and the manifest records the cache date that was relied on.

Two things run regardless of the answer, because they are about the user's specific target rather than the platform, and they change without notice: the rules of the community actually being posted to — the subreddit, the Lemmy community, the Facebook group, the daily.dev squad, a Hashnode or Medium publication's submission rules — and a community that forbids link-drops or self-promotion is reported with the option to pick another target; and anything the user's account tier changes where the cache does not already record the tier.

When the check does run, it verifies the volatile facts only (a cap that may have moved, a media format, a hashtag norm the table marks *verify live*), writes each entry to `repurpose/platform-cache.md` with its platform, values, source URL and checked-on date, and reports what changed against the tables. A cache entry records the page that was actually opened — a value recalled from memory, taken off a search-result snippet, or written from a URL that did not load is not a source: record that it could not be reached and treat the table value as still binding.

## Phase 4 — Write

Load three things before writing: `references/authored-style.md`, `references/platform-specs.md`, and the genre file for each selected platform. The register belongs to the genre, the shapes and the numbers belong to the two reference files, and this phase adds the repurposing craft on top.

Each platform version is composed to its own band from the start. The band is in `platform-specs.md`, and it is a writing instruction rather than a validation threshold: a `buymeacoffee` unit is drafted as a two-to-five-thousand-character mini-blog, a `peerlist` unit as four hundred characters, and neither is derived by cutting the other. Writing one long version and trimming it per platform at publication time is the single most expensive mistake this skill makes, because the cut always falls on the tail: the pricing, the closing line, the link. When a version comes out over its cap, it is rewritten to the band, never amputated.

The opener comes from the catalog in `authored-style.md`, and the run varies the shape across platforms rather than reaching for the same one every time. No post opens on an abstract category doing something a category cannot do, and none opens on a vague event with a vague time attached.

Paragraphs are paragraphs. Never three one-line paragraphs in a row, and in anything over 1500 characters the one-line share stays well under half. A stack of short lines is the loudest structural tell these posts carry and it survives every other pass, because each individual line reads fine.

One post, adapted per platform — not one post per platform. The run picks ONE idea out of the source and writes it once; every selected platform then gets that same post adjusted for its mechanics: trimmed to the verified cap, hashtags in that platform's norm, the title-and-body split where the platform has one, the hook above the fold where the feed cuts. A reader following the author on three of them should recognise the same post three times, not discover three unrelated ones. Producing a different extract per platform is the failure this rule exists to prevent: it multiplies the work, dilutes the message, and leaves nothing that can be pointed at as "the post".

The user asks for more than one idea → that is more than one run, or an explicit list of units decided together up front and stated in the manifest. It is never a side effect of having several platforms selected.

Choosing the idea: compression is selection, not summarizing. A 2,000-word article becomes one post about its sharpest single point — not a synopsis, not a table of contents, not "here are the 5 takeaways" unless the source genuinely is five takeaways. The reader who never opens the original should still get something whole.

What makes an idea worth the post. Prefer the mechanism, the consequence, the thing that changes how someone works — and skip the inventory. A list of version numbers, a table of names, a feature roll-call carries no insight even though it is factual and easy to extract: it tells a reader what exists, never what it means for them. "Messages carry text, not files, so two sessions stay informed and still overwrite each other" is a post; "2.1.224+ on Linux and macOS, 2.1.234+ on Windows" is a footnote to one. Where a number genuinely matters, it belongs inside the mechanism it constrains, not as the subject.

Verify the claims the idea actually uses, and only those. Verification runs here, after the idea is chosen, because the ladder is expensive and a source carries far more claims than one post will ship. For each claim, number or command the unit will carry that is current, version-sensitive, priced, benchmarked, install-related, support-matrix-related or counted (stars, downloads, rank): the official site, the official repository, the official documentation, the paper or model card, the vendor's own announcement, in that order, stopping at the first that settles it. Reputable secondary sources only when none of those carries it. A claim the unit does not use is not verified, however tempting.

Where the source is stronger than the evidence, keep the interesting idea and correct the claim. `works on any PC` becomes `runs on surprisingly modest consumer hardware, with real RAM and GPU caveats`; `native video generation` becomes `writes the code that a renderer then previews`. A claim that cannot be verified either goes with the hedge the evidence supports or does not go.

Numbers that came from the project rather than from an independent test say so: `the project reports`, `the paper reports`, `the README shows`. A project benchmark presented as a universal guarantee is a fabrication with a citation attached. Fast-moving counts are date-stamped in the notes and written evergreen in the post (`200k+`, `when it landed`), because a star count is stale within the week. An install command is verified or it is not published: never invented, and the official quick-start path is preferred over a source build unless the source is specifically about building from source.

Every post carries its provenance. One clause, early, saying what is being talked about and where it came from: the release, the changelog, the announcement. Without it a post about a mechanism reads as an opinion out of nowhere, and the reader cannot tell whether it is news, a manual, or a thought.

Write it as the author's own experience, because that is what a feed post is. Someone saw the thing, tried it, and is reporting back: ran into it, spent an evening on it, changed how they set something up, would not bother with half of it. First person, an opinion, a recommendation, a thing that annoyed them. A post that reads as a neutral summary of someone else's announcement has no reason to exist on a personal feed.

The frame is invented on purpose; the substance never is. Allowed: having read it, tried it, set it up this way, preferred one option, given up on another, expected something else. Forbidden: invented outcomes and measurements, a build time cut by a number, a bug caught, a team convinced, a client saved, any result the source does not carry. The Phase 5 fidelity pass reads first-person framing as framing and any specific result inside it as a fabrication.

No calendar dates, in any language. "Checked 30 Aug 2026", "as of August 2026", "30 августа разбирался" is the loudest machine tell a post can carry, because nobody stamps their own writing with an audit date. Recency is a relative word: yesterday, last week, the other day, recently, a few days ago, soon. The single date allowed to survive is one that is the subject itself, a deadline or an event day the reader has to show up for. A date attached to the author's act of reading, checking or verifying is never written, in the body, in a graphic, in alt text, or in a title. The frontmatter `scheduled` field is machinery, not prose, and is the one place a date belongs.

Cut the specification. Version floors, per-OS build numbers, tier matrices and requirement tables are what release notes are for, and a person writing about an update says roughly what changed and how recently. "Needs a fairly recent version" is how that sentence sounds. Where a constraint genuinely decides whether the reader can use the thing at all, it gets one plain clause and never a matrix; a long-form platform may carry one line more, still as prose. Whatever number does survive keeps the condition `source-notes.md` recorded.

Energy is set by the genre, and it is read before writing rather than after. A micro-post opens on the hook and carries its emoji where that platform's natives use them; a community post opens on the problem and stays plain; a long article earns its first line. Where the genre supports it a post is allowed to sound like someone who found something good: an opener that promises a payoff, a sharp line, the question the reader already has. Still banned everywhere: emoji as bullets, hype closers, and a loud label such as "PRO TIP" stamped on a post that carries no tip.

No em dash in a post. Zero, not "sparingly". The `—` character (and its long siblings `–` and `―`) is the single most recognisable machine fingerprint in a feed, and hand-set typography is not what a person types into a composer anyway. Every one of them becomes a full stop, a comma, a colon, or a pair of parentheses, and the sentence is usually better for it. This covers the body, the title, hashtag lines, alt text, and any words on a graphic. Two exceptions and no others: a verbatim quotation that carries one (prefer quoting a different line), and text inside a code block or a command. A hyphen inside a compound word, a flag or a slug is not a dash and stays.

Emoji are part of how these platforms are written, so use them, and place them the way a person does. A writer does not decorate a post evenly. They punctuate it: the emoji lands right after the phrase that earned a reaction, and the choice reports what the reaction was. 🤯 after the number nobody expected, 🧐 next to the caveat, 🤑 on the cost, 😅 on the part that went wrong. Put it at the end of that sentence or open the post with it, and the reader feels a person reacting rather than a template being filled.

The budget is 0 to 5 for a whole text, scaled to its length, and the exact count matters less than the spacing. A micro-post carries none or one. A medium feed post carries one or two. A long article carries three to five across the whole piece, and it is allowed to go several paragraphs with none. Two emoji inside the same paragraph, or a pair a line apart, reads as decoration however good each one is on its own; keep real distance between them.

On a piece with headings, pick ONE surface and stay on it. Either the emoji live in the prose, three to five across the article, or one sits at the end of every heading — `## What it costs to leave one running 🤑`, `## What I would take away 🧐`, and so on down the whole outline. Never both surfaces in one piece, and never a subset of the headings: two decorated out of six is the pattern a reader clocks immediately, because it looks like whoever wrote it stopped caring after the second section. If the last heading has no emoji that honestly fits, that is the signal to use the prose surface instead and leave every heading bare. The article's own title sits outside the choice and may carry one either way. The check is countable: headings with an emoji must equal 0 or all of them.

Restraint still applies: never as bullet markers, never one per line, never a row of three, never in place of a word the sentence needs, and never on a platform whose natives do not use them (the genre file and the Phase 3 research decide that). The interview's emoji answer overrides this default in both directions.

Write it in the English people speak. The register is a competent person talking, so the vocabulary stays where speech is. Literary and rare words are the tell that something reached for a synonym instead of a word: `duller`, `says it outright`, `thus`, `hence`, `myriad`, `plethora`, `albeit`, `bespoke`, `salient`, `wherein`, `heretofore`, `deliberately`. Write `more boring`, `says it plainly`, `so`, `many`, `on purpose`. The test is spoken, not written: would you say this word out loud to a colleague? No → replace it. Technical precision is untouched by this — `worktree`, `merge conflict` and `file lock` are the words for those things and stay.

Every post has a person in it. A run that produces four flat declarative sentences and stops has written a machine report, whatever the facts are. Somewhere in each post there is a reaction: the emoji where the surprise lands, the question the reader already has, a short fragment, an aside, an exclamation on the part that went wrong. One human signal per post is the floor, and it is checked in Phase 5. The exceptions are narrow and named: a platform whose natives write flat (`hackernews`), and an interview answer that turned emoji off — and even then a question or a wry half-line still belongs there, because flat register is not the same as nobody being home.

Name what a tool is the first time the post mentions it. A paragraph that compares products by bare name only works for a reader already inside the ecosystem: `Agent Teams does not change this. MCP Agent Mail gets closest with file reservations` tells everyone else nothing. The first mention carries a short identifying clause — what kind of thing it is, and where it matters how it is switched on: `Agent Teams (Claude Code's experimental multi-agent mode, behind CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS)`, `MCP Agent Mail (a third-party coordination server for AI coding agents)`. This applies to every platform and every length; on the shortest posts it is the reason to name one tool instead of three.

One hashtag set for the whole run, trimmed per platform, never re-invented. The tags come from the unit's subject once, then each platform gets the share its norm allows: the fuller block where hashtags are the discovery mechanism (`mastodon`, `instagram`, `tumblr`'s tag field), one or two on `x` and never more (more measurably costs reach there), none where they read as noise (`hackernews`, community rooms, `reddit`). Trimming drops whole tags off the end. A tag is never cut mid-word to fit a cap, and no post ends on half a hashtag. A platform whose post file has an empty `hashtags` list because nobody thought about it is a defect, not a decision.

The link belongs to the sentence that points at it. Where a post says "read it", "their post", "the announcement", the URL follows on that same line after a colon or a space, never on a line of its own with a blank line above it. A URL floating between two paragraphs is the shape of a post assembled out of blocks, and a reader scanning a feed sees a naked link rather than a reason to click. The exception is a platform whose composer wants the URL alone to build its preview card, and that comes from the Phase 3 research rather than from habit. Anywhere else, a blank line between prose and its own link is a defect — the closing sentence carries the URL inline: `Faster than real time is what turns a video model into a channel. Read more: <url>`.

And a URL never goes in parentheses. `Anthropic says it plainly in the docs (https://code.claude.com/…): two agents editing one file…` shoves the link into the middle of a clause, where it reads as a footnote marker and breaks the sentence in half. The sentence makes its point, then hands over the link at its end.

On a platform whose editor does not linkify text, the link is applied, not typed. A pasted URL in a rich editor publishes as dead characters — `medium`, `substack`, `tumblr` and `telegraph` all need the words selected and the editor's own link control used on them. The post file still carries the plain URL; making it a link is the composer step, and Phase 5 checks the published page rather than the file.

No trademark word carrying its ordinary meaning. A common noun that is also a large company's name stops reading as the noun the moment it lands in a feed: `slack` for spare capacity, `stripe`, `square`, `notion`, `discord`, `prime`, `oracle`, `meta`, `swift`, `zoom`, `teams`, `windows`. The reader sees the company, the sentence bends around it, and on a post about software the misread is instant. Write the ordinary synonym instead — head start, margin, band, idea, disagreement — and keep the word only where the post genuinely is about that company. This covers the body, the title, alt text, hashtags and any words on a graphic.

Distinctions that collapse under compression, and must not. Each pair below reads as a shorter version of the same claim and is a different claim: `can run` against `runs fast`; context capacity against reliable recall; a VRAM requirement against total system memory; official support against community compatibility; open-weight against free to use; model size against active parameters per token; local-first against fully offline; no cloud storage against no server involvement; an agent skill against a native model capability. Technical credibility outranks keeping a viral headline intact: where the headline needs one of these collapsed to work, the headline changes.

The shape a post about a tool takes, adapted to the platform's depth rather than forced whole into every one: the hook, what the thing is, why it matters, the concrete headline result, how it works, the caveat that matters most, who it is for, and the link or quick start. A short platform carries three of those, a long article carries all of them. The recurring framing that earns its place: the headline sounds like magic, the architecture is more interesting because it is not magic at all, then the actual mechanism.

Every post carries the caveat. Not a hedge and not a disclaimer, the one limit a reader would hit first: what it costs, what it does not do, where it breaks. A post with a result and no caveat is marketing copy, and it is the shape a reader has learned to discount.

Rules that hold across every platform:

- Numbers keep the conditions `source-notes.md` recorded. A benchmark without its machine, a percentage without its base, a claim without its scope is not a shorter version — it is a different claim.
- Quoted lines stay verbatim, inside quotation marks. A paraphrase presented as a quotation is a fabrication.
- The source's own terms and spellings survive; renaming its concepts to something punchier is how a repurposed post stops being about the source.
- Nothing from the "What the source does NOT say" section reaches a post.
- Threads only where the content is sequential, and each part must survive being read alone — the platform will show it alone.
- Tags with their own field in the composer never appear in the body. The article platforms (`devto`, `hashnode`, `hackernoon`, `medium`) and `tumblr` take tags in an input of their own, so the post file carries them as a `tags` frontmatter list and the prose ends on prose. A line of bare words under the last paragraph (`ai machine-learning video news`) is a tag dump that publishes as literal text, and it is the tell that a feed post's hashtag habit was applied to a platform that does not work that way. Inline `#hashtags` stay in the body only where the platform's own natives write them there.
- No invented idiom. A phrase that sounds like a saying but is not one — "proved it the blunt way", "a figure worth stopping on", "the honest version of that story" — is machine phrasing, because it reaches for the shape of a colloquialism without any colloquialism behind it. Write what happened in ordinary words: "someone at fal just tried it", "one number stuck with me". When a phrase cannot be found in speech, it does not belong in a feed post.
- Voice per the profile when there is one, including the habits its *Personal tics* section protects; those are exempt from the Phase 5 slop pass.
- The link is the one Phase 1 settled on, or none at all. An assistant's own domain never appears, and no post closes on a research transcript.

### The unit is cleaned before it fans out

Write the unit once, whole, as a single text. Then run the humanity pass on that one text, before any platform adaptation touches it. A tell copied into ten files gets fixed ten times and usually only in nine.

What runs is this checklist, inline, against the one text. It is the part of four external catalogs that applies to a feed post, written out here so the run does not load the catalogs themselves; `--deep-audit` loads them (`awesome-document-style` Pass 1 and Pass 3, `awesome-humanize-en`'s structure pass and vocabulary tiers, `awesome-slop-audit`'s marker catalog) on top of this list, for a piece the user wants read harder than usual.

- Chatbot residue: citation markers, `utm_source=` parameters on any surviving link, visible placeholders, zero-width characters, a chat-UI leftover such as a "Sources:" block.
- Filler: adverbs that add no fact (`truly`, `really`, `very`, `actually` outside a contrast), `it is important to note`, `it is worth mentioning`, `in conclusion`, `overall`, sentence-initial `Furthermore` / `Moreover`.
- Inflation: `not only X but also Y`, forced groups of three, a vague positive ending, an opener that stamps a summary on what follows, a closing line that restates the opening.
- Contrast frames as the default shape: `not X, but Y`, `it is less about X than Y`, `the real question is not X`. One per post at most, and never as the opener.
- The list rhythm: an emoji or a bold lead on every bullet, bullets that all start with the same word, a list where prose would carry it.
- Em dashes: zero, counted by search, in body, title, hashtags, alt text and graphics alike.
- Vocabulary: the literary word list in `references/authored-style.md` and the hype list beside it, searched as words rather than judged by feel. The test is spoken: would you say it out loud to a colleague.
- Restatement: a point made twice in different words, the second time usually opening with `In other words` or `Put simply`.
- Structure tells: an outline showing through as a heading per source section, a run of rhetorical questions, a stance announced (`I would argue`) rather than taken.

Then read it out loud. Uniform sentence length, every line engineered to land, no ordinary sentence anywhere: that text was scrubbed rather than written, and one plain observation goes back in.

Only the cleaned unit fans out. Adaptation may cut and reshape; it may not put back what this pass removed.

### Writing in a language other than the source

The other-language version is written in that language, not carried across from the version that already exists. Sentence order, connectors, idiom and sentence length all belong to the target language, and the English original stops being the skeleton showing through.

For Russian and English in either direction, `awesome-translate-ru-en` holds the rules, and the load-bearing ones here are semantic-over-literal, its connector map read in whichever direction this run needs, register matching, and its forbidden-phrase list. On top of that, the tells that give away a Russian post assembled out of English: English word order left intact, «это не X, это Y» negation frames, calqued connectors («более того», «важно отметить», «в современном мире»), passive constructions where Russian wants an active verb, participial chains nobody speaks in, and a formal «вы» register on a feed written on «ты». The test is reconstruction: if a native reader can rebuild the English sentence behind the Russian one, the sentence is rewritten rather than adjusted.

Identifiers, commands, flags, product names and error text stay in the original, untranslated. One rule of that skill does not carry over: where it says to preserve em dashes as em dashes, the zero-dash rule above wins, because these outputs are composer text rather than formatted prose.

## Phase 5 — Audit: one script, then four passes

The mechanical half runs first and it is a script, not a reading: `node scripts/gate.mjs repurpose/<slug>/posts` (add `--subset` when the user trimmed the platform list). It settles, in one pass and in seconds, everything that has a countable answer: filename shape and platform slug, frontmatter agreeing with the filename, title length and terminal period, attachments present on disk, ASCII punctuation, `#show` and internal labels, assistant domains, a URL in parentheses, calendar dates, the literary and hype word lists, the hard caps at their 98% margin, the depth bands, one-line paragraph runs and their share, the banned opener shapes, emoji-bullet rows, body hashtag counts against each platform's norm, duplicate platforms, the file count, and the share of posts opening on `I` across the run. Exit 0 or one `slug: check: detail` line per finding. A finding is fixed in the file, and the script is run again until it exits 0; no judgment pass starts while it does not, because a reader spending attention on a post that is over its cap is attention spent twice.

Then the four passes a script cannot run, one at a time across all posts, listing every finding before fixing any — detection mixed into rewriting collapses onto one dimension:

1. Fidelity — the post's point matches `source-notes.md`; every claim and number traces to it with its condition; quotations verbatim; nothing from the "does NOT say" section present; every version still carries the same point, the same provenance and the same numbers, and no adaptation quietly turned into a second claim. A post that fails here is rewritten, not patched.
2. Structure — the outline test, the question sequence, position tells and stance, run on the unit itself. Where `--deep-audit` is on, this is `awesome-humanize-en`'s structure pass in full; otherwise the structure items of the Phase 4 checklist.
3. Slop — vocabulary and syntax beyond what the word lists catch: the invented idiom, the contrast frame that survived, the paragraph engineered to land, with the voice profile's protected tics excluded. Under a declared voice the voice's *known costs* are reported, not fixed against the user's chosen aesthetic, while uniformity findings keep full strength: the same signature move on every platform's version is a finding even when the profile lists the move. An announcement-shaped unit also takes the release-notes tells — marketing inflation, benefit claims with no mechanism, the journey intro and the road-ahead outro. Where a voice rule and a slop rule directly conflict, name both in `campaign.md` and let the user pick.
4. Register and placement — the things that need a reader: the first-person frame present where the voice asked for it with no invented result inside it; at least one human signal per post (an emoji, a question, an aside, a fragment) unless the platform is one of the named flat ones; emoji placed the way a person places them, never one per line; every tool beyond the main subject carrying an identifying clause at first mention; every link belonging to the sentence that points at it; on article platforms the image in the body under the title; the title naming the subject and stating the point rather than teasing it; for a post in another language, the nativeness test from Phase 4 with technical tokens untranslated; and the link being the one Phase 1 settled on or none.

The gate, per post: any fidelity finding, any structural finding, or three or more findings total → rewrite from the source notes; one or two wording findings → fix in place; none → ship. A rewritten post re-enters at the script and then pass 1 only; passes 2 to 4 are re-run on it only if pass 1 changed its text again. Fixes skew replace and delete over insert; the only addition allowed is specificity already present in the source notes. Report, do not "fix", posts that read scrubbed — no contractions anywhere, every line engineered, no ordinary sentence left.

## Phase 6 — Files, always

`repurpose/<slug>/posts/`, one file per platform, in the format `awesome-content-publisher` reads, named exactly as it expects:

```
YYYY-mm-dd_HH-mm_<pub-timezone>_<title>_<platform>.md
```

The scheduled time is the publish time chosen in Phase 2 (now, or the time the user named). Frontmatter carries `platform`, `scheduled`, `timezone`, `title`, `voice`, `target` where the platform needs one, `attachments` with alt text, `links`, `hashtags`, `status: draft`. `links` holds the public source Phase 1 settled on, or nothing at all; the URL the source arrived on never lands there when it belongs to an assistant.

The `<title>` field is a lowercase kebab-case slug, cut from the post's title after that title is written — the publisher parses the name against `[a-z0-9][a-z0-9-]*` for this field, so a capital letter or an underscore fails the round trip before a word of content is read.

What the title has to say is `awesome-content-campaign`'s rule and is not restated here: name the subject and state the point, never an unanchored fragment, a topic label or a teaser. It is the same rule the unit's own headline follows, applied to the field a composer and a file listing will show without the post around it.

`voice` is written on every post file, always, and it names what was actually used rather than what was offered. A post read back months later has to answer which voice wrote it without the manifest beside it, and a batch written under a profile that has since been rewritten is unreadable evidence otherwise. The value is the Phase 2 answer resolved to its source:

- A profile from `awesome-content-voice` → `profile: <path>`, the path as it was read, so the file can be opened again.
- A style guide from `awesome-style-mimic` → `style-guide: <path>`, same rule.
- One of the built-in answers → `first-person`, `first-person-plural`, or `third-person-neutral`.

Where a post deviates from that voice on the platform's orders — a genre demanding what the profile's evidence does not carry, a tag field that overrides the profile's hashtag casing, a platform whose natives use no emoji — the deviation goes on the same file in a `voice_deviation` line saying what was overridden and what overrode it. A deviation recorded only in `campaign.md` is lost the moment a post file travels on its own.

Beside them, `campaign.md` — the name is the publisher's contract, not a claim that this was a campaign. It records the source and its provenance, the link the posts carry with how it was found (or that none exists and the posts carry none), the notes the posts were checked against, the one idea the unit carries, per-platform limits with their checked-on dates, what each platform's version had to cut or reshape, and any Profile prerequisite (a bio link a "link in bio" post depends on).

Files exist before anything is published. A run that fails at the third platform leaves seven finished posts on disk, and the publisher's ledger knows which two already went out.

## Phase 7 — Publish, or stop

Files only → the skill reports where they are and stops.

Publish now, or at a named time → call the Skill tool with "awesome-content-publisher" and hand it the folder:

```
/awesome-content-publisher repurpose/<slug>/posts --now
```

Everything about publishing belongs to that skill and is not reimplemented here: the browser-bridge preflight, the login check with wait-or-skip, the ledger that survives a restart and prevents duplicates, the confirmation gate, the human pacing, the read-back of every post, the incident handling. Drop the `--now` when the posts carry real future times; it will wait for them.

That skill not installed → say so, leave the files, and print the command to run once it is. Nothing about the output depends on it.

## Verification

The report states: the source and its provenance, the link the posts carry and how it was found (or that no public one exists, and that the posts therefore carry none), the one idea extracted from it, the N platform versions of that single post and what each had to cut, the `scripts/gate.mjs` exit code quoted with its final finding count (a report claiming a clean gate without having run it is the claim the script exists to replace), the platform-cache date the run relied on or the platforms it re-checked live, each of the four judgment passes with its findings and the gate row each post landed on, filenames parse-verified, the voice the posts were written in named by its resolved source rather than by the interview option that chose it, the folder path, and — when publishing ran — the publisher's own report rather than a restatement of it. Anything skipped (a platform dropped for want of media, a community whose rules forbid the post) is named, never implied.

## Anti-patterns

- Writing a different post for each platform. One unit, adapted — a reader who follows the author on three of them should meet the same post three times.
- Building the post out of an inventory: version numbers, feature roll-calls, lists of names. Factual, easy to extract, and worth nothing to a reader who wanted to know what changed for them.
- A post with no provenance, leaving the reader unable to tell what is being discussed or where it came from.
- Summarizing instead of selecting — the "5 key takeaways" post that reproduces the source's table of contents and gives the reader nothing whole.
- Publishing the URL the source arrived on when it points at an assistant's own site, or closing a post with "full research thread" and a chat share link.
- A calendar date in a post: the "checked on" stamp, the "as of <month>" qualifier, the dated opening line in either language.
- A version and OS matrix inside a feed post, where a person would have written "needs a recent version".
- The neutral-summary voice: a post that reports someone else's announcement instead of the author's own run at it.
- Fanning the unit out to ten platforms before the humanity pass has touched it, then hunting the same tell ten times.
- A Russian post with English sentence order and calqued connectors showing through, produced by translating the English one instead of writing it.
- An em dash anywhere in a post, including the title, the alt text and the graphic.
- A post with no emoji at all on a platform whose feed is full of them, and the opposite failure: emoji as bullet markers or one on every line.
- Inverting the source's point by cutting the qualifier that carried it.
- A number without the condition the source attached to it, or a paraphrase inside quotation marks.
- Adding the adjacent claim the source stopped short of — that is what the "What the source does NOT say" section is for.
- Rendering a graphic for the one platform that demanded it and shipping every other post text-only. The image was made for the idea, not for `instagram`; it belongs everywhere the platform accepts one.
- A post built out of one-line paragraphs: a stack of fragments where a paragraph belonged, or a sequence of steps formatted as four separate blocks. Each line reads fine on its own, which is why this survives every other pass.
- Opening on an abstract category doing something a category cannot do (`AI video crossed a line`, `AI code review is moving from X to Y`), on a vague event with a vague time (`Something important happened this week`), or on a tease that withholds the subject to build suspense.
- Opening every post in the run on `I think`. Variety across the seven working shapes is the rule; one friendly shape repeated across the whole set is the same uniformity tell as one corporate shape repeated across it.
- A `ko-fi` or `buymeacoffee` post written at feed length. Both are blog surfaces, and a 400-character post there reads as abandoned rather than concise.
- A `bastyon` post written as a long read. The Shares composer is the target and its band is what the feed is made of.
- Writing one long version and trimming it per platform at publication time, which always amputates the tail: the closing line, the number, the link.
- Publishing without files, or writing files the publisher cannot parse.
- Reimplementing any part of publishing, humanizing, or voice-building here instead of handing off.
- Repurposing into a feed the ledger shows already carries this source, without telling the user.
- Letting the whole source text into the conversation context instead of reading it from disk.
- Re-verifying 26 platforms' caps and formats on every run when the tables already hold them and the user was never asked whether they wanted the check.
- Opening the user's browser to populate a target question they can answer from memory, before they asked to see their options.
- Asking the full interview on a run whose answers are the same as last time's, when a one-screen "same as before?" would have done.
- Verifying every claim in the source before the idea is chosen, then shipping a post that uses three of them.
- Reading a post for a defect a script can count: an em dash, a cap, a run of one-line paragraphs, a banned opener.
- Loading three external audit skills for a routine run whose checklist fits on one screen.