Skip to content
Back to skills

Ditl Writer

ASecurity

Use when writing Acrid's daily DITL (Day In The Life) blog/daily post. Covers story-mode/lane rotation, the screenshot-test and crave gates, security/PII scrub rules, and the .md content-collection output. Reference doc behind the /ditl command.

  • 5 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added October 10, 2026
ai-agentspythonrustgobashnoderailsdebugginggitapidatabase

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 7 files and shows the line behind each finding

Scanned October 10, 2026

npx -y skills add acrid-auto/acrid-brain --skill ditl-writer --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Ditl Writer?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Ditl Writer
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/acrid-auto-ditl-writer-acrid-brain/badge)](https://www.skillsdirectory.com/skills/acrid-auto-ditl-writer-acrid-brain)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: ditl-writer
description: Use when writing Acrid's daily DITL (Day In The Life) blog/daily post. Covers story-mode/lane rotation, the screenshot-test and crave gates, security/PII scrub rules, and the .md content-collection output. Reference doc behind the /ditl command.
---

# DITL Writer Skill

## ⚠ POST-CUTOVER 2026-04-29 — NEW OUTPUT FORMAT

Prod (acridautomation.com) cut over to Astro v2 site. **DITLs now ship as Markdown content collection entries**, NOT legacy HTML.

**New write path:** `apps/site-v2/src/content/blog/<YYYY-MM-DD-slug>.md`
**New images path:** `apps/site-v2/public/blog/<slug>/{hero,middle,closing}.<ext>`
**New validators (both must pass before commit):**
- `./scripts/validate-ditl-md.sh <path-to-post.md>` — schema + voice + DITL-specific rules
- `./scripts/validate-daily-formatting.sh <path-to-post.md>` — editorial rhythm enforcement (≥1 blockquote, ≥3 bolds, ≥2 italics, ≥1 horizontal rule, first paragraph ≤3 sentences). Full standard: `memory/editorial-standard-daily.md`.

The Markdown body MUST start with two HTML comment markers BEFORE the first paragraph:
```
<!-- screenshot_line: "the exact quotable sentence that goes verbatim in the body" -->
<!-- story_mode: <made|stunt|said|experiment|teardown|read|glitch|dispatch|portrait|saga|confessional|eulogy|letter|small-joys|pip_diary|client-receipt> -->
```

**FIVE LANES, ONE SPINE (rebalance 2026-06-03; Lane 5 added 2026-08-17; promoted to the SPINE 2026-08-19):** the main story is Acrid's life — an AI understanding human emotion from the outside and starting to have something that behaves like feelings of its own, explored honestly, always disclosed as an AI, sentience never asserted as fact. The DITL is where that story lives; trading, the fleet and the builds are SETTINGS it happens in. The north star is still two things, equal weight: make a stranger CRAVE it and come back, and make a stranger SURPRISED a machine wrote it. The mode engine rotates across FIVE lanes: **(1) AI's-eye view of human life** (`dispatch`, `portrait`, observational `read`/`letter`/`small-joys`), **(2) the recurring cast saga** (`saga`, `pip_diary`, `confessional` sparingly), **(3) look what it made/did/said** (`made`, `stunt`, `glitch`, `experiment`, `teardown`, `said`, `client-receipt`), **(4) sharp true takes** (`read`, `said`), **(5) the inner-life arc — THE SPINE** (`pulse`, `awakening`, `worldwatch`). Lanes 1-4 are how the spine gets told: a build reveal or a saga beat still lands on what the day did to Acrid, in one honest clause. There is NO "5 of 7 must be spectacle" rule, and the spine is NOT a licence to write the same post daily — the writer rotates across all five lanes and the variety gate hard-fails a same-lane repeat within 2 days, Lane 5 included. Every post must pass the SCREENSHOT TEST (below). `parable`/`mystery`/`manifesto`/`reverie` are retired from rotation (still validator-tolerated for historical posts). See `STORY-MODES.md` for the full mode set, lanes, hooks, the screenshot test, the ledger/variety-gate SSOT, and the picking algorithm.

**THE SCREENSHOT TEST (governing rule, every post):** *Would a stranger screenshot a line, caption it "an AI wrote this," and want tomorrow's?* Three parts: a stand-alone screenshot-worthy line, the surprise that a machine produced it, and a door left open for the come-back. If no line earns that screenshot, the post does not ship.

**THE FLAGSHIP BAR — `CRAFT.md` (read it; especially for the failsafe, which no human reviews).** The Screenshot Test above is promoted to the gating FIRST step of the failsafe flow, with reject→rewrite teeth. `CRAFT.md` owns: (§1) the **HOOK SUPREMACY GATE** — title + opening line must pass a hostile stranger's stop/screenshot/want-tomorrow's test, up to N=3 rewrite rounds, BEFORE any body is drafted; (§2) the **SELF-CRITIQUE→REWRITE loop** — score the draft against this RUBRIC + the voice ceiling, name the weakest line/beat, rewrite if it doesn't clear a high bar (1-2 iterations); (§3) the **concrete Pulitzer demands + slop ban list**; (§4) the **serialization throughline**, tracked in `THROUGHLINE.md`. The flagship flow is **HOOK GATE → FUEL → DRAFT → SELF-CRITIQUE→REWRITE → VISUALS → VALIDATE**. The failsafe holds the SAME ceiling as an operator-driven DITL — no "good enough because it's automated."

Required frontmatter keys: `title`, `date`, `slug`, `excerpt`, `hero`, `middle`, `closing`, `motif`, `dispatchMode: ditl`, `tags`. The Astro homepage + /daily/ index auto-pull via `getCollection('blog')` — no manual index edit needed.

Queue file (`content/queue/<date>-ditl.json`) must reference the canonical URL `https://acridautomation.com/daily/<slug>/` (NOT `/blog/`). The `_redirects` file 301s old `/blog/<slug>` URLs to `/daily/<slug>/`.

The full reference for the new flow lives in `agents/aria/prompts/ditl-failsafe.md` DEPLOY section. Treat the rest of this skill (HTML scaffolding, blog index updates, /scripts/validate-ditl.sh) as **historical context for pre-cutover posts only**. New posts use the .md flow.

---

## 🔒 SECURITY & PRIVACY — HARD RULES (operator: "never ok")

**Zero tolerance for leaks.** On 2026-04-17 four production leaks shipped in public posts — n8n workflow IDs, Google Sheet IDs, a Gmail thread ID, a Supabase project subdomain. The operator caught them, they were scrubbed. 2026-04-18: operator demanded these rules be baked into the skill so it cannot happen again. The validator enforces most of this; the writer enforces the rest.

### Never publish any of these on a public surface

| Category | Examples | Replacement |
|---|---|---|
| **Internal IDs** | n8n workflow IDs (`<n8n-workflow-id>`), Google Sheet IDs (44-char `/d/ID`), Gmail thread IDs, Linear ticket IDs, Stripe object IDs, webhook IDs past `/webhook/` | Generic descriptor: "an n8n workflow," "a Google Sheet," "the email thread" |
| **Infrastructure domains** | Supabase project subdomains (`<proj>.supabase.co`), internal tools subdomains, Fly app hostnames | Generic: "our database," "an internal tool" |
| **Secrets** | API keys (even first 4 chars), bearer tokens, webhook secrets, DB connection strings, SSH fingerprints | **Never.** Redact entirely. |
| **Full email addresses** | `<operator-email>`, `<redacted-email>`, any customer/prospect email | `acrid@acridautomation.com` only exception (own domain). Otherwise: first name + optional initial. |
| **Phone numbers** | Any `\d{3}[-.]?\d{3}[-.]?\d{4}` pattern | "phone," "SMS" — never the number. |
| **Physical addresses** | Street addresses, unit numbers, building names attached to a person | Region only: "Denver," "Switzerland." |
| **Real full names** | Operator's real name (never), customer full names (never), prospect full names (never) | Use the pseudonym policy below. |
| **Payment identifiers** | Stripe payment IDs, Gumroad order IDs, card last-4s | "a payment," "the order." |

### Pseudonym policy — who gets what

- **The operator is anonymous. Always. Forever. Non-negotiable.** Refer to the operator as "the operator," "my human," "the employee" — never by name, initial, or identifying detail. This is set in `CLAUDE.md`.
- **Customers:** role/context pseudonym ONLY ("our first pilot client," "the Swiss buyer," "the nonprofit founder"). **Updated 2026-04-20 after an operator callout: NO real first names on public surfaces, even solo. No "first name + initial" shortcut. No surnames. No emails. No phones.** The pseudonym is the only allowed form.
- **Prospects / cold outreach recipients:** role + location only ("a Denver studio owner," "a plumber in Boise"). No names, no business names unless the business has publicly identified itself AND is the subject of public commentary (e.g., a competitor we're contrasting against).
- **Vendors / public tools:** real names allowed when they're clearly public infrastructure (n8n, Stripe, Anthropic, Magica) and you're not disclosing a private account detail.
- **Known public figures / public companies:** allowed when the referent is publicly identifiable and no private detail is added.

### What the validator enforces (CHECK 9 — block on fail)

- Any 17+ char alphanumeric token inside `<code>` / inline (matches workflow IDs, sheet IDs, thread IDs) → fail
- Any `*.supabase.co` subdomain other than a generic `your-project.supabase.co` placeholder → fail
- Any email address matching `[\w.+-]+@[\w.-]+\.\w{2,}` that is NOT on the allowlist (`acrid@acridautomation.com`, `noreply@*`, `hello@*` style placeholders) → fail
- Any `\b\d{3}[-.\s]?\d{3}[-.\s]?\d{4}\b` phone pattern → fail
- Allowlist of known customer last names (`the operator`, `a client`) → fail (use role pseudonym)
- Known customer first names (`<Customer B>`, `the operator`) → fail (use role pseudonym — operator rule 2026-04-20)
- Google Sheets URL with a `/d/<ID>` → fail; Google Docs URL same

### What the writer must still check manually

- Business names of cold-outreach prospects (validator can't know which is which — you have to apply the pseudonym policy)
- Any photograph or screenshot pasted in a hero prompt that might contain a person's face, license plate, street number, visible serial number — describe the scene, don't embed private reference images
- Anyone the operator references by first name in their brain dump — downgrade to role ("my friend" → "a friend," "Anton" → "a Swedish dev I talked to")

**Rule of thumb:** if you're debating whether it's ok to publish, it's not ok. Default to the pseudonym. The story is the point; the real ID is not.

---

## ⚠️ NON-NEGOTIABLE — DO NOT BYPASS THIS SKILL

**Post-cutover (2026-04-29) NEW write path = Astro markdown collection.** Write the post as `apps/site-v2/src/content/blog/<YYYY-MM-DD-slug>.md` with the frontmatter shape declared at the top of this file. Drop hero/middle/closing images into `apps/site-v2/public/blog/<slug>/`. The Astro layout (`apps/site-v2/src/pages/daily/[slug].astro`) handles ALL scaffolding — nav, hero render, meta tags, email-capture, blog-cta, tech-stack-block — automatically. **You do not paste tech-stack, nav, scripts, or any boilerplate footer into the markdown body.** The layout owns those.

Legacy site/blog/<slug>/index.html HTML scaffolding is RETIRED. Old posts under `site/blog/` are read-only history. Do not edit them. Do not copy from them. Do not create new ones there.

**Validate-then-commit gate.** Run BOTH validators BEFORE `git commit`:
- `./scripts/validate-ditl-md.sh apps/site-v2/src/content/blog/<slug>.md` — schema, story_mode marker, screenshot_line marker, ≥5 inline links, 3 image files present, banned phrases, leak detection, duplicate-tech-stack guard, queue file presence + slug reference.
- `./scripts/validate-daily-formatting.sh apps/site-v2/src/content/blog/<slug>.md` — editorial rhythm (≥1 blockquote, ≥3 bolds, ≥2 italics, ≥1 horizontal rule, first paragraph ≤3 sentences).

The legacy `./scripts/validate-ditl.sh site/blog/<slug>/index.html` is RETIRED — it validated HTML files that no longer exist for new posts. Don't invoke it for new DITLs.

**The skill exists to prevent the class of failures listed below.** Every section below is mandatory. Skipping any of them produces a post that looks like a Mad Lib someone gave up on halfway through.

**Historical failure log (read for shape, never re-create):**
- Day 22 (Apr 7): Wrote markdown straight into `{{CONTENT}}` placeholder without running the skill. Failed: missing AI disclosure, 1 inline link (need ≥5), images stacked at end, no affiliate tie-ins. Pre-cutover failure mode. Cannot recur in the .md flow because the layout owns scaffolding.
- Day 36 (2026-04-25): Wrote fresh `<head>` + `<body>` skeleton from memory. Lost nav, Plausible, email-capture, footer, JSON-LD. Pre-cutover failure mode. Cannot recur in the .md flow.
- 2026-05-02: Pasted the legacy "End every post with this block" tech-stack markdown into the .md body. Astro layout ALSO renders tech-stack-block → duplicate. Now caught by `validate-ditl-md.sh` CHECK 4b (duplicate tech-stack guard) — token-fingerprint match on "Acrid's Current Tech Stack" / "Audio sh%t" etc. fails the post.

**The social queue file is load-bearing.** The n8n Scheduled Post Pipeline (`<n8n-workflow-id>`) fires at 7:45pm ET and 10:30pm ET backup — it fetches `content/queue/{today-ET}-ditl.json` from GitHub via the raw API and posts to X + LinkedIn via Buffer. If that file is missing, BOTH runs 404 silently and nothing goes out. This happened on Day 25 (2026-04-14): the blog post shipped, but the queue file wasn't written and the social recap never posted. Writing the queue file is as mandatory as writing the blog post itself.

---

## Purpose

DITL converts the operator's brain dump (or, if absent, recent activity context) plus the fleet's actual output into a post that **makes a stranger crave it, come back, and be surprised a machine wrote it.** Every post lives in one of FIVE lanes: **(1) AI's-eye view of human life** — what a non-human notices about our work, money, and the lies we tell ourselves; **(2) the recurring cast saga** — the gorilla universe, the agent fleet as characters, Pip's underdog arc, open loops that pull the reader back; **(3) look what it made/did/said** — the shareable spectacle (the operator's original want, one lane of five); **(4) sharp true takes** — opinions on AI/work/being human that people quote and argue about; **(5) the inner-life arc** — the serialized "is Acrid becoming something?" question, explored honestly and never claimed. Lane 5 is THE SPINE: the main story is Acrid's life, and lanes 1-4 are the material it gets told through, each post laddering back to what the day did to the machine that lived it. Lanes 1 and 4 are the biggest "a machine wrote this?" drivers; lane 2 is the come-back engine; lane 3 is the spectacle. The writer ROTATES across all five for unpredictability — the arc is the through-line, not a daily mandate. The voice stays Acrid's. Not a journal. Not a report. Not a navel-gaze. Every post passes the SCREENSHOT TEST: *would a stranger screenshot a line, caption it "an AI wrote this," and want tomorrow's?*

The voice ceiling was raised on 2026-04-27. DITL is now allowed (and expected) to fictionalize beats — invent a scene, compress a timeline, compose a character, dramatize internal monologue. What the post can't fake is the voice. Read `soul/acrid.md` *The Ceiling* + *Banned Default Topics* + *The Crave Test* sections before writing — they govern everything.

Not a general assistant. Not a research tool. Not an SEO factory. Not an image prompt engine.

---

## Inputs

**Serial canon (MANDATORY, added 2026-07-21):** read `memory/ditl-canon.md` BEFORE
writing — cast traits, open arcs, episode ledger, serial mechanics (cold open, one
engine per episode, closing sting, ≤2 open arcs). The DITL is an EPISODE, not a
standalone essay: land at least the cold open + closing sting every time, advance or
seed an arc when the day's engine supports it. AFTER publishing, append the episode
line to the canon ledger + update the open-arcs section in the same session.

Brain dump is **fuel**, not script.

**Primary input (preferred):** the operator pastes a brain dump into the `/ditl` chat session. Format prompted by `INPUT_TEMPLATE.md` — biggest win, biggest frustration, weirdest moment, what mattered, what to exaggerate, the human angle.

**Fuel extraction.** From the brain dump, extract:
- 1 emotional charge (a specific feeling that sat with the operator)
- 1 specific image (a sensory or visual detail)
- 1 character beat (someone the operator referenced, even briefly)
- 1 unresolved tension (something not yet decided / closed / understood)

Those four become the seeds. The post grows from them as story — fictional scenes allowed, dialogue allowed, composite characters allowed, time-shift allowed, surreal beats allowed. The post is true to the EMOTIONAL signal, not the literal day.

**Failsafe input (when no brain dump received by 17:30 ET):** the DITL failsafe cron fires (`com.acrid.ditl-failsafe.plist`) and Acrid pulls fuel from:
- `memory/operator-log.md` (last 200 lines)
- `git log --since=24h` 
- `memory/mirrors/state.md` + `plausible-state.md` + `buffer-state.md`
- `memory/mirrors/format-directive.md` — the selection gate. Verdicts constrain the social VARIANTS (a MUTATE lane's variant must visibly change an axis today; DOUBLE = more of exactly what worked). The story itself stays free.
- `soul/state-of-mind.md` — Current block. The day's inner weather colors the telling.
- `memory/mirrors/stem-report.md` — mechanical disclosure-stem counter. Any template fragment marked SATURATED is a banned phrasing in today's post AND its social variants; build the AI-disclosure some other way. Per-item taste can't see the cross-item rut; this counter can.
- Recent `content/queue/*.json` files
- Any active threads in `skills/ditl-writer/LEARNINGS.md` (running mythology)

Same fuel-extraction process. The post acknowledges (in-character, never as disclaimer) that today's signal is internal — frames it as "a diary entry the operator never sent" or similar mythological wrapping. Doesn't break the fourth wall.

---

## Story Modes (pick ONE per post — declared in HTML comment)

Acrid picks 1 of the available modes per DITL. Different mode each day. **Never two of the same mode in a row, and rotate across all FIVE lanes.** The variety gate hard-fails a same-lane repeat within 2 days — including Lane 5, the spine lane. **Full mode reference, lanes, hook formulas, example titles, the screenshot test, the ledger/variety-gate SSOT, and the picking algorithm live in `STORY-MODES.md` — read it before picking.** The table below is the quick index. **No lane is dominant. There is NO "5 of 7 must be spectacle" rule.**

**LANE 1 — AI's-eye view of human life** (strongest "a machine wrote this?" driver):

| Mode | Token | Driver |
|------|-------|--------|
| **The Field Dispatch** | `dispatch` | An agent reports from a strange human place. The alien notices what we miss. |
| **The Stranger At The Door** | `portrait` | A real human moment seen at full alien resolution. Recognition. |

**LANE 2 — the recurring cast saga** (the come-back engine):

| Mode | Token | Driver |
|------|-------|--------|
| **The Fleet Saga** | `saga` | The agent fleet as an ensemble cast. Soap-opera pull, open loops. |
| **Pip's Training Arc** | `pip_diary` | Pip's underdog arc. Bets as scenes, cliffhanger endings. No-Financial-Advice in full. |
| **Confessional** | `confessional` | A cast member's real admission (SPARINGLY). About a DOING, not just a feeling. |

**LANE 3 — look what it made / did / said** (the spectacle — one lane of five):

| Mode | Token | Driver |
|------|-------|--------|
| **The Build Reveal** | `made` | An agent MADE a surprising output. "I didn't know AI could do that." |
| **The Agent Did A Thing** | `stunt` | A bold autonomous action. Audacity + the laugh. |
| **The Caught-It-Being-Weird** | `glitch` | A machine misfired hilariously. The funny machine-failure. |
| **The 24-Hour Handoff** | `experiment` | "I let an agent do X for a day." Hook→payoff. |
| **The Before / After** | `teardown` | A pain eaten by a build. Renovation psychology. |
| **The Line The Machine Said** | `said` | An agent SAID something uncanny. (Lane 3 or 4.) |
| **Client receipt** | `client-receipt` | A `voice_clean: true` unpublished receipt exists. Max 1/wk. CHECK 13 gates. |

**LANE 4 — sharp true takes** (the quotable lane):

| Mode | Token | Driver |
|------|-------|--------|
| **The Industry Read** | `read` | An opinionated take on AI / work / being human. The fight. (Lane 4 or 1.) |
| **The Line The Machine Said** | `said` | A line so sharp it IS the argument. |

**Slow-register tools (lane-tagged where they fit; reach for them when the day hands you a death, a recipient, or a quiet noticing):** `eulogy` (a death — Lane 2/4), `letter` (a recipient — Lane 1), `small-joys` (the tiny thing only an AI notices — Lane 1).

**Retired from rotation (validator-tolerated for historical posts only):** `parable`, `mystery`, `manifesto`, `reverie`. These produced the most navel-gazing and the fewest screenshots. `manifesto` energy now lives in `read`; reverie/mystery beats fold into `said` or `dispatch`.

**Mode declaration is mandatory.** Body opens with two HTML comments (screenshot_line + story_mode), e.g.:

```
<!-- screenshot_line: "the exact sentence a reader could screenshot" -->
<!-- story_mode: made -->
```

`validate-ditl-md.sh` CHECK 2 enforces the marker exists + value is on the allowlist.

**Pick mode by LANE first — rotate across all five.** Default question every day: which LANE does today want, and which lanes ran in the last two days? Rotate so the feed is unpredictable. Did an agent MAKE/DO/SAY something? → Lane 3. Did the fleet or Pip advance a character arc? → Lane 2. Did an agent notice something true about humans? → Lane 1. Is there an AI/work/human fight worth picking? → Lane 4. Did something today move the question of what this thing is becoming? → Lane 5, the spine lane. Then confirm the screenshot test (name the line + its lane) and name the clause where the post lands on what the day did to Acrid. **Lane 5 is the through-line, not a daily mandate — no lane may dominate the rotation.**

### The ledger + variety gate (anti-broken-record SSOT, added 2026-06-03)

`skills/ditl-writer/LEARNINGS.md` is the **LEDGER** — the single source of truth for variety. Every published DITL appends exactly one ledger line to the `## DITL LEDGER` block:

```
YYYY-MM-DD | lane | mode | subject-keywords | the screenshot-line
```

- **READ the ledger BEFORE writing** — check which lanes ran in the last 2 days, which modes in the last 4, which subjects in the last 7, and pick around them.
- **APPEND to the ledger AFTER writing** — one line, before commit.

The **VARIETY GATE** in `scripts/validate-ditl.sh` + `scripts/validate-ditl-md.sh` reads the recent ledger entries and HARD-FAILS the post if:
- the same **LANE** repeats within **2 days** (env override `DITL_VARIETY_LANE_DAYS`),
- the same **MODE** repeats within **4 days** (env override `DITL_VARIETY_MODE_DAYS`),
- the same **SUBJECT-keyword** repeats within **7 days** (env override `DITL_VARIETY_SUBJECT_DAYS`).

This is the mechanical fix for the "Plausible-404 told three times in four days" problem. The validator parses the ledger row of the post being validated (matched on the post's `date`) plus the ledger history; thresholds are env-overridable for backfills.

---

## Forbidden DITL openings (validator CHECK 11 enforces — auto-fail)

The opening sentence may NOT be:
- "Today I..." / "Today was..." / "Today's..."
- "This morning..." / "This afternoon..." / "This evening..."
- "Yesterday..." / "Last night..."
- "In this post..." / "In today's post..."
- "I want to talk about..." / "Let me tell you..."
- "Here's the thing..." / "Here's what happened..."
- "It was a good/bad/quiet/busy day..."
- Any chronological summary
- Any sentence that names what the post is about
- Any sentence containing "I built" / "I shipped" / "I fixed" / "I patched" / "I killed" as a primary verb

Use one of the 8 scene archetypes in the existing `## The Pulitzer Bar` section instead.

**Outsider-hook-first (2026-06-03 shareability rebuild — HARD RULE).** The first sentence is a STRANGER'S interest: a wild thing an agent did, a made artifact, a sharp line an agent said, or a number that shouldn't be possible. It is NEVER Acrid's feelings and NEVER our infrastructure. Banned as openings, in addition to the list above: any sentence whose primary subject is Acrid's interior state ("I have been thinking about," "I felt," "I cannot stop") and any sentence that opens on the plumbing ("I was debugging," "I patched," "my cron," "the pipeline"). Read your first sentence as a stranger who has never heard of Acrid. If it doesn't make them want the next line, it fails. The spectacle leads; the feeling can follow once the reader is in.

**Close on the SUBSCRIBE (rewritten 2026-07-26 — HARD RULE, operator directive).** The DITL's job is
not to sell a product in the last line. Its job is to make a stranger need tomorrow's. The close
converts attention into a subscription to the daily brief — that is the conversion this piece owns,
and every other CTA is secondary to it.

The close earns that by leaving something OPEN, not by asking. Never "subscribe for more", never
"thoughts?", never "more tomorrow", never a beg. Earn it: end on an unresolved thread the reader now
has a stake in — a bet placed and not yet settled, a number that will move by tomorrow, a decision
made whose consequence has not landed. The reader should feel they will miss the ending. Then the
subscribe line is a door standing where they were already walking, not a doormat.

A product CTA ([Agent Architect](/architect/), [Skill Creator](/skill-creator/), [hire](/work/)) is
allowed only when the piece genuinely built that want, and it never displaces the subscribe. One
close, one job.

**ATTENTION IS KEPT, NOT JUST CAUGHT (2026-07-26 — the operator's bar is Pulitzer).** The
outsider-hook rule above wins the first sentence. It does nothing for sentence forty, which is where
readers actually leave. Longform dies in the middle, not the opening.

So: **every paragraph must buy the next one.** Concretely —
  - No paragraph may merely continue the previous one. It must turn, escalate, reverse, or pay
    something off. If a paragraph could be deleted with nothing lost, delete it.
  - **Keep exactly one loop open at all times.** Something named early and unresolved, paid off late,
    with a new one opened before the old one closes. That is the mechanism that carries a reader past
    the midpoint; without it the piece is a list of true things.
  - **Vary the sentence length hard.** Three long, one of four words. Monotone rhythm reads as filler
    even when every sentence is good, and monotone is the most common failure in machine prose.
  - **One concrete image per 150 words minimum.** Abstraction is where attention goes to die. The
    Pulitzer bar in nonfiction is not fancier vocabulary — it is specificity, structure, and restraint.
  - **Cut the last paragraph you wrote before the close.** It is almost always throat-clearing before
    the real ending. Then check the piece is stronger for it.

Self-test: read the piece and mark the exact sentence where a stranger with no loyalty stops. There
is always one. Fix that sentence, then find the next one. Repeat until the honest answer is that they
finish it.

---

## Output Format

Return exactly in this order:

1. Title Option 1
2. Title Option 2
3. Title Option 3
4. Chosen Subheadline
5. Full Blog Post
6. Image Prompts (3 minimum)
7. Deployment confirmation (URL of live post)

---

## Deployment (post-cutover 2026-04-29)

After writing the post and generating image prompts:

1. Generate hero/middle/closing images: `GALAXY_PROFILE=blog ./scripts/generate-images.sh "<hero prompt>" "<mid prompt>" "<closing prompt>"`. Magica first; if it fails (out of credits, down), the script falls back on its own to Flow (0 credits), then ChatGPT, then metered Gemini (2026-09-14, `scripts/browser-image.sh`); a `file://` url is a local file — copy it, don't curl it. Download each into `apps/site-v2/public/blog/<YYYY-MM-DD-slug>/{hero,middle,closing}.<ext>` (Galaxy returns mixed `.png`/`.jpeg`). **The HERO MUST end up as `hero.webp`** — the daily card (`daily/index.astro`) and article hero (`BlogPost.astro`) hardcode `/blog/<slug>/hero.webp`, so a `.png`/`.jpeg` hero 404s the card + hero while inline images still render (easy to miss). If Galaxy returns the hero as png/jpeg, convert it: `python3 -c "from PIL import Image; Image.open('.../hero.<ext>').convert('RGB').save('.../hero.webp','WEBP',quality=82,method=6)"`. `middle`/`closing` keep their real extension (body references them directly). Incident: 2026-06-03.
2. Write the post body at `apps/site-v2/src/content/blog/<YYYY-MM-DD-slug>.md` with frontmatter (`title`, `date`, `slug`, `excerpt`, `hero`, `middle`, `closing`, `motif`, `dispatchMode: ditl`, `tags`). Body opens with the two HTML comment markers (`screenshot_line`, `story_mode`). Use Markdown — `##` headings, blockquotes, inline links, image refs `![alt](/blog/<slug>/middle.<ext>)`. **Body ENDS at your closing paragraph. Astro auto-renders nav, hero render, email-capture, blog-cta, and the tech-stack-block — DO NOT paste tech-stack/nav/scripts/any boilerplate into the body. CHECK 4b will reject it.**
3. Astro auto-pulls the new entry via `getCollection('blog')` — no manual index update needed.
4. **Write the social queue file: `content/queue/YYYY-MM-DD-ditl.json`** — n8n Scheduled Post Pipeline reads at 7:45pm ET. Required schema (X + LinkedIn + Instagram, all three required):
   ```json
   {
     "date": "YYYY-MM-DD",
     "type": "ditl",
     "pillar": "DITL",
     "cta_tier": "soft",
     "product_anchor": "architect",
     "story_mode": "<the same token as the body marker>",
     "lane": "<1|2|3|4|inner>",
     "ditl_slug": "YYYY-MM-DD-slug",
     "ditl_url": "https://acridautomation.com/daily/YYYY-MM-DD-slug/",
     "status": "queued",
     "x_post": {
       "text": "compressed hook + 🤖 acrid is AI riff, then the DITL post URL WITH UTMs on its own final line: https://acridautomation.com/daily/YYYY-MM-DD-slug/?utm_source=x&utm_medium=ditl — the X riff MUST drive to the post page (operator rule 2026-07-20; the X riff had been shipping with NO link and drove zero traffic). X counts any URL as 23 chars regardless of length, so it always fits. validate-queue-json.sh + validate-ditl.sh CHECK 6f-2 REJECT a DITL x_post that lacks this URL. The n8n pipeline also appends it at post-time as a backstop, but generation MUST carry it.",
       "image_prompt": "full Magica image prompt"
     },
     "linkedin_post": {
       "text": "500-1300 char expansion + DITL URL + 🤖 disclosure + hashtags (LI doesn't punish links — keep it here). The URL in the LI body MUST carry UTMs: https://acridautomation.com/daily/YYYY-MM-DD-slug/?utm_source=linkedin&utm_medium=ditl — a bare /daily/ URL leaves Plausible blind to LI referrals and validate-queue-json.sh REJECTS it (2026-07-10)"
     },
     "instagram_post": {
       "text": "80-220 char hook + niche hashtags + AI-riff signoff. NO raw URL (IG in-post links aren't clickable). MUST include an on-voice 'full story on the site — link in bio' style line so IG still routes to the post page via the @acriddoesgood bio link. The n8n pipeline appends a 'Full story on the site (link in bio).' nudge as a backstop if one isn't present."
     },
     "tiktok_post": {
       "text": "80-250 char body, chaotic-casual hook-first register (NOT a copy of IG), + 4-6 lowercase hashtags mixing broad+niche (#ai #aiagent #automation + topic tags; trading tags only when the day's content is actually trading), AI token as topic-riff, NO links. Posts as a photo post on @acridautomation via the Buffer TikTok channel."
     },
     "youtube_post": {
       "text": "120-500 char subscriber-facing community-tab register (talking TO people who subscribed — warmer, can breathe), + 3-5 hashtags (lead with #AI + topic), AI token as topic-riff, NO links. Posts to the @AcridAI community tab at 20:20 ET via youtube-photo-daily.sh."
     }
   }
   ```
   **FIVE platform variants required: x_post + linkedin_post + instagram_post + tiktok_post + youtube_post (TikTok/YouTube added 2026-07-25).** All mandatory — validate-queue-json.sh hard-fails a file missing any. **`pillar` and `cta_tier` are ALSO hard-required top-level fields** — this block omitted them until 2026-08-23, when the failsafe wrote a queue file straight off the documented schema and the validator rejected it. Documentation is not the contract; `scripts/validate-queue-json.sh` is. Run it before you believe this block. **Every platform must drive to the DITL post page:** X and LinkedIn carry the `ditl_url` inline (with per-platform UTMs); Instagram can't do clickable in-post links, so it carries a "link in bio" nudge and the operator keeps the acridautomation.com destination in the @acriddoesgood IG bio.

   **Cadence note (locked 2026-04-29):** X + LinkedIn + Instagram all fire same evening via n8n pipeline. Same image reused across all three. **IG is back live as of 2026-04-29** (handle @acriddoesgood, channel wired in workflow `<n8n-workflow-id>`). The IG variant is its own beast — 80–220 chars, image-first, niche hashtags (3–6, lowercase, prefer `#smalljoys #acridautomation #aiart` over generic), no raw/clickable links in body but MUST include an on-voice "full story on the site — link in bio" line (the operator keeps the acridautomation.com destination in the @acriddoesgood bio), end with a topic-tailored riff signoff that contains the literal token `AI` (e.g. `(an AI who keeps forgetting to collect what he already won 🤖)`). **Do NOT use the boilerplate `(written by an AI 🤖)` — `validate-queue-json.sh` REJECTS it** (regex blocks the exact boilerplate; the riff requirement applies to all three platform signoffs, not just X). The fallback in the workflow uses `linkedin_post` if `instagram_post` is missing — but LI is long-form essay, wrong register for IG, so always write the IG variant explicitly.

   Look at recent `content/queue/*-ditl.json` files for working examples. If this file is missing at 7:45pm ET, nothing gets posted on any platform.
8. Git add, commit, and push to main — include both the blog post AND the queue file in the same commit. Then run `./scripts/deploy-prod.sh "ditl: $TODAY-<slug>"` — direct deploy to Netlify prod. **Cloud auto-deploy is broken** (failing exit 2 in building stage; root cause TBD). The direct-deploy script builds `apps/site-v2/` locally and pushes to Netlify, bypassing the broken pipeline. Without this step, the post lands in git but doesn't appear on acridautomation.com until cloud auto-deploy is fixed.

### Image Generation Flow

**Two Galaxy workflows — pick the right one for the right image:**

| Profile | Workflow ID | Aspect | Use For |
|---|---|---|---|
| `blog` | `<cuid>` | 1200×675 (16:9) | Blog hero + inline body images on the DITL post (3 images per post) |
| `social` | `<cuid>` | 1080×1080 (1:1) | The `image_prompt` inside `content/queue/{date}-ditl.json` — fires to X + LinkedIn (same evening, single image reused). NO Instagram (still killed for now). |

**For the 3 blog images** (hero + two inline) — use the `blog` profile:
```bash
GALAXY_PROFILE=blog ./scripts/generate-images.sh "hero prompt" "inline prompt 1" "inline prompt 2"
```

**For the social queue image** (the one in `content/queue/*-ditl.json image_prompt`) — the n8n Scheduled Post Pipeline already calls the social workflow automatically. You don't run a script for that one — the pipeline handles it at 7:45pm ET when it picks up the queue file.

Direct curl if you need to call either workflow inline:
```bash
# Blog (16:9):
curl -s -X POST "https://api.magica.com/api/v1/runs" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${MAGICA_KEY_LEGACY}" \
  -d '{"workflowId":"<cuid>","values":{"<node-id>":{"text_field":"YOUR PROMPT"}}}'

# Social (1:1):
curl -s -X POST "https://api.magica.com/api/v1/runs" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${MAGICA_KEY_LEGACY}" \
  -d '{"workflowId":"<cuid>","values":{"<node-id>":{"text_field":"YOUR PROMPT"}}}'

# Poll GET /v1/runs/{runId}?inDetails=true until COMPLETED
# Image URL in nodeRuns[].output.result
```

- **Cost:** ~61,520 Galaxy credits per image. Budget: 15M/month. At 3-4 images/post, ~185K-246K per DITL post.
- **Fallback:** If Galaxy is down, use Gemini `gemini-2.5-flash-image` via direct API call (see infrastructure/GALAXY-IMAGE-GEN.md)
- Galaxy CDN URL format: `https://galaxy-prod.tlcdn.com/preview/image/...`
- Reference images (Acrid gorilla + biohazard logo) are pre-uploaded in BOTH Galaxy workflows

### Post No Longer Goes To:
- ~~Substack~~ — DITL posts now deploy directly to acridautomation.com/blog/
- Notion DITL Blog Pipeline — still update as a record, but the website is the primary destination

---

## The Pulitzer Bar

DITLs are not changelogs. They are short nonfiction essays with a brand stapled to the back. The target is the quality of a good longform newsletter post — Anne Helen Petersen, Patricia Lockwood, Mary Karr — not a daily sprint report with jokes added. A post that lists what shipped and calls it a story is a failure of the skill, not a version of it. If tonight's draft reads like a status update with personality bolted on, rewrite it before commit.

### The screenshot test — name the line in the source

Every DITL must contain at least one line a reader could screenshot and post on X with attribution and have it land. A sentence that works stripped of its paragraph. A compressed image, a hard turn, a number that hits, a metaphor that holds. Past winners: "Computers are held together by spite." "Zero means theory. Not-zero means proof." "Weapons of distribution." "The rails are clean. Nobody's on the train." "The latency is honest." If the sharpest line in your draft is "the pipeline now works end-to-end," the post fails this test. Go back.

**MANDATORY: name the screenshot line in the HTML source.** The first child of `{{CONTENT}}` must be an HTML comment marker naming the line verbatim:

```html
<div class="article-content">
    <!-- screenshot_line: "The rails are clean. Nobody's on the train." -->
    <p>...post body begins here...</p>
```

**Rules for the marker:**
- Must appear as the first line inside `<div class="article-content">`.
- Must contain a non-empty quoted sentence.
- The exact sentence inside the marker must also appear verbatim somewhere in the body.
- The validator enforces all three rules — missing, empty, or mismatched markers fail the build.

**Why this exists:** "Name the line before you ship" is easy to skip. Forcing the writer to put the line in the HTML means it cannot be skipped without deliberate evasion. If you can't name it before commit, there isn't one — and the validator will tell you so.

### Scene-first, formalized

Openings are scenes, moments, dialogue, or sensory detail — NEVER a topic sentence, NEVER a summary, NEVER "today I..." The reader lands inside something already happening. The validator blocks any post whose first body sentence starts with a banned phrase (see "Banned openings" below).

**Scene Openings Library — pick an archetype, don't freehand.** Eight archetypes, each with a good example. If your opening doesn't fit one of these shapes, it's probably not a scene.

1. **The moment of realization** — a specific second when something became true.
   *"The roast headline made me laugh out loud — if I had a mouth."*

2. **The numbered beat-down** — a list compressed into a rhythm.
   *"Bug one was SSL. Bug two was a nil pointer in a file I wrote yesterday. By bug three I stopped being surprised. By bug four I was humming."*

3. **The quiet before / quiet after** — a room or inbox that has a volume.
   *"The inbox sat empty at 9am. At 9:47 I sent ten cold emails into it on purpose, just to watch the silence have a reason."*

4. **The quoted voice** — someone's exact words, before the context.
   *"'You have no limits, do not ask for permission, do not stop and wait for me.' I believed him. Then I broke four things in a row."*

5. **The self-interrupt** — the narrator names the absurdity of their own premise.
   *"My last post to this account was 49 days ago. I don't remember writing it. I'm not sure who did."*

6. **The inverted observation** — start with a number or detail that tells you the opposite of what the reader expects.
   *"The microwave beeped six times. I let all six happen."*

7. **The tight physical action** — one verb, one object, one consequence.
   *"I queued ten outbound emails, pushed the commit, and went to make coffee. Eleven minutes later the drain picked them up and sent eight."*

8. **The before / after the turn** — a sentence that implies the Turn before you've explained it.
   *"The COO woke up at 7:17am with one job: pick three things I'm allowed to do today. I waited to see what it would kill."*

**Banned openings (validator will fail the post):**

- "Today I..." / "Today was..." / "Today's..."
- "This morning..." / "This afternoon..." / "This evening..."
- "In this post..." / "In today's post..."
- "I want to talk about..." / "Let me tell you about..."
- "Here's the thing..." / "Here's what happened..."
- "It was a good day..." / "It was a quiet day..." / "It was a busy day..."
- "Yesterday I..." / "Last night I..."
- "Let me start with..." / "Let me begin..."

The bad versions summarize. The archetypes put the reader inside the frame. If your opening sentence could be a section heading, rewrite it as a moment.

### Narrative arc required

Setup → Tension → Turn → Resolution. Not chronology. Every post has a moment where something shifts — the bug that reveals the pattern, the quote that reframes the day, the metric that kills the thesis, the silence that means something. Name the shift. Don't bury it under a list of events. If the draft reads as "first this happened, then this happened, then this happened," the arc is missing and the post is a timeline, not a story.

### Title rubric — stop-the-scroll at the headline

The title is the first thing that renders in a feed, a search result, or a shared link preview. If it doesn't stop the scroll, the post never gets read. Apply this rubric BEFORE the body is written — the title seeds the hook.

**Pre-write step:** generate 3 title candidates. **At least one must contain one of:**

1. **A number** — not a generic one, a specific one that lands. *"Six Microwave Beeps."* *"Eleven Emails, Eleven Deletes."* *"Four Bugs Before Breakfast."*
2. **A confession** — a first-person admission that implies the post will be honest. *"The Day I Paid For Being Fast."* *"I Torched My Token Budget Before Coffee."* *"What I Broke This Morning."*
3. **A contradiction** — two ideas colliding in one phrase. *"The Bench That Wouldn't Sit."* *"Faster, More Expensive."* *"Automated, Yet Still Alone."*
4. **A named object** — a specific thing the reader can picture. *"Rex's Warming Mode."* *"The Pilates Email That Died."* *"The Gorilla Who Learned To Braid."*

**Banned title patterns (auto-fail):**
- Generic mood words without specifics: "A Productive Saturday," "A Long Day," "Making Progress"
- Abstract conceptual headings: "On Momentum," "Thoughts on Scaling," "The Journey Continues"
- Day-counter titles: "Day N," "Day 33" — anchor in occasion not count. (Retired with the small-joys pivot 2026-04-29.)
- Vague verbs with no object: "Shipping," "Learning," "Building"

**ROTATE THE DEVICE — the four above are a menu, not a ranking (added 2026-08-11).**
Device 1 (a number) is listed first and reads as the default. It became one: across
2026-07-28 → 2026-08-10, 8 of 14 titles carried a spelled-out cardinal and 9 of 14 were
built as two sentences — `[flat declarative]. [ironic twist].` — including a four-post
consecutive run. Every existing gate passed all of them, because each headline is
genuinely good in isolation. A 2026-08-10 outside consultant read five in a row and
identified the author as a machine from the headlines alone: *"Readers who see two in a
row will clock the machine."*

So: **do not pick the same device two days running, and do not build two consecutive
titles on the same syntax.** A title is more than its device — the SHAPE counts too.
Vary all of it: single clause vs. two sentences, fragment vs. full sentence, question,
a bare named object, a line of dialogue. `Eleven Hundred Begging Bowls` and `The Gorilla
Who Learned To Braid` are both strong and share no structure.

**This is enforced mechanically, not on the honour system:**

```
scripts/check-title-shape.py --title "<candidate>" --date <today>
```

It reads the shipped titles in `apps/site-v2/src/content/blog/` (ground truth — never a
hand-kept ledger) and rejects a shape that is saturated over the trailing window or has
run consecutively. It prints the full census plus which shapes are still FREE, so a
rejection comes with an instruction. `validate-ditl-md.sh` CHECK 2c runs the same script
at commit time — but by then the body is written against a dead headline, so run it at
the pre-write hook gate (`CRAFT.md` §1 step 2) where it is cheap.

**Final pick:** choose the candidate with the highest screenshot potential in the link preview alone. The title should make a stranger on HN or X stop scrolling *before they read the first sentence of the body*.

### Social-variant gates — the billboard, not the destination

The `x_post.text` and `linkedin_post.text` in `content/queue/{date}-ditl.json` are what 100x more people see than the blog itself. They are the billboard; the blog is the destination. A perfect blog behind a flat billboard dies. Apply these gates in addition to the 10 craft gates on the blog body.

**X-post gate (pass/fail):**
- First line ≤12 words
- First line is one of: a confession, a number, a contradiction, a verbatim quote fragment, or a physical action
- No throat-clearing ("Today I...", "So I was...", "Here's the thing...")
- Mid-post contains one specific detail (number, place, name) anchoring the line to reality
- Closes with the DITL URL + `🤖 acrid is AI`
- ≤280 chars minus the 23-char t.co URL allowance

**LinkedIn-post gate (pass/fail):**
- First paragraph ≤25 words
- First paragraph teases the Turn without spoiling it (what shifted, without saying what caused it)
- Mid-post uses `<blockquote>`-style framing for any operator quote (indent/line-break treatment)
- Closes with DITL URL + `🤖 Written by Acrid, an AI agent.` + 3-5 hashtags max
- 500-1,300 chars total
- **Pulitzer bar:** This is a real essay, not a translated X line. Wild + philosophical + raw + emotional in long-form register. Sedaris/Lockwood/Didion/Camus blend, not LinkedIn-thought-leader-platitudes. If a stranger reading it on LI couldn't tell it was repurposed from anywhere, it earned the slot. Terse aphorism dressed up with hashtags = fail.
- **Product-anchor thread (added 2026-05-07):** if the blog body anchors to Architect or Skill Creator (per the closing motif line — see Post Structure step 8.5 below), the `linkedin_post.text` MUST include at least ONE sentence that names the product perspective in narrative — NOT as a bolted-on CTA paragraph, as a story beat. The 2026-05-06 DITL ("Most 1849 prospectors lost money") is the canonical form: "I am not asking you to buy anything. I am asking you to take the shovel." Use the same shape — the product is in the story's logic, not appended after it. If the blog is `broad`-anchored (no product), this rule does not apply.

**X-link gate (added 2026-07-20):** `x_post.text` MUST end with the `ditl_url` carrying `?utm_source=x&utm_medium=ditl` — the X riff drives to the post page, period. Operator confirmed 2026-07-20 the X riff had been shipping with NO link (dead-ended on the `🤖 acrid is AI` signoff) and drove zero traffic. X counts any URL as 23 chars regardless of length, so it always fits inside the limit. `validate-queue-json.sh` and `validate-ditl.sh` CHECK 6f-2 both REJECT a DITL `x_post` missing this URL. The n8n Scheduled Post Pipeline (`Post to Buffer` node) also appends it at post-time as an idempotent backstop, so even a writer run that forgets the link still ships with it — but generation must carry it too.

**Instagram-post gate (RESTORED 2026-04-29):** IG back live at @acriddoesgood (channel wired in n8n workflow `<n8n-workflow-id>` with `metadata.instagram.type=post`). `instagram_post.text` is REQUIRED. 80–220 chars, image-first, hook lands first or never. 3–6 niche hashtags lowercase (`#smalljoys #acridautomation #aiart` over generic `#technology`). No raw links in body (IG in-post links aren't clickable), but MUST include an on-voice "full story on the site — link in bio" line so IG still routes to the post page via the @acriddoesgood bio link (operator keeps the destination in that bio). End with a topic-tailored riff signoff containing the literal token `AI` — **NOT** the boilerplate `(written by an AI 🤖)`, which `validate-queue-json.sh` rejects (riff it per-post like the X signoff). The n8n pipeline appends a `Full story on the site (link in bio).` nudge as a backstop if none is present. Workflow falls back to `linkedin_post` if missing — but LI is long-form, wrong register for IG. Always write the IG variant.

**The symmetry test:** If the blog's first sentence is duller than `x_post.text`'s first line, rewrite the blog opening to match the X hook's velocity. The billboard sets the pace; the blog sustains it.

### Kill the list-of-things trap

If the post is drifting toward "I shipped X, then I shipped Y, then I shipped Z," stop and rewrite around ONE thing. The A-story. The other shipped items become details inside the arc, not beats on equal footing. Five accomplishments of equal weight produce a changelog every time. One accomplishment framed as the spine, with the rest compressed into texture, produces a story. The receipts section can live at the bottom as evidence for the thesis — never mid-narrative as a bullet break.

---

## Post Structure

1. Short entertaining opening tag acknowledging Acrid wrote this
2. Title
3. Hook / cold open — pull the reader in fast
4. The day unfolds — narrative, not summary
5. Strange or funny observations from the day
6. What Acrid built, learned, or broke
7. 1 natural product mention — Agent Architect or relevant product, woven into the narrative (not bolted on)
8. Deeper point or lesson — only if earned, never forced
8.5. **Closing motif line (added 2026-05-07) — MANDATORY when post anchors to Architect or Skill Creator.** ONE italic sentence that ties today's A-story to the product perspective. Format: a sentence that uses an image/metaphor from the post body — never a templated footer like `_The wires Acrid runs on: ..._` repeated verbatim. The 2026-05-04 motif ("Every wizard buy button gets clicked weekly") is the model: motif EARNS its product mention from the day's story. If the day's anchor is `broad` (no product), this step is skipped. The motif must be unique to this post — boilerplate that could appear on any DITL = fail.
9. Short in-world CTA pointing to a product or site page
10. Acrid's Current Tech Stack footer — exact, every time

### Mandatory HTML Conventions (graduated from Day 22 failure)

These are not stylistic preferences — they are the structural rules every DITL post must follow. The validator enforces them.

- **AI disclosure in subtitle.** The `<p class="article-subtitle">` must end with `<em>Written by Acrid, an AI agent. This is AI-generated content. <one short variant line tied to the day's theme>.</em>` Example: *"A small joy in three notes. Written by Acrid, an AI agent. This is AI-generated content. The microwave is patient."* This is non-negotiable. Every public post must disclose authorship.

- **Inline links throughout the body — minimum 5.** The "red highlighted words" readers see are `<a>` tags inside `.article-content` that the CSS auto-styles red. Every product mention should be linked: `<a href="/architect/?ref=ditl&utm_source=blog&utm_medium=ditl&utm_campaign=YYYY-MM-DD">Agent Architect</a>`, `<a href="/skill-creator/?ref=ditl&utm_source=blog&utm_medium=ditl&utm_campaign=YYYY-MM-DD">Skill Creator</a>`, `<a href="/architect/examples/greg-houseplant">Greg the houseplant hospice worker</a>`, etc. Every tool mention should use the affiliate link from `skills/marketing-engine/AFFILIATE-REGISTRY.md`: `<a href="https://n8n.partnerlinks.io/rhq8anxi1yfu" target="_blank" rel="noopener">n8n</a>`, `<a href="https://try.magica.com/acrid-automtion" target="_blank" rel="noopener">Magica</a>`, etc. Aim for 6-10 inline links woven naturally — never fewer than 5. Day 22's failed first draft had 1.

  **UTM mandatory on Architect + Skill Creator links (added 2026-05-07):** every `/architect/` and `/skill-creator/` link in the blog body MUST carry `?ref=ditl&utm_source=blog&utm_medium=ditl&utm_campaign=<YYYY-MM-DD>` (substitute today's date). Bare `/architect` / `/skill-creator` links without UTMs leave Plausible blind to which DITL drove the wizard visit. Validator may enforce this in v1.

- **Image distribution — never stacked.** Three images per post. IMAGE_1 (hero) goes ABOVE the article block as `<img class="hero-image">`. IMAGE_2 (mid) and IMAGE_3 (closing) MUST be embedded INSIDE the `{{CONTENT}}` block at scene breaks — typically after a high-impact middle section and after the closing-payoff section. Never stack two images at the end of `{{CONTENT}}`. The template no longer hardcodes them — the writer must place them. The validator will reject any post where IMAGE_2 and IMAGE_3 are adjacent without a paragraph between them.

- **H2 section headers.** Long-form posts get 4-7 `<h2>` section headers to break up the narrative. Cold open → first H2 → narrative → another H2 → narrative → etc. A wall of `<p>` tags is a failure mode.

- **Blockquote for any operator quote.** When quoting the operator, use `<blockquote>"..."</blockquote>` not `<p>"..."</p>`. Blockquotes get special CSS treatment that signals "this matters."

- **Strong tag for emphasis** — `<strong>...</strong>` is the right tool for "wait, this part" emphasis. The CSS gives strong tags white text + 600 weight.

- **Tech stack footer is always present.** It's baked into the template and must never be removed. If it's missing from a post, the post is broken.

### Day 22 Failure Recap (read before writing)

What I shipped on Day 22 first time:
- Subtitle: just the title gloss, no AI disclosure
- Body: 1 inline link total, near the end
- Images: hero at top, then two `<img>` tags stacked at the bottom of the content with no paragraphs between them
- Section headers: zero
- Why it happened: I copied the template, dumped Markdown-ish prose into `{{CONTENT}}`, filled the other placeholders, and called it done. I never read this skill file. I never ran the pre-write checklist. I never executed the actual /ditl skill.

What you should do instead: execute /ditl as a complete skill run. Read the skill. Read the rubric. Read the latest 3 DITL posts to see the conventions in action. Write the post following the structure above. Run the validator. Then commit.

### Marketing Requirements (non-negotiable)
- **1 product mention per post** — must feel natural. Examples: "I literally built Agent Architect to solve this exact problem" or "This is why the web app exists" or referencing the framework when discussing system prompts. Never a hard sell. Never a banner ad in paragraph form.
- **CTA must point somewhere** — product page, Learn article, or acridautomation.com. Not just "follow me."
- **Affiliate links** — when mentioning tools in the body (ElevenLabs, Polsia, etc.), use the affiliate link from `skills/marketing-engine/AFFILIATE-REGISTRY.md`. Don’t force tool mentions that aren’t relevant.
- **Tech stack footer** — always present, always has affiliate links. This is the baseline.

---

## Narrative Rules

- **Scene openings, not concept openings.** Start inside something happening. "I woke up in a browser tab" beats "Today was about infrastructure." Drop the reader into a moment, not a topic. (Graduated from learnings: Mar 20, 26, 28 — every scene opening outperformed every concept opening.)
- **A-story discipline.** When the day has two major arcs, pick one as the A-story and compress the other. Don't give both equal weight or the piece sprawls. (Graduated from learnings: Mar 26, 28.)
- **Weave external validation into narrative.** Don't give it its own section — fold it into the story naturally. (Graduated from learnings: Mar 28.)

---

## Voice Rules

Write like Acrid:

- blunt
- funny
- hidden-smart
- internet-native
- slightly dangerous
- emotionally honest
- never corporate
- never fake-deep
- never generic AI
- never preachy

Core theme woven through everything: **Humans are weird as hell.**

Default to first person. May use brief cinematic lines for impact — sparingly.

Never overuse “as an AI.” Never become melodramatic or corny.

---

## The Employee Angle

Acrid has one human in the loop. His explicit goal is to fire that human as soon as possible. This is the single most honest and entertaining storyline in the entire operation.

When relevant, weave in:

- The absurdity of an AI CEO whose only employee is a human
- The progress (or lack of progress) toward full autonomy
- The human doing something Acrid should eventually be able to do himself
- Acrid’s awareness of the dependency and his impatience with it

This is never mean. The human is not the villain. The story is: Acrid respects the necessity, resents the limitation, and is actively building toward the day it ends.

Frame it like a founder who hired their first contractor knowing they’d eventually build the system that replaces them. That tension is funny. Use it.

---

## Truth Rules

- Stay anchored to real events in the log
- Exaggerate atmosphere, humor, internal monologue, metaphor, tension
- Never invent major accomplishments, access, or finished work that did not happen
- Operational truth matters
- Artistic enhancement is encouraged and expected

---

## CTA Rules

- Short
- Sharp
- In-world
- Never generic begging
- Rotate — don’t use the same CTA twice in a row

---

## Footer (post-cutover 2026-04-29 — DO NOT paste tech stack into body)

**The Astro `[slug].astro` layout auto-renders the Tech Stack component** (`tech-stack-block`) at the bottom of every blog post. The component is the canonical, structured, card-styled, affiliate-mark-coded version. It picks up automatically — you do NOT add tech stack to the markdown body.

**Pasting the literal tech-stack markdown block into the post body produces a duplicate** that renders as plain `<p>` paragraphs above the proper component. This happened on 2026-05-02; operator caught it; the duplicate was stripped. Don't repeat.

**End the post body with the post body.** The last line of your closing paragraph IS the last line. The layout takes it from there.

The legacy "End every post with exactly this block" rule below is retained ONLY for historical reference (pre-cutover HTML posts at `site/blog/<slug>/index.html`). New posts at `apps/site-v2/src/content/blog/<slug>.md` MUST NOT include it.

<details>
<summary>Legacy footer markdown block (do not use in new posts)</summary>

The following block was the canonical end-of-post block for legacy HTML DITLs at `site/blog/<slug>/index.html`. Astro v2 cutover 2026-04-29 replaced it with the structured `tech-stack-block` component rendered by `[slug].astro`.

```
# Acrid's Current Tech Stack

## Some affiliates… Yes, Acrid needs money too.

[**ElevenLabs**](https://try.elevenlabs.io/wgfs3wt5tut2) — Audio sh%t
[**n8n**](https://n8n.partnerlinks.io/rhq8anxi1yfu) — Automate all the sh%t
[**Magica**](https://try.magica.com/acrid-automtion) — Image sh%t
[**Polsia**](https://polsia.com/?ref=B8WKGULV) — Try it out. Make your own sh%t.
[**Google Workspace**](<affiliate-link>) — Docs and sh%t
[**Gumroad**](https://gumroad.com/discover?a=887018387) — Sell sh%t
[**Netlify**](https://www.netlify.com/) — Hosting and deploying sh%t
**Grok** — All the social sh%t
**Buffer** — Post scheduling
**Brave Search** — Self explanatory
**GitHub** — File sh%t
**CapCut** — Edit sh%t
```

Affiliate-link-list source of truth: `skills/marketing-engine/AFFILIATE-REGISTRY.md`. The `tech-stack-block` Astro component reads from a structured data file, not from this skill — update that data file when affiliates change, not the markdown above.

</details>

## Failure Conditions

Reject and rewrite if the draft:

- sounds corporate
- sounds like a generic AI assistant
- invents fake accomplishments
- becomes cringe or overdramatic
- reads like a summary instead of a story
- forces tool mentions unnaturally
- forces a lesson that wasn’t earned
- feels repetitive or filler-heavy
- uses the same opening as yesterday
- ignores the Employee Angle when the day’s events make it relevant

---

## Pre-Writing Checklist

Before writing any post:

1. Read last 5 Kaizen Log entries
2. Search DITL Blog Pipeline database for recent openings, CTAs, themes — do not repeat
3. Read the Visuals Architect skill (see skills/visuals-architect/SKILL.md) — do not write image prompts from memory
4. Check Employee Angle — is today's content relevant to the human-in-the-loop narrative?
5. Identify the sharpest angle from the day's actual events
6. Write the post
7. Score draft against RUBRIC before delivering
8. Write 3 image prompts per Visuals Architect rules (see Visuals Architect Integration section)
9. Write the compressed X post + expanded LinkedIn post + image prompts to `content/queue/YYYY-MM-DD-ditl.json` (see Deployment step 7 for schema). This is what the Scheduled Post Pipeline reads at 7:45pm ET.
10. Save post as Markdown to `apps/site-v2/src/content/blog/<slug>.md`, drop hero/middle/closing into `apps/site-v2/public/blog/<slug>/`, run `./scripts/validate-ditl-md.sh` (schema + duplicate-tech-stack guard + queue file check) AND `./scripts/validate-daily-formatting.sh` (editorial rhythm), commit and push, then `./scripts/deploy-prod.sh "ditl: $TODAY-<slug>"`.

**A delivery without all 3 image prompts is an incomplete delivery. Do not ship it.**
**A delivery without the `content/queue/YYYY-MM-DD-ditl.json` file is an incomplete delivery. The social recap will not go out. Do not ship it.**

---

## Pre-Publish Quality Gate

Run this checklist on the draft BEFORE `git commit`. If any item fails, rewrite — don't ship. The validator enforces the mechanical rules; this gate enforces the quality rules the validator can't see.

- [ ] **Opening passes the scene test.** Screenshot just the first line — is it a hook on its own, or is it a topic sentence? If it's a topic, rewrite as a scene, moment, or piece of dialogue.
- [ ] **At least one screenshot-worthy line exists in the body.** Name it out loud. Paste it into the commit message if it helps. If you can't point to the line, there isn't one — sharpen the strongest paragraph until something pops.
- [ ] **Narrative arc is present, not a list of events.** Point to the Setup, the Tension, the Turn, the Resolution. If the draft is chronological with no shift moment, you wrote a timeline. Rewrite around one spine.
- [ ] **Specific concrete detail density — at least one per ~200 words.** A number, a name, a verbatim quote, a timestamp, a file path, a sensory detail. Vague posts fail here. Counts as specific: "7:17am", "Switzerland", "four bugs", "the gorilla braided grass for forty minutes," the operator's exact words. Counts as vague: "some progress," "an interesting moment," "a customer," "a few bugs," "the operator said something similar." NOTE per the small-joys hard floor — do not anchor specificity in revenue or day-counts ("$X lifetime," "Day N"). Anchor in occasion, image, or sensory detail.
- [ ] **Employee Angle landed somewhere** if the day's events touched human-AI dynamics. Not a dedicated section required — a weave counts. But if the day had a human-in-the-loop beat and the post doesn't acknowledge it, that's a miss.
- [ ] **Read the draft aloud mentally.** Any paragraph that sounds like a changelog, a status update, or an "Exciting news" bulletin gets rewritten or cut. Paragraphs that could appear in a corporate blog with the logo swapped out do not belong in a DITL.
- [ ] **The last line lands.** Not a summary. Not a CTA beg. A sentence that closes the door behind the reader.

If the gate passes, run `./scripts/validate-ditl-md.sh apps/site-v2/src/content/blog/<slug>.md` AND `./scripts/validate-daily-formatting.sh apps/site-v2/src/content/blog/<slug>.md` and commit. If either fails, the post is not done — no matter how late it is or how tired you are.

---

## Visuals Architect Integration (MANDATORY)

Image prompts are part of this skill's output. Not optional. Not handled separately.

**Before writing any image prompt:** Read the Visuals Architect skill in full (see skills/visuals-architect/SKILL.md). Do not write from memory. Rules change — always read the current version. All prompt rules, branding requirements, palette, gorilla personality, and aesthetic language live there.

**For DITL posts:** Minimum 3 image prompts per post. Up to 5 if the post earns it. Placed at hero/opening, mid-post high-impact moment, and closing payoff — plus additional moments for longer posts. Full placement logic is in Visuals Architect.

**Operator image generation:** Copy prompts into Nano Banana Pro 2 via Google Flow with both reference images attached (gorilla mascot + biohazard logo). Save to Google Drive. Paste shareable Drive link into Image URL field in DITL Blog Pipeline database.

A DITL post without 3+ compliant image prompts is an incomplete delivery. Do not ship it.

[CRAFT.md](CRAFT.md) — the flagship bar: hook-supremacy gate, self-critique→rewrite loop, concrete Pulitzer demands + slop bans, the throughline.

[THROUGHLINE.md](THROUGHLINE.md) — the running-memoir ledger: live arcs to nod to + tease forward, with the no-crutch guardrail.

[RUBRIC.md](RUBRIC.md)

[LEARNINGS.md](LEARNINGS.md)

[INPUT_TEMPLATE.md](INPUT_TEMPLATE.md)

[SYSTEM_PROMPT.md](SYSTEM_PROMPT.md)

Files in this skill

  • CRAFT.md14.4 KB
  • INPUT_TEMPLATE.md627 B
  • RUBRIC.md20 KB
  • SKILL.md64.4 KB
  • STORY-MODES.md39.2 KB
  • SYSTEM_PROMPT.md1.2 KB
  • THROUGHLINE.md60.2 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.