Prepare Post
Prepare chan.dev posts for publication.
This skill has two operating contexts, not multiple modes:
- Single post — full editorial workflow
- Batch — metadata-only workflow
The skill should infer which context to use from the input:
- one post path → single-post workflow
- many post paths or a filter request → batch workflow
When to use
- A post has
datebut nopublishDateand is ready to go live - A new post needs metadata before publishing
- A seed post has grown into something publishable
- Many posts need descriptions, tags, or metadata cleanup
- You want to audit existing descriptions and tags for quality
Inputs
- Either:
- one post file in
src/content/posts/ - multiple post files in
src/content/posts/ - a natural-language filter like:
posts missing descriptions,all unpublished posts,all posts tagged react without descriptions
- one post file in
Site conventions
Posts live in src/content/posts/.
Two date fields have distinct semantics:
publishDate— published to feeds, sitemap, listingsdate— tracks when the note was written, not syndicated
When promoting a date-only post, keep both fields.
Frontmatter template
---
title: Post Title
date: 2026-03-27 # when written (keep if exists)
publishDate: 2026-03-27 # when published
description: "150 chars max. Extracted from the post, not about the post."
tags: [topic, subtopic]
references:
- https://example.com
cover: ./post-slug/image.png
coverAlt: Alt text
---
Execution profile
Single post
Use the full editorial workflow:
- assess readiness
- interview to harden if appropriate
- generate description
- apply tags
- validate frontmatter
- ask before setting
publishDate
Batch
Use the metadata-only workflow:
- do not interview
- do not rewrite content
- generate or audit descriptions
- apply or normalize tags
- summarize uncertain cases in a review table
- never set
publishDateunless explicitly asked
Process
Step 1: Read and assess
Read the full post or posts.
For a single post, determine:
- Readiness: seed (< 5 sentences), draft (incomplete), or publication-ready?
- Voice: does it sound like Chan? (Reference
chan-dev-writingif uncertain.) - Metadata state: what exists, what is missing, what looks wrong?
If the post is a seed or clearly incomplete, say so and ask whether to proceed.
For a batch, identify only:
- which files match the request
- which files are substantial enough to deserve descriptions/tags
- which files are found notes or empty stubs and should be skipped
Step 2: Interview to harden (single post only)
Only do this for a single post.
Ask 3-5 questions using the questionnaire tool.
For personal essays:
- What's the one thing you want someone to walk away with?
- Is there a story or moment that's missing?
- Does the ending land?
For technical posts:
- What search query should land someone here?
- Is there a step or concept you haven't addressed?
- Would you link to this from another post? Which one?
For promoted seeds:
- What made you come back to this?
- Is this its own post or a section of something bigger?
- What's the minimum version worth publishing?
If the interview reveals content changes, propose them.
Do not rewrite without approval.
Reference make-it-personal if the draft needs deeper personal work.
Step 3: Generate description
Classify search intent
Searchable — Someone would Google a problem and this post answers it.
- Signal: code blocks, step-by-step structure, tool/API names, "how to" framing
Shareable — Someone encounters this through a link or social share.
- Signal: first-person narrative, no code, aphoristic title, confessional tone
Extract the description
For searchable posts:
- Identify the primary search query
- Lead with the topic keyword or problem statement
- Include specific terms: API names, tool names, exact problem
- Close with what the reader gets
Pattern: [Topic/problem]. [What the post covers]. [What the reader gets].
For shareable posts:
- Find the most compelling line from the post itself
- Pull it verbatim or near-verbatim
- Do not genericize
- Do not add moral framing the author didn't write
Pattern: Pull the hook. Use the author's words.
Validate
- Length: ~150-155 characters for Google snippets. Shorter is fine.
- Accuracy: Must match what the post actually says.
- Self-contained: Should make sense without the title.
Anti-patterns
Reject descriptions that:
- open with imperative verbs like
Discover,Explore,Learn,Master,Unlock,Embrace,Dive into - moralize generic lessons the author didn't write
- replace a specific story with a universal platitude
- inflate the importance of a straightforward setup or note
- add framing the author already stated more directly in the post
The test:
Could this description have been written by someone who only read the title?
If yes, it's bad.
Review boundary
- For a single post being prepared for publication, present the description for operator review.
- For a batch, apply descriptions directly to substantial posts. Surface uncertain cases in the summary table instead of asking one-by-one.
Step 4: Apply tags
Query the live vocabulary from the site's Astro-backed tags endpoint.
Canonical source:
/api/tags.json
This endpoint is backed by Astro content collections and already sees both supported frontmatter styles. Do not regex-parse frontmatter for vocabulary discovery unless the endpoint is unavailable.
Use:
all.tagsfor the complete normalized vocabulary with countspublished.tagswhen you want the public vocabulary onlyunpublished.tagswhen comparing unpublished drafts against private/internal tag usageentriespayloads when you need examples of how a tag is actually used in the corpus
Selection guidance:
- prefer tags with multiple existing examples over one-off curiosities
- inspect representative entries before applying sparse tags like
seed,from:pi, or niche topic labels - treat counts as guidance, not law; choose for fit, not popularity
Fallback behavior if the endpoint cannot be queried:
- use Astro collection-backed project helpers if available
- otherwise stop and report that canonical tag vocabulary could not be loaded
- do not fall back to brittle regex scraping as the default path
Rules:
- Apply 1-3 tags from the existing vocabulary
- Prefer specific over general (
reactoverweb) - Use
lifeas the base tag for personal essays; add a second for the angle (family,career,faith) - Content-type tags (
reference,tutorial,seed) go alongside topic tags - Do not invent new tags unless 3+ posts would use them
- Normalize tags to the site's current standard when editing (
lowercase, bracket format preferred when touching frontmatter)
Tags are low-risk and reversible. Apply without asking.
Step 5: Validate frontmatter
Check for:
✓ title
✓ description
✓ tags
○ publishDate (single-post publication flow only)
○ cover / coverAlt
○ references
Also flag:
- quoted or inconsistent tag formatting
- empty
descriptionstrings - multiline
descriptionaccidents - cited links in the body that are missing from
referenceswhen that field is already in use for similar posts
Step 6: Set publishDate (single post only, explicit)
Only set publishDate when explicitly requested or when working interactively on a single post and the operator confirms publication.
Ask:
- publish now?
- or schedule for a specific date?
For batches, never set publishDate unless explicitly requested.
Step 7: Summary
For a single post, present:
- content changes proposed or made
- description added/updated
- tags applied
publishDateset or deferred- warnings (missing cover, uncited references, etc.)
For a batch, present a table:
- file
- action taken (
description added,description rewritten,tags added,tags normalized,skipped) - why skipped (found note, empty stub, uncertain)
- any cases needing human review
Audit behavior
When the request is clearly audit-oriented, read existing metadata and flag:
Description issues
- content mismatch
- AI-isms (
Discover,Explore,Embrace,Unlock) - generic self-help language
- too long (>160 chars)
- empty or broken values
- typos
Tag issues
- missing tags on substantial posts
- singleton tags that should be consolidated
- quoted, capitalized, or inconsistent formatting
- tags that are too vague compared to the site's current vocabulary
Decision boundaries
| Decision | Who | Why |
|---|---|---|
| Content changes | Operator | Taste-sensitive |
| Description on a single post headed to publication | Operator reviews | Publication-sensitive |
| Description in batch enrichment | Agent | Low-risk on unpublished or maintenance work |
| Tags | Agent | Low-risk, reversible |
publishDate |
Operator | Publication decision |
Composition
References:
chan-dev-writing— voice referencemake-it-personal— use when the interview reveals the post needs deeper personal work
Typical calls:
prepare-post for src/content/posts/sticky.mdprepare-post for all unpublished posts missing descriptionsprepare-post for posts tagged react without tagsprepare-post for all posts with AI-ish descriptionsprepare-post for uncommitted posts