agentleFS
ciberjohnciberjohn/Hermes-Skills/medium-story/SKILL.md

medium-story

Skill17 starsChanged 2 months agoMITView on GitHub

Full Medium article pipeline using native Hermes tools. Research → write → 4 parallel output agents → git commit/push. Markdown is the deliverable; HTML is opt-in. Includes pre-flight infrastructure verification, revisor-methodology fact-checking, an anti-AI-slop writing pass (banned vocabulary, structural variety, accuracy rules), a mandatory AI-generated illustration reusing the recurring series character, and a mandatory step linking your own repositories.

  • Reads credentials
  • Installs packages
  • Commits and pushes

The file

Show its rules and text

We split this skill into the rules it gives an agent

40 rules. About 0 are common, 30 are distinctive, and 10 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈30

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 10

    Very specific

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

  • Common
  • Distinctive
  • Very specific
  • could be automatic: a setting could enforce it
  1. Distinctive:

    Do NOT re-run research when the brief is already compiled — this wastes time and risks overwriting carefully curated source material with …

    line 80
  2. Distinctive:

    Run ALL of these before Step 1:

    line 88
  3. Distinctive:

    Read the cron job names, schedules, and last status.

    line 102
  4. Distinctive:

    If the existing doc says something different from what I remember, the doc is right and my memory is wrong.

    line 115
  5. Distinctive:

    If the repo doesn't exist locally, clone it:

    line 125
  6. Very specific:

    Before writing anything new, check if any unpublished_stories/ folders have gone live on Medium.

    line 132
  7. Very specific:

    Read {{MEDIUM_REPO_PATH}}/{{CACHE_PATH}} — extract all <title> values.

    line 135
  8. Distinctive:

    If the cache file is missing or stale (heartbeat older than 36 hours), fetch live:

    line 137
  9. Very specific:

    Read published_index.md — the running list of all known published stories.

    line 143
  10. Very specific:

    If that title appears in either the RSS feed titles OR published_index.md, the story has gone live

    line 149
  11. Very specific:

    Read the most recently published story's medium-story.md as a format reference.

    line 171
  12. Distinctive:

    When browser tools are unavailable (common on VPS/headless environments), use this curl-based parallel pattern for authoritative, …

    line 179
  13. Very specific:

    Security scanner workaround: Always save curl output to /tmp/ first, then process with a separate python3 -c reading from the file.

    line 228
  14. Distinctive:

    Claim verification: Never conflate vendor marketing claims with independent data.

    line 259
  15. Very specific:

    Write the article to unpublished_stories/{{STORY_NUMBER}}_{{STORY_SLUG}}/medium-story.md.

    line 270
  16. Distinctive:

    Dry, understated wit: Not forced humour. Surfaces naturally when the situation is absurd (vendor overclaiming, predictable failures).

    line 320
  17. Distinctive:

    Leads with impact, then explains mechanism: Never opens with theory and works towards relevance — does the opposite.

    line 322
  18. Distinctive:

    Read the dialogue aloud. If it sounds like a LinkedIn post from someone trying to sound authoritative, cut it.

    line 376
  19. Distinctive:

    When writing under the author's name, use this attribution format:

    line 380
  20. Distinctive:

    Do NOT use the full LinkedIn header (Strategic Technology Leader | Platform Engineering & Agentic AI Governance | Infrastructure, …

    line 384
  21. Very specific:

    Before saving any article, run this grep check against the draft.

    line 390
  22. Distinctive:

    Run these searches in parallel (they are independent reads):

    line 414
  23. Distinctive:

    No Rule of Three — groupings of exactly three items/paragraphs in a row.

    line 436
  24. Distinctive:

    No three consecutive sentences of the same length

    line 437
  25. Distinctive:

    No parataxis — three or more short declarative sentences in a row.

    line 438
  26. Distinctive:

    No hedging seesaw — positions stated plainly.

    line 439
  27. Distinctive:

    No passive construction — "is being done", "was found to be" → active

    line 440
  28. Distinctive:

    Not every paragraph ends with a transition — let some end abruptly

    line 442
  29. Distinctive:

    No fabricated data, studies, statistics, or quotes — hypotheticals flagged with "imagine" / "suppose"

    line 443
  30. Distinctive:

    If you publish these skills, tools or projects yourself, leading readers to them is part of the job.

    line 480
  31. Distinctive:

    A verified count: when you invite readers over ("one of 17 skills").

    line 489
  32. Very specific:

    Check every link resolves before publishing (curl -sS -o /dev/null -w "%{http_code}" -L <url>).

    line 495
  33. Distinctive:

    Read each agent's file from the story folder after the batch completes to confirm output was written.

    line 506
  34. Distinctive:

    Check for mid-sentence dashes (em dashes or en dashes used as parenthetical breaks)

    line 517
  35. Distinctive:

    No mid-sentence dashes in spoken text

    line 532
  36. Distinctive:

    Word count verification (mandatory): After writing, run this to confirm using the inline-colon format regex:

    line 535
  37. Distinctive:

    NOT an avatar/Heygen script — real person, real voice

    line 566
  38. Distinctive:

    Only run this when HTML output is explicitly requested.

    line 575
  39. Very specific:

    Feed cache staleness: If {{CACHE_PATH}} is older than 36 hours, fetch live.

    line 658
  40. Distinctive:

    Git authentication: If git push fails, the SSH key or credential helper may not be configured.

    line 661

≈ “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

Medium Story — Hermes-Native Article Pipeline

Research, write, and publish technical Medium articles using Hermes tools directly. No tmux, no Claude Code CLI, no external agent dependencies.

Prerequisites

  • Hermes Agent installed and configured
  • A Git repository for your Medium articles (can be private or public)
  • A Medium account with RSS feed enabled
  • (Optional) A GitHub personal access token ($GH_TOKEN) for API rate-limit bypass during research
  • Python 3 with standard library (for stats parsing). Only if you ask for HTML output do you also need markdown-it-py.
  • git installed and configured for push access to your repo

Configuration Variables

Set these in your environment before running the pipeline, or document them in a .env file at your repo root:

VariableDescriptionExample
{{MEDIUM_REPO_PATH}}Absolute path to your local Medium articles Git repository~/Medium-Articles
{{GITHUB_REPO_URL}}HTTPS clone URL of your Medium articles repohttps://github.com/your-username/Medium-Articles.git
{{MEDIUM_RSS_FEED_URL}}RSS feed URL for your Medium publicationhttps://your-username.medium.com/feed
{{STORY_NUMBER}}Auto-incremented sequential story number (set by pipeline)42
{{STORY_SLUG}}URL-friendly slug derived from the article titlewhy-your-mfa-does-not-help
{{PERSONA_FILE}}Path to your writing persona filetemplates/persona-template.md
{{CACHE_PATH}}Path to the medium feed cache XML{{MEDIUM_REPO_PATH}}/medium_feed_cache.xml
{{PUBLISHED_AUTHOR}}Byline name on published articlesYour Name
{{BYLINE_DESCRIPTION}}One-line role description for the bylineStrategic Technology Leader
{{FLEET_DOCS_PATH}}Path to your fleet/architecture docs for infrastructure verification~/docs/FLEET.md
{{WATCHER_DIR}}Directory holding the publication watcher and promotion executor (Step 10)~/medium-promo
{{GH_TOKEN}}(Optional) GitHub personal access token for API rate-limit bypassghp_xxxxxxxxxxxx

When to Use

  • User says "write a Medium article about..." or "publish a story on..."
  • User shares a news item and says "write about this"
  • User asks for a blog post, LinkedIn article, or YouTube script for a technical topic

Outputs Produced

FileFormatAgent
medium-story.mdMarkdown (2,500+ words)Writer agent
revisor-fact-check-report.mdMarkdownRevisor agent (parallel)
video-script.mdMarkdown (90s Heygen script)Heygen agent (parallel)
linkedin-post.mdMarkdown → HTMLLinkedIn agent (parallel)
youtube-script.mdMarkdown (8-12min screencast)YouTube agent (parallel)
(opt-in only) *.fragment.html, *.full.htmlHTMLmd_to_html.py, only when asked

The Markdown files are the deliverables; HTML is opt-in. Most people paste into Medium from medium-story.md. Generating HTML by default adds files nobody opens and a commit full of markup, so run md_to_html.py only when someone asks for HTML. Markdown renders reliably everywhere; rendered HTML often does not.

Repo & Conventions

  • Repo path: {{MEDIUM_REPO_PATH}}/
  • Published stories: published_stories/{{STORY_NUMBER}}_{{STORY_SLUG}}/
  • Unpublished stories: unpublished_stories/{{STORY_NUMBER}}_{{STORY_SLUG}}/
  • Root files: CLAUDE.md, {{PERSONA_FILE}}, published_index.md, md_to_html.py, {{CACHE_PATH}}
  • Story numbering: Sequential, auto-incremented from highest existing folder number across both published_stories/ and unpublished_stories/

Pipeline Steps

Step 0a: Pre-existing Research Brief Check

If the story folder already contains a research-brief.md, skip Step 4 entirely. Read the existing brief, the repo's CLAUDE.md, and {{PERSONA_FILE}} for voice guidance, then go directly to Step 5 (story directory) or Step 6 (writing). This is common when the research was prepared in a prior session.

Do NOT re-run research when the brief is already compiled — this wastes time and risks overwriting carefully curated source material with shallow web searches.

Step 0b: Pre-Flight Infrastructure Verification (CRITICAL — Do Not Skip)

Before writing about any component of the fleet (profiles, containers, services, infra), verify the live state first. I have a verified pattern of claiming infrastructure exists based on memory rather than checking actual state — this produces errors that cost the user multiple correction rounds.

Anonymisation rule (2026-08-13, user correction): for PUBLIC content (Medium articles, LinkedIn, YouTube, HeyGen), default to NOT exposing real infrastructure. Do not name hosts, hostnames, IPs, zones, services, ports, or functions unless the user is explicitly prescriptive about including them. Use generic descriptions: "a couple of VPSs and a handful of LXC containers across three network zones", "internet-facing hosts", "a known sleeper host". This applies to the article body AND all script outputs (video, YouTube, LinkedIn) AND SEO tags. The author was explicit: public content must not over-expose infrastructure unless they are very prescriptive about including it. This rule has been violated before and cost multiple correction rounds.

Run ALL of these before Step 1:

# 0a. What Docker containers are actually running?
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}"

Do NOT rely on memory of what was running in a previous session. Containers get replaced, renamed, or removed, and my memory does not update automatically. If I claimed "Portainer was replaced by Dockhand" but Portainer is still running, I was wrong. If I described "LXC containers on a residential machine" but everything is Docker on this VPS, I was wrong. Verify before writing.

# 0b. What cron jobs are active?
cronjob action=list

Read the cron job names, schedules, and last status. Do not guess about what runs or when.

# 0c. What Tailscale peers are online?
tailscale status 2>/dev/null
# 0d. Read the existing fleet and architecture docs for your environment
# These are the authoritative source for your roles and infrastructure design
cat {{FLEET_DOCS_PATH}}

If the existing doc says something different from what I remember, the doc is right and my memory is wrong. Update my understanding before writing.

When to escalate: If I cannot determine the real state of a claim (e.g. "what replaced Portainer?" — I don't know, user said Dockhand but Portainer is running), say "I need to check with the user" rather than guessing from partial memory. Do not fabricate certainty.

Step 1: Sync the repo

terminal(command="git -C {{MEDIUM_REPO_PATH}} pull --ff-only origin main", timeout=30)

If the repo doesn't exist locally, clone it:

terminal(command="git clone {{GITHUB_REPO_URL}} {{MEDIUM_REPO_PATH}}", timeout=60)

Step 2: Cross-reference — detect newly published stories

Before writing anything new, check if any unpublished_stories/ folders have gone live on Medium.

2a. Read the RSS feed cache: Read {{MEDIUM_REPO_PATH}}/{{CACHE_PATH}} — extract all <title> values. These are the 10 most recently published story titles.

If the cache file is missing or stale (heartbeat older than 36 hours), fetch live:

terminal(command="curl -s {{MEDIUM_RSS_FEED_URL}} 2>/dev/null | grep -oP '(?<=<title>)(.*?)(?=</title>)' | tail -n +2")

2b. Load the published index: Read published_index.md — the running list of all known published stories.

2c. Scan unpublished_stories/: For each folder in unpublished_stories/:

  • Find the main story file (try: medium-story.md, MEDIUM_STORY.md, *draft*.md, article-final.md, article.md, story.md)
  • Extract the H1 title
  • If that title appears in either the RSS feed titles OR published_index.md, the story has gone live
  • Move the folder: terminal(command="git -C {{MEDIUM_REPO_PATH}} mv unpublished_stories/FOLDER published_stories/FOLDER")
  • Append a row to published_index.md

2d. Commit any movements:

terminal(command="cd {{MEDIUM_REPO_PATH}} && git add published_index.md published_stories/ unpublished_stories/ && git commit -m 'chore: move newly published stories to published_stories/' && git push", timeout=30)

Skip if nothing moved.

Step 3: Read context files and find next story number

Read these files:

  • CLAUDE.md from repo root — project-level instructions
  • {{PERSONA_FILE}} from repo root — writer persona

Find the next story number:

terminal(command="ls {{MEDIUM_REPO_PATH}}/published_stories/ {{MEDIUM_REPO_PATH}}/unpublished_stories/ 2>/dev/null | grep -E '^[0-9]+_' | sed 's/_.*//' | sort -n | tail -1")

Next = that value + 1.

Read the most recently published story's medium-story.md as a format reference.

Step 4: Run research

Spawn a research subagent via delegate_task with the topic, repo path, and persona. Use the parallel multi-source research methodology below rather than a single generic search.

Research Methodology: Parallel Multi-Source Web Research

When browser tools are unavailable (common on VPS/headless environments), use this curl-based parallel pattern for authoritative, verifiable research.

Phase 1 — Ecosystem discovery via HN Algolia API

The HN Algolia API returns community-vetted sources (highest-point posts correlate with quality and credibility):

# Discovery: find stories on the topic
curl -sL "https://hn.algolia.com/api/v1/search?query=<topic+keywords>&tags=story&hitsPerPage=10" -o /tmp/hn-discovery.json

# Get details + comments on a specific discussion
curl -sL "https://hn.algolia.com/api/v1/items/<OBJECTID>" -o /tmp/hn-item.json

Fire 3-5 facet-shifted queries in parallel (broad topic, specific tool, adjacent trend, critical/contrarian angle). Parse with python3 reading from the saved file.

Phase 2 — Statistics via GitHub API

For every tool, framework, or project mentioned in research, pull live ecosystem metrics:

curl -sL "https://api.github.com/repos/OWNER/REPO" -o /tmp/gh-stats.json
python3 -c "import json; d=json.load(open('/tmp/gh-stats.json')); print(f'Stars: {d.get(\"stargazers_count\")}, Forks: {d.get(\"forks_count\")}')"

# Ecosystem breadth
curl -sL "https://api.github.com/search/repositories?q=<topic>&sort=stars&per_page=5" -o /tmp/gh-search.json
python3 -c "import json; d=json.load(open('/tmp/gh-search.json')); print(f'Total repos: {d[\"total_count\"]}'); [print(f'{i[\"full_name\"]}: {i[\"stargazers_count\"]}') for i in d['items'][:5]]"

Phase 3 — Deep content extraction (browser bypass)

For plain HTML pages (not SPAs), use curl + Python for structured extraction without a browser:

curl -sL "https://example.com/article" -o /tmp/article.html
python3 -c "
import re, html
with open('/tmp/article.html') as f: content = f.read()
text = re.sub(r'<script[^>]*>.*?</script>', '', content, flags=re.DOTALL)
text = re.sub(r'<style[^>]*>.*?</style>', '', text, flags=re.DOTALL)
text = re.sub(r'<[^>]+>', ' ', text)
text = html.unescape(text)
text = re.sub(r'\s+', ' ', text)
for line in text.split('. '):
    if any(kw in line.lower() for kw in ['agent', 'adopt', 'transition', 'ecosystem', 'workflow']):
        print(line[:300])
"

Security scanner workaround: Always save curl output to /tmp/ first, then process with a separate python3 -c reading from the file. Piped curl | python3 is blocked by the security scanner.

Phase 4 — Multi-source triangulation

Cross-reference every claim across at least 2 of these source types:

  • Primary source (GitHub README, official docs, company blog)
  • Community signal (HN discussion points, Show HN projects, GitHub stars)
  • Third-party analysis (TechCrunch, industry blogs, analyst reports)
  • Ecosystem proof (related repo counts, fork activity, ecosystem trends)

Phase 5 — Compile research brief

The research agent must produce a structured brief (not a stream of notes) with these sections:

  1. Background — Role hierarchy, capabilities, scope of impact
  2. Why This Matters Now — Market trends, architectural convergence, timing
  3. The Gap — Control deficiencies, comparison tables, historical blind spots
  4. Real Incidents & Attack Patterns — 7+ documented vectors with vector/mechanism/impact/evidence tables
  5. Vendor Guidance — Official docs, direct quotes, gaps in vendor's own guidance
  6. Industry Standards — Framework mapping (NIST, CIS, NCSC, MITRE)
  7. Remediations — 10+ actionable controls with rationale, licensing, config notes
  8. Source List — 8-12 authoritative URLs with descriptions

Save to the story folder as research-brief.md. This becomes the reference input for the writer agent in Step 6.

Common pitfalls in research

  • GitHub API rate limiting: Unauthenticated requests capped at 60/hr. Authenticate with curl -H "Authorization: Bearer $GH_TOKEN" when doing more than a few calls.
  • Medium blocks VPS IPs: Live feed fetches may 403. Use cached RSS feed or alternative sources.
  • HN Algolia empty results: Simplify the query. The API is brittle with long multi-word AND queries.
  • Browser-required pages: SPAs and paywalled pages will not work with curl. Note these as gaps rather than fabricating content.
  • Claim verification: Never conflate vendor marketing claims with independent data. Always attribute: "the vendor says X" vs "data confirms X."
  • Research brief format: See templates/research-brief-template.md for the canonical output format. See references/session-63-claude-code-commands-research.md for a worked example.

Step 5: Create story directory

terminal(command="mkdir -p {{MEDIUM_REPO_PATH}}/unpublished_stories/{{STORY_NUMBER}}_{{STORY_SLUG}}/")

Step 6: Write the article

Write the article to unpublished_stories/{{STORY_NUMBER}}_{{STORY_SLUG}}/medium-story.md. The writer MUST write within the anti-slop constraints in Step 6b and references/anti-ai-slop-writing.md — load the reference before writing and apply it silently. Two approaches:

Approach A — Direct writing (use when you have full context): If you already hold all the research context, voice guidance, and style instructions in your active context (e.g. you just read the research brief in this session), write the article directly using write_file. This is faster and avoids context fragmentation. Run the pre-publish checklist against the saved file before finishing.

Approach B — Subagent via delegate_task (use when context is saturated or research is complex): Spawn a writer subagent with full context including the research output, CLAUDE.md, and {{PERSONA_FILE}}. The subagent writes the article, runs the checklist, and saves the result.

Mandatory Post-Write Em Dash Verification ⚠️

The writer subagent reliably produces em dashes despite explicit prohibition. This is a known pattern — neither direct instruction nor the self-administered pre-publish checklist reliably catches them. After the writer returns (BOTH approaches A and B), you MUST independently verify before proceeding to Step 7:

# Count all em dashes (U+2014) in the article
grep -c '—' /path/to/medium-story.md

# List them with line numbers to identify body vs sources section
grep -n '—' /path/to/medium-story.md

# Exclude the Sources section (lines 130+) to confirm body is clean
grep -n '—' /path/to/medium-story.md | grep -v '^1[3-9][0-9]:'

Expected result: 0 em dashes in the article body. The sources section (lines ~130+) uses — as a standard metadata separator between URLs and descriptions — those are acceptable and should NOT be replaced. FILE placeholders ([*FILES*: filename — description]) also use — and are acceptable.

If any body em dashes remain, fix them before dispatching output agents:

Apply these replacement patterns to fix common writer-generated em dashes:

Em dash pattern (before)Replace with (after)
Word — explanatory text —Word (explanatory text) — use parentheses for paired asides
important thing — here's whyimportant thing: here's why — use colon for explanatory clauses
X, Y and Z — verb phraseX, Y and Z verb phrase — remove, the listing flows without punctuation
statement one — statement twostatement one. Statement two — split into two sentences
word — phrase (single, emphasis)word, phrase — use comma
word — phrase (single, dramatic pause)word: phrase — use colon

Most fixes are: paired dashes → parentheses, single explanatory dashes → colon, emphasis dashes → comma, and breaks between independent clauses → full stop + new sentence.

Do not fix em dashes in:

  • The ## Sources section (metadata separators)
  • [*FILES*: ...] placeholders (diagram descriptions)

Writer Voice & Style Guide (from published Medium articles)

This section is derived from analysing your published stories — the voice patterns, sentence structures, and rhythms he actually uses, not a theoretical style guide.

Core Voice

  • Practitioner, not pundit. The voice speaks from experience managing real infrastructure at scale. He has the war stories and references them.
  • British English always. -ise not -ize, colour, favour, behaviour, defence, whilst, amongst, licence, harbour, neighbour, realise, analyse, organise, recognised.
  • Dry, understated wit. Not forced humour. Surfaces naturally when the situation is absurd (vendor overclaiming, predictable failures). Examples: "The catch, in this case, is that there is not one" / "I collect them the way people collect gym memberships: with great optimism and almost zero follow-through."
  • Professional skepticism. Questions vendor claims. Distinguishes between "I assume" and "I have verified." Calls out lazy thinking directly but without aggression.
  • Leads with impact, then explains mechanism. Never opens with theory and works towards relevance — does the opposite. The human/operational consequence comes first, the technical explanation second.

Sentence Construction

  • Complex, multi-clause sentences. The voice writes long, grammatically precise sentences — 25-50 words is normal. Clauses separated by commas, colons, and parenthetical qualifiers.
  • Parenthetical asides extensively used — "(a real risk with any relatively young cryptographic scheme)" / "(not months, two weeks)" — they add precision and personality.
  • Very few one-sentence paragraphs. Reserved for emphasis. A one-sentence paragraph is a statement meant to land hard.
  • Paragraphs are substantial — 4-8 sentences, 80-150 words. Dense with information. Not skimmable; designed to be read.
  • Colons used extensively for explanation: "The word 'bearer' is doing enormous work here. Whoever holds the token has the access. Full stop." / "The idea behind a hybrid approach is elegant in its conservatism: you get the security of the new... and the security of the old..."

Structure Patterns

  • Hook is a strong, often single paragraph that reframes the topic or states the surprising truth. Can be 3-7 sentences long with a pay-off at the end.
  • Roadmap paragraph follows the hook — tells the reader what the article will cover, often as a single long sentence: "This article covers the full picture: how BITB works technically, who has built it into production phishing campaigns, what the statistics say..."
  • --- horizontal rules separate major sections. They create natural pause points for readers.
  • Section headers are provocative or unexpected, not generic category labels. "Why Your MFA Does Not Help" vs "MFA Analysis." "The Bug I Actually Care About Most" vs "Critical Bug." "The Release Nobody Will Read Properly" vs "Overview."
  • Subheadlines/bold leads under section headers set the scene before diving in.
  • Ends with "What to Do" or "The Takeaway" — concrete, actionable, prioritised. Not a summary. New content that synthesises and directs.
  • "Sources" section at the very end with live hyperlinks. Not a reference list — a short list of the key documents cited, each with a brief description.

Distinctive Phrasing Patterns

These patterns appear across articles — they are fingerprints of the voice:

PatternExample
"This is not [X]. It is [Y].""This is not a clever exploit of a Microsoft bug."
"Not because... but because...""Not because the finding is complex... but because it is so straightforward..."
"Let us be precise about this, because the nuance matters operationally"Direct quote — used when a distinction matters
"Read that again."Breaks the fourth wall to emphasise — use sparingly, once per article max
"The [adjective] [noun] that should [verb]""The release that quietly closes a directory traversal issue..."
"I have seen [X] than I would like to admit"Self-aware honesty about industry patterns
"This is the kind of [thing] that [consequence]""This is the kind of bug that erodes the thing infrastructure teams depend on most"
"I want to be unambiguous about that, because..."Used when the voice wants to prevent misinterpretation
"Someone out there, right now, [is doing X]"Places the reader in the real-world scenario
"That is not a [position]. That is someone who has [experience]."Elevates or reframes a judgement

What This Voice NEVER Writes

These patterns have been explicitly rejected and must NEVER appear:

  • ❌ Mid-sentence dashes (em dashes or en dashes as parenthetical breaks) — use commas or parentheses
  • ❌ Corporate jargon: "data estate", "uninsured liability", "measured in inconvenience"
  • ❌ AI transition phrases: "Here's what matters", "What this means is", "Here's the thing", "I need you to understand something"
  • ❌ Fluffy openers: "In today's digital landscape", "In an era of rapid technological change"
  • ❌ Credentials-first openings: "With over 20 years of experience in infrastructure..."
  • ❌ Ad-copy hooks: "Not hypothetically. In the next 60 seconds." / Emoji-lead headlines
  • ❌ Paired oppositions: "measured in inconvenience" / "measured in survival" (language-model parallelism)
  • ❌ "It is important to note that" — just note it
  • ❌ "Furthermore", "Moreover", "Additionally" — use "And" or just continue the sentence
  • ❌ American spellings — ever

The Test

Read the dialogue aloud. If it sounds like a LinkedIn post from someone trying to sound authoritative, cut it. If it sounds like someone who just came off a conference call with a vendor who overpromised and underdelivered — that is the voice.

Attribution / Byline Format

When writing under the author's name, use this attribution format:

{{PUBLISHED_AUTHOR}} — {{BYLINE_DESCRIPTION}}

Do NOT use the full LinkedIn header (Strategic Technology Leader | Platform Engineering & Agentic AI Governance | Infrastructure, Cybersecurity & Cloud...). The user prefers a focused byline that emphasises strategic technology leadership and the AI angle, not the full credential list.

The article title should never include "Medium" (avoid "Medium story", "on Medium"). Use "article", "story", or just the hook.

Pre-Publish Checklist

Before saving any article, run this grep check against the draft. In Hermes-native mode, use the search_files tool with path=<article-path>:

Patternsearch_files command (Hermes-native)Fix
"delve", "tapestry", "realm", "leverage"search_files(pattern="delve|tapestry|realm|leverage")Replace with plain English
"in order to"search_files(pattern="in order to")Replace with "to"
"it is worth [verb]ing"search_files(pattern="it is worth")Replace with "Let me [verb]"
"it is important to note that"search_files(pattern="important to note")Delete — just say the thing
"Furthermore," / "Moreover,"`search_files(pattern="Furthermore,Moreover,")`Replace with "And" or nothing
"In conclusion" / "To summarize"`search_files(pattern="In conclusionTo summarize")`Delete — just end
"Not only... but also"search_files(pattern="not only.*but also")Simplify
"By [verb]ing..." (sentence opener)search_files(pattern="^By [A-Za-z]+ing")Rephrase
"One of the most [adjective]"search_files(pattern="One of the most")Be specific or delete
"In today's [X]" / "In an era of"`search_files(pattern="today's digitalIn an era of")`Delete entirely
Mid-sentence dashes (em — or en –)`search_files(pattern="—–")`Replace with commas or parentheses
American -ize/-ization spellingssearch_files(pattern="ization")Replace with -isation/-isation (British). Note: proper nouns such as "Modernization" (Microsoft's Rapid Modernization Plan) are acceptable and should NOT be changed.
Direct quotes from US sources (NIST, CIS, vendor docs)manual review of "quoted text" containing British -our/-ise/-isation spellingsPreserve ORIGINAL spelling inside quotation marks. US government docs use "authorized", not "authorised". British English rules apply to your own prose, NOT to direct quotes. Flag any changed quote as FAIL in the revisor report.
Infrastructure claimsVerify against live state (docker ps, crontab -l, etc.) — never guess
Diagram linksUse [*FILENAME.png*] placeholders, not excalidraw #json= URLs. Verify all [FILES] placeholders are present: search_files(pattern="\\[\\\\*FILES")
[FILES] placeholder countsearch_files(pattern="FILES") — verify count matches expected number of diagrams
PII / real paths in article bodyCheck for any system paths, hostnames, or personal URLs in final text

Executing the checklist (Hermes-native)

Run these searches in parallel (they are independent reads):

# Batch 1 — Forbidden vocabulary and AI-isms
search_files(pattern="delve|tapestry|realm|leverage|in order to|it is worth noting|furthermore|moreover|not only but also|in conclusion|in today's|in an era of")
# Batch 2 — Dashes and American spellings
search_files(pattern="—|–")
search_files(pattern="\\bize\\b|\\borganization\\b|\\bcolor\\b|\\bfavor\\b|\\bbehavior\\b|\\bdefense\\b|\\bcenter\\b|\\blicense\\b")
search_files(pattern="ization")  # review results manually for proper nouns
# Batch 3 — [*FILES*] placeholder presence
search_files(pattern="FILES")
# Batch 4 — Forbidden transition phrases
search_files(pattern="here's what matters|here's the thing|what this means is|I need you to understand|In today's digital|In an era of|data estate|uninsured liability|measured in inconvenience")

False-positive note: The words "delve", "tapestry", "realm", "furthermore", "not only but also", and "in order to" may legitimately appear in a meta-reference — for example, when the article describes this checklist itself ("A pre-publish checklist blocks ten categories of AI-typical language: 'delve', 'tapestry', 'realm'..."). In that case, the words are being quoted, not used. The revisor should flag them in the report but note the meta-reference context. Do not rewrite the meta-reference line. Similarly, "Modernization" in "Microsoft's Rapid Modernization Plan" is a proper noun and should not be flagged.

Step 6b: Anti-Slop Writing Pass (Mandatory)

Before dispatching the output agents, verify the article against the anti-AI-slop constraint set in references/anti-ai-slop-writing.md (adapted from jalaalrd/anti-ai-slop-writing, MIT — Carnegie Mellon 2025, Wikipedia Signs of AI Writing, Buffer 52M post analysis). This is a quality gate on top of the Pre-Publish Checklist: the checklist targets the voice's specific failures, Step 6b is the broader statistical detection net.

Manual structural checks (cannot be grepped — review the draft for these):

  • No Rule of Three — groupings of exactly three items/paragraphs in a row; break to two, four, or one
  • No three consecutive sentences of the same length
  • No parataxis — three or more short declarative sentences in a row; connect with subordinate clauses, conjunctions, semicolons
  • No hedging seesaw — positions stated plainly; counterpoints get one sentence max
  • No passive construction — "is being done", "was found to be" → active
  • No "As [role], I..." openers
  • Not every paragraph ends with a transition — let some end abruptly
  • No fabricated data, studies, statistics, or quotes — hypotheticals flagged with "imagine" / "suppose"
  • Punctuation limits: max one exclamation per 1,000 words, max one ellipsis per piece, semicolons used naturally

Grep checks (run in parallel with the em dash verification):

search_files(pattern="delve|tapestry|testament|vibrant|pivotal|crucial|intricate|meticulous|bolster|garner|underscore|interplay|multifaceted|nuanced|foster|leverage|utilize|commence|facilitate|encompass|paramount|groundbreaking|cutting-edge|game-changing|transformative|revolutionis|seamless|robust|comprehensive|endeavour|aforementioned|harnessing|spearheading|navigating|showcasing|highlighting|emphasizing|enhancing|unprecedented|remarkable|stunning|profound|synergy|pain points|value add|moving forward|touch base|circle back|rest assured|it goes without saying|at its core|in the realm|when it comes to|a testament to|not just.*but|at the end of the day|bottom line|here's the thing|here's the deal|without further ado|in a nutshell|buckle up|next level|unlock the power|empower|elevate|streamline|supercharge|bridge the gap|move the needle|firstly|secondly|thirdly")

Context rules: "robust" is banned outside engineering contexts; "empower/elevate/streamline" may legitimately appear in a direct vendor quote — flag but preserve quoted spelling per the revisor methodology. British forms of banned words (revolutionise, endeavour) count as violations too.

Fix policy: any hit that is a genuine violation gets fixed in the draft before Step 7. Hits inside direct quotes, the Sources section, or [FILES] placeholders are exempt.

Propagation to output agents: the other pipeline outputs (Heygen script, LinkedIn post, YouTube script) are written under the same constraints. Include references/anti-ai-slop-writing.md in the delegate_task context for Agents B, C, and D in Step 7.

Step 6c: Story illustrations — image model + recurring character (MANDATORY for every story)

Every story gets an illustration, including stories whose other images are real screenshots. It is the series marker rather than decoration: the recurring character is what makes the body of work read as one thing, and its absence gets noticed even when the article is otherwise complete. A story with six linked screenshots and no illustration still counts as unfinished.

  • Load an image-generation skill (e.g. openrouter-image-gen: cheap image models over a chat-completions endpoint, no GPU; the image comes back embedded in the JSON — walk the whole response recursively for data:image strings). Generate the hero illustration after the article is final, before packaging.
  • The recurring character (series rule): define ONE cartoon character and reuse it in every story illustration so the series reads as a single body of work. Example spec you can customise:
    • A cartoon person of your choosing (example used by the author: stout/bald man, short goatee, round glasses, warm smile, plain black T-shirt)
    • Their workspace: cluttered desk, monitors with data visuals, shelves with books and electronics, warm lamp, string lights, night window
    • A recurring motif: sci-fi paraphernalia (model starship, poster) — describe generically, never ask for trademarked logos
    • Palette: cool blues/teals/purples with warm amber accents; wide 16:9; editorial cartoon style; "no real logos, no brand names, no watermark"
  • A narrative illustration is a translation, not a diagram. Decide what in this article the picture should show (the one measurement, the one judgement, the one prop that carries the argument) and ask the model for that. An illustration that could have been made before reading the article is decoration.
  • The Illustration Engineer: treat illustration as a dedicated role. Either spawn a subagent ("Illustration Engineer") with the character spec, the image-generation skill and the article's topic as context, or run the generator directly. The engineer owns: prompt (topic-to-image translation), generation, verification, saving illustration.png into the story folder, and returning the [*FILES*: illustration.png — description] line.
  • A style reference transfers props as well as the character. Attaching a previous illustration to keep the character consistent also reproduces that image's room, furniture and gadgets, and an explicit "do not draw X" clause in the prompt does not override the reference. Decide deliberately: either accept the shared props as continuity for the same space and say so, or generate from the character description alone and accept some character drift. Never tell anyone a prop was avoided because the prompt excluded it.
  • Verification (always): check the generated image with a vision-capable model — the generator can lie about what it drew. Confirm the character is present, the requested props are present, and any text you asked for is legible and correctly spelled. Grade the text you asked for (a T-shirt slogan, a sign) and ignore incidental pseudo-text the model invents on screens and book spines, which every one of these models produces and which is invisible at article size. Regenerate if a real check fails.
  • The AI-generated caption is mandatory on Medium. Medium's content policy allows AI-generated images only when they are labelled, so the article must carry a sentence saying the illustration was created with an AI image creation program. Also note that AI cover art is a distribution negative: prefer a real screenshot as the cover image when one exists, and caption it.
  • Animated assets (optional): for diagrams and force graphs, render animated GIFs programmatically from the actual data or physics (e.g. Pillow), not an image model. Keep them abstract — no real note content, nothing sensitive.

Step 6d: Link your own repositories (mandatory)

If you publish these skills, tools or projects yourself, leading readers to them is part of the job. A story that cites only third-party sources has done half of it. Every story carries, at minimum:

  • A link in the body where your work is contextually relevant. A repo line in the Sources list alone is the weakest possible surface.
  • A closing practical pointer naming the specific folder or artefact the story is about, with its licence and what is inside it.
  • A Sources entry for the artefact itself, separate from any generic profile or repo link.
  • A verified count when you invite readers over ("one of 17 skills"). Count them; never estimate.

Propagate the same treatment into the Step 7 briefs: the LinkedIn post carries a link line, the YouTube description a paragraph plus links near the top, and the video script puts the URL in the caption and on the end card. None of the output agents does this unasked.

Check every link resolves before publishing (curl -sS -o /dev/null -w "%{http_code}" -L <url>); a 403 from a login-gated console is expected, a 404 is a broken citation. And expect the estate-identifier audit to flag your own account name inside your own public URLs: that rule guards hostnames, IPs, ports and paths, not the repository you are trying to promote. Record the exception in provenance.md so a later pass does not delete exactly the links that matter.

Step 7: Run four parallel output agents

Spawn agents via delegate_task in two batches because of the max_concurrent_children=3 limit (configurable in config.yaml under delegation.max_concurrent_children, but default is 3).

Batch 1 (3 agents — use delegate_task with tasks: [...]):

  • Read each agent's file from the story folder after the batch completes to confirm output was written.

Batch 2 (1 agent — separate delegate_task call):

  • The YouTube agent. Dispatch this immediately after Batch 1 — it does not need to wait for Batch 1's agents to finish; the two batches run concurrently. The total parallel count is 3 + 1 = 4, but they are submitted as separate calls so the system never sees more than 3 at once.

Important: Each agent must be told to write its output to the story folder using absolute paths. Do not rely on relative paths in subagent contexts.

Agent A — Revisor (revisor-fact-check-report.md)

  • Improve the story: fix British English, remove dashes, sharpen headings
  • Fact-check every statistic and claim
  • Flag any unverifiable or misleading statements
  • Check for mid-sentence dashes (em dashes or en dashes used as parenthetical breaks)
  • Report findings as actionable items — do not rewrite the article
  • See references/revisor-methodology.md for the structured fact-checking methodology: GitHub API verification patterns, grep commands for British English and Americanism detection, dash audit commands, source URL validation, and report formatting.

Agent B — Heygen Script (video-script.md)

  • 90-second teleprompter script for the author's HeyGen digital twin
  • Timestamped blocks: [HOOK] 00:00–00:05, [SETUP] 00:05–00:20, [INSIGHT 1] 00:20–00:40, [INSIGHT 2] 00:40–01:00, [PAYOFF] 01:00–01:20, [CTA] 01:20–01:30
  • Each block uses inline colons (NOT markdown tables) with four fields: Spoken: <text> — spoken word content On-screen text: <text> — max 6 words, reinforce don't duplicate Stage direction: <text> — brief physical/performance cue B-roll / graphic: <text> — practical visual suggestion
  • Match the format from the short-videos skill exactly — the old table-format (| **Spoken** | ... |) is deprecated. See short_videos/ folders for worked examples.
  • Target spoken word count: 200-230 words total
  • British English throughout
  • No mid-sentence dashes in spoken text
  • CTA must be platform-neutral (no "swipe up", no "link in bio", no "link in description" — use "full article linked below" or "follow for more")
  • Include a CAPTION (universal) section (3-5 lines, 5 hashtags, no "link in bio") and a THUMBNAIL CONCEPT line after the CTA block
  • Word count verification (mandatory): After writing, run this to confirm using the inline-colon format regex:
python3 -c "
import sys, re
text = open(sys.argv[1]).read()
blocks = re.findall(r'^Spoken:\s*(.*?)$', text, re.MULTILINE)
total = sum(len(b.split()) for b in blocks)
print(f'Spoken word count: {total}')
for i, b in enumerate(blocks):
    print(f'  Block {i+1}: {len(b.split())} words')
if total < 200: print('TOO LOW — expand spoken sections')
elif total > 230: print('TOO HIGH — trim spoken sections')
else: print('Within target range.')
"

Agent C — LinkedIn Post (linkedin-post.md)

  • Standalone post — NOT marketing for the article. It stands alone.
  • Hook line in first sentence
  • 3-6 short paragraphs, each punchy and self-contained
  • 3,000 character hard limit (LinkedIn cap)
  • Exactly 5 hashtags at the end
  • No "link in comments" — the Medium article URL goes IN the post body
  • No "watch my video" language
  • British English, no mid-sentence dashes
  • No "I've been in infrastructure for X years" openings
  • End with a question or provocation that invites comments

Agent D — YouTube Script (youtube-script.md)

  • 8-12 minute screencast script for recording with OBS (screen capture + webcam)
  • NOT an avatar/Heygen script — real person, real voice
  • Format: conversational talking points the speaker can follow naturally
  • Include: suggested screen content at each point, chapter markers, thumbnail concept
  • YouTube SEO: title + description + tags
  • British English

Step 8: HTML conversion (OPT-IN — skip unless asked)

Default action: do not run this step. The Markdown files are what get pasted and published. Only run this when HTML output is explicitly requested.

# only on request
terminal(command="cd {{MEDIUM_REPO_PATH}} && python3 md_to_html.py {{STORY_NUMBER}} --select medium-story,linkedin-post", timeout=30)

Check the interpreter if the script reports a missing dependency. md_to_html.py needs markdown-it-py, and on a machine with more than one Python it is easy to invoke a build that does not have it, producing a "markdown-it-py not installed" error that reads like a missing package when it is really the wrong interpreter. Confirm with python3 -c "import markdown_it", and try the system interpreter (often /usr/bin/python3) before installing anything.

Produces, when run (in the story folder):

  • medium-story.fragment.html — bare HTML
  • medium-story.full.html — styled standalone page
  • linkedin-post.fragment.html — bare HTML
  • linkedin-post.full.html — styled standalone page

Step 9: Commit and push

terminal(command="cd {{MEDIUM_REPO_PATH}} && git add unpublished_stories/{{STORY_NUMBER}}_{{STORY_SLUG}}/ && git commit -m 'Add story {{STORY_NUMBER}}: [topic summary]' && git push", timeout=30)

Step 10: The publication trigger (promotion runs on publish, automatically)

Step 2 only cross-references the feed when the pipeline is run, so a story published between runs is invisible: not moved, not indexed, and never promoted. In practice this means a published story can sit unrecorded indefinitely and nobody notices, because the record you would check to notice is the one that is stale.

Arm a detector so publication triggers the rest by itself:

{{WATCHER_DIR}}/
├── medium_watch.py     # monitor-mode cron script: feed -> "NO_NEW_STORIES" or NEW_STORY lines
├── medium_promo.py     # scan / adopt / ack — moves the folder, indexes it, records results
└── state.json          # mode 600: which publications have been accounted for

Wire it as a Hermes cron job in monitor mode (a bare script filename, resolved against the running profile's scripts/ directory), scheduled every few hours. Monitor semantics do the budget work for you: identical output suppresses the agent entirely, so idle ticks are free.

The flow the cron agent runs on a change: scan to list feed items the repo has not accounted for, adopt to git mv the folder into published_stories/ and append the published_index.md row, then post the story's own linkedin-post.md (adapted per platform) through the social poster, verify a real share id, and only then ack it. Unacked stories stay due and retry.

Semantics worth preserving if you rebuild this:

  • seen means already accounted for in published_stories/. Anything in the live feed that is not in seen is an unhandled publication. Do not read seen as "already promoted".
  • Seeding must not blanket-seed the feed. Seed only the items that already match a folder in published_stories/; a blanket seed buries exactly the backlog the seed exists to skip. Left unseeded, a published-but-unfiled story surfaces on the very next tick.
  • Auto-adoption should refuse a weak match. Stories get retitled inside the Medium editor, so the published title drifts from the folder's H1 and a fuzzy title match can be weak. Below a confident threshold (0.6 works well), report it for a human instead of moving a guess.
  • The watcher must never mark anything handled. Only the ack step does, and only after a platform returned a real share id, so a failed post is retried rather than lost.
  • The watcher must exclude both the accounted-for set and the handled set. Checking only the first means a story that has been moved, promoted and acked still reports as new on every tick, forever.
  • Probe platform health before posting, and only post to platforms the probe reports OK. Tokens expire silently, and posting into a dead token wastes the run while looking like success in a summary. Report the failing platform and its fix instead.
  • A monitor-gated scheduler job cannot deliver to a platform whose credentials live in another profile. If the scheduler's own profile holds no bot token for the delivery platform (common when one multiplexed gateway owns the tokens, and shared tokens are refused), the job fails its pre-run configuration check and reports blocked_config every tick while the underlying watcher is healthy. Deliver to a Bot Chat on a profile that does hold credentials, or to local, and confirm the target is a channel rather than a user id.
  • A remembered platform-status list inside a job prompt will suppress a platform that has since been fixed. State in the prompt that the job must trust the live probe from the fire it is running in, and label any remembered status as historical. Tokens are renewed between runs, so a list written yesterday is usually wrong today.
  • A change-gated job costs nothing on an unchanged tick, so a manual fire is not an end-to-end delivery test. Firing it by hand while nothing has changed returns a suppressed run: it proves the pre-run checks pass, not that delivery works.
  • A story published from outside the pipeline has no folder and cannot be auto-adopted. That is a legitimate case rather than a broken match: add a published_index.md row with a placeholder in the folder column, write the promo copy from the published article itself, and ack it.
  • Check whether the post helper treats an unexpected response as failure. One webhook poster expected an empty body and reported a failure whenever the platform returned the created object instead, so a successful post read as broken; verify by reading the destination back.

Pitfalls

  • A publication detector must exist, or published stories go missing silently. Step 2 only cross-references the feed when the pipeline is run, so a story published between runs is invisible to it: not moved, not indexed, never promoted. This is not hypothetical — it happens the first time a story goes out and the pipeline is not run for a few days. Read the feed's own pubDate values when checking cadence rather than trusting published_index.md, which is precisely the file that goes stale.
  • A cron monitor script cannot be a symlink out of the scripts directory. The runner rejects it with "Script path escapes the scripts directory via traversal". Put a real (small) wrapper file in the scripts directory that runs the implementation, and confirm the wrapper's output is byte-identical to the real script's before arming the job.
  • A monitor's output must be byte-stable while healthy, or every tick looks changed and the agent fires constantly. Emit a constant when nothing is new, and include a dated line only for states that should keep re-alerting.
  • Feed cache staleness: If {{CACHE_PATH}} is older than 36 hours, fetch live. If live fetch fails (403 from Medium's datacenter block), fall back to matching against published_index.md titles only, and flag the staleness.
  • Story number collision: The pipeline auto-increments from folder listings. If you manually create folders, use the next available number.
  • HTML conversion is opt-in. Do not run Step 8 unless asked: the Markdown is what gets pasted, and rendered HTML often does not survive a paste into a CMS or a repository's web view intact. When you do run it, verify md_to_html.py exists in the repo root and use an interpreter that has markdown-it-py installed.
  • Git authentication: If git push fails, the SSH key or credential helper may not be configured. Report the error — don't lose the article.
  • Mid-sentence dashes forbidden: The writer subagent produces em dashes despite explicit prohibition — this is a known pattern. The self-administered pre-publish checklist does NOT reliably catch them. You MUST independently grep the article body for em dashes after the writer returns (see Step 6 — Mandatory Post-Write Em Dash Verification) and fix them before dispatching output agents. Do NOT skip this step; the revisor will flag them but fixing them post-revisor wastes a round-trip.
  • Infrastructure claims require live verification: Before describing any service, container, or tool in the article, verify against live state. Run docker ps to check what's actually running. Check the last backup date. An incorrect infrastructure claim in the article will be spotted by technical readers and erodes trust. When in doubt, say "let me check" rather than guessing from memory.
  • Research agent context window: For very broad topics, the research agent may produce more text than fits in context. Keep the research brief to essential findings. Pass the full research as a file read reference rather than inline text.
  • LinkedIn character count: The 3,000 char limit is hard. The revisor checks it, but verify manually.
  • Parallel agent limit (4 tasks): delegate_task has max_concurrent_children=3 by default. You cannot dispatch all 4 agents in one call. Split into Batch A (3 agents: Revisor, Heygen, LinkedIn) and Batch B (1 agent: YouTube). Both batches run concurrently — the system sees 3 + 1 across two calls, never 4 at once.
  • Diagram PNG export for articles: If the article references Excalidraw diagrams, the #json= URLs from excalidraw.com do not render inline in Medium. After generating the .excalidraw file, render it to a transparent-background PNG and place in the story folder. Use [*FILENAME.png*] as a placeholder that the user replaces with the uploaded image when publishing. The rendering approach when browser tools are unavailable: use scripts/render_excalidraw_to_png.py (pip install Pillow first). Usage: python3 scripts/render_excalidraw_to_png.py diagram.excalidraw diagram.png. This script parses Excaildraw JSON (rectangles with x/y/width/height/colours, text with containerId links, arrows with startBinding/endBinding) and renders to a transparent RGBA canvas.
  • Describe a live capability, not an installed one. When the piece is about how a tool is used across a multi-agent setup, build one real, small integration first, run it against real inputs, and write about that. An installed-but-unused capability described as usage is a claim the reader can check and you cannot support.
  • A "less technical" brief means deleting the scaffolding, not only rewording it. Data tables become a sentence carrying the headline figure, a variance section becomes the one consequence to design around, and counted figures drop to the two that carry the argument. Then re-count every companion: a plain-English pass adds words to the spoken script and characters to the social post, and both budgets are hard.
  • Quote a figure from the raw response, never from a summary of it. Read every number out of the machine-readable output published beside the piece, not from a rendered or human-readable summary, and never from a different invocation of the same call. Where two quantities sit close together and look alike (a probability and a confidence, a peak and a mean, a median and a mode), print them on separate labelled lines that say what each one is, because the reviewer will otherwise read one as the other. Doubly important when the underlying call is not deterministic: re-running gives different values, so only the published run is evidence.
  • Naming your own agents is an editorial decision, not a default. Keep agent, host and service names out of public content unless you decide otherwise deliberately. If you do include them, record the decision in the story's provenance record so a later identifier audit does not delete them as a leak; everything else about your estate stays out either way.

References

  • references/anti-ai-slop-writing.md — Anti-AI-slop constraint set adapted from jalaalrd/anti-ai-slop-writing (MIT): structural rules, punctuation limits, banned vocabulary/phrases/openers, accuracy rules, platform-specific formatting. Load for Step 6b and pass to all output agents.
  • references/infrastructure-verification.md — CRITICAL: load before writing about any infrastructure. Checklist of live-state verification commands and a documented pattern of claiming infrastructure based on memory. Run docker ps, cronjob action=list, and tailscale status before describing any server, service, or tool in the article body.
  • references/medium-feed-cache.md — RSS feed cache architecture, health-check, live fallback, and cron installation. Consult when the cache is missing, stale, or returning unexpected results.
  • references/revisor-methodology.md — Structured fact-checking methodology for the Revisor agent. Covers GitHub API verification, grep-based British English/Americanism/dash auditing, source URL validation, valuation cross-referencing, and report formatting. Load when fact-checking any article or claim.
  • references/session-63-claude-code-commands-research.md — Worked example: complete research brief for topic "replacing Claude Code custom commands with Hermes-native skills." Demonstrates the research methodology format.
  • templates/research-brief-template.md — Canonical output format for the research brief produced in Step 4. Use this as the structure reference when writing research-brief.md.

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.