zpaper-draft

Type to search...

to open search from anywhere

l-convert

Convert a draft article to a blog-compatible MDX file. Use when: (1) User wants to publish a draft article to the blog, (2) User says 'convert to article', 'convert', 'publish article', or 'move to bl...

Convert Draft to Blog Article

Convert a doc site draft article from doc/src/content/docs/articles/ to a blog-compatible MDX file in blog/src/articles/.

Model requirement: This skill performs Japanese translation of English conversation blocks (### Takazudo / ### Claude sections become <ConvTakazudo> / <ConvClaude> with a Japanese translation after <TransSep />). The frontmatter pins model: opus so translation always runs on Opus — do not downgrade. If you find yourself running this skill on a smaller model, stop and re-invoke /l-convert so it runs on Opus.

Arguments

  • --auto: Automatically apply all suggested tags (including new ones) from /l-tag-attach-to-article without asking for confirmation. Still report what tags were applied.

Steps

1. Identify the draft article

Determine which draft to convert:

  • Check git diff --name-only for uncommitted changes in doc/src/content/docs/articles/
  • Check git log --oneline -10 --diff-filter=AM -- doc/src/content/docs/articles/ for recently added or modified articles
  • If the user specified an article name or path, use that
  • If multiple candidates exist or the target is unclear, ask the user which article to convert

2. Read the draft

Read the full content of the target Markdown file from doc/src/content/docs/articles/.

3. Determine the output filename

The output file goes to blog/src/articles/{slug}.mdx.

  • Strip date/time prefixes from draft filenames before using as slug. Draft files often have prefixes like 20260301-1500- — remove the YYYYMMDD-HHMM- portion. For example: 20260301-1500-claude-code-agent-teams-usageclaude-code-agent-teams-usage
  • If the remaining name is suitable as a slug (kebab-case, descriptive), use it
  • Otherwise, derive a slug from the article title (lowercase, hyphens, ASCII only, max 50 chars)
  • If a file with the same slug already exists, ask the user before overwriting

4. Build the frontmatter

The blog MDX requires this frontmatter format:

---
title: "記事のタイトル"
description: "記事の概要説明(1-2文)"
author: Takazudo
tags: []
createdAt: "YYYY-MM-DD"
---
  • title: Use the draft’s title frontmatter, or the first # heading if no frontmatter title exists. If neither exists, ask the user.
  • description: Use the draft’s description frontmatter if available. Otherwise, generate a concise summary (1-2 sentences) based on the article content.
  • author: Always Takazudo
  • tags: Leave as empty array [] for now (tags will be attached via /l-tag-attach-to-article in the next step)
  • createdAt: Today’s date in "YYYY-MM-DD" format

Do not include doc site-specific frontmatter fields (sidebar_position, sidebar_label, pagination_next, pagination_prev).

5. Convert doc site admonitions to MDX components

Convert doc site admonition blocks to the corresponding blog MDX components:

:::note<Note>

<!-- doc site input -->
:::note 注記

Content here.
Multiple lines supported.

:::
<!-- Blog MDX output -->
<Note>

Content here.
Multiple lines supported.

</Note>

:::info<Info>

<!-- doc site input -->
:::info 備考

Content here.

:::
<!-- Blog MDX output -->
<Info>

Content here.

</Info>

Custom titles

If the admonition has a custom title (other than the standard 注記/備考):

:::note カスタムタイトル

Content here.

:::
<Note title="カスタムタイトル">

Content here.

</Note>

The standard titles are:

  • :::note 注記<Note> (no title prop needed, defaults to 注記)
  • :::info 備考<Info> (no title prop needed, defaults to 備考)

Other admonition types

If :::tip, :::warning, :::danger, or :::caution are found (they shouldn’t be per writing rules, but just in case):

  • :::tip<Info>
  • :::warning<Note>
  • :::danger<Note>
  • :::caution<Note>

6. Handle other doc site-specific syntax

  • Internal doc links: Convert doc site relative links ([text](./other-doc.md)) that point to other docs to appropriate form. If the link target is another article, convert to the blog URL format (/articles/slug). If it’s a reference doc, remove the link and keep the text.
  • Import statements: Remove any doc site-specific import statements (e.g., import CategoryNav from ...)
  • doc site components: Remove doc site-specific JSX components (e.g., <CategoryNav />)
  • Image paths: See step 6a below.
  • Fix internal links in the doc draft: See step 6b below.
  • Approximation tildes (~): See step 6c below.

6a. Copy and rewrite image paths

doc site serves static files from doc/public/, so images in drafts use paths like /img/articles/.... The blog (Next.js) serves static files from blog/public/ with basePath: '/pj/zpaper', so images must be both copied and path-rewritten.

For each image reference found in the article (markdown ![alt](/img/...) or JSX <Img src="/img/..." />):

  1. Copy the image file from doc/public/{path} to blog/public/{path}
  • Example: doc/public/img/articles/20260217-foo/bar.pngblog/public/img/articles/20260217-foo/bar.png
  • Create intermediate directories as needed (mkdir -p)
  1. Rewrite the path in the MDX to include the blog basePath prefix /pj/zpaper/
  • Example: /img/articles/20260217-foo/bar.png/pj/zpaper/img/articles/20260217-foo/bar.png

This is necessary because:

  • The blog uses basePath: '/pj/zpaper' in next.config.mjs
  • Raw <img> tags (from markdown images) are NOT automatically prefixed by Next.js — only next/image gets basePath prefixing
  • The blog’s Img component renders a plain <img> tag without basePath handling

If the draft article has no images, skip this step.

The doc draft (doc/src/content/docs/articles/) and the blog output (blog/src/articles/) use different link formats for internal article references. A link that works in the blog may break the doc site build, and vice versa. This step ensures both files have correct links.

Scan all markdown links in the article and identify internal links — links pointing to other articles or pages within the site (not external URLs like https://...).

Fix the doc draft source file (edit in place):

  • Links to other articles must use doc site-relative paths: ./other-article-slug (no /articles/ prefix, no .md extension needed)
  • Blog-style absolute paths like /articles/slug will cause doc site broken link error — convert them to ./slug
  • Verify the link target actually exists in doc/src/content/docs/articles/ by checking for a matching .md file

Fix the blog output:

  • Links to other articles should use the blog URL format: /articles/slug
  • doc site-relative paths like ./other-article-slug should be converted to /articles/other-article-slug
  • Verify the link target actually exists in blog/src/articles/ by checking for a matching .mdx file

If a link target doesn’t exist in either location, warn the user and ask how to handle it (remove the link, keep as-is, or fix the path).

6c. Sanitize approximation tildes (~)

Bare ASCII ~ used as an “approximately” marker (e.g., ~80 LOC, ~1–3s, ~500K) is dangerous in the blog’s MDX rendering. The blog parser treats ~text~ (single tildes) as GFM strikethrough, so when two such tildes appear in the same paragraph or bold span, the text between them gets rendered with a strike-through line.

This often shows up because Claude’s English responses use ~ casually, and a literal Japanese translation preserves it.

Rules:

  • In Japanese paragraphs (after <TransSep />): Replace approximation ~N (where N is a digit) with 約N. This is the most natural reading in Japanese and avoids the markdown ambiguity entirely.

    • ~80 LOC約80 LOC
    • ~1-3秒約1-3秒
    • ~500トークン約500トークン
  • In English paragraphs (inside <ConvClaude> / <ConvTakazudo> before <TransSep />): Keep ~ as-is in most cases — single tilde per paragraph renders fine. But if a paragraph or bold span contains two or more ~N patterns, escape them with \~ to prevent strikethrough pairing.

    • Safe (single tilde): Total: ~200–300 LOC of pure Rust.
    • Broken (two tildes pair as strikethrough): **Rebuild time goes from ~1–3s (Astro) to ~1–10ms (Rust per file).**
    • Fixed: **Rebuild time goes from \~1–3s (Astro) to \~1–10ms (Rust per file).**
  • Inside backticks / code blocks: Leave ~ untouched. Backticks disable markdown parsing, so ~/.claude/ and ~80 inside code are fine.

  • Inside table cells: Single ~ per cell is safe (the | separator breaks pairing). No change needed.

After writing the output, grep for ~[0-9] in the file and audit each occurrence to confirm it’s either inside backticks, inside a table cell, or a single occurrence per paragraph.

6d. Fix clear typos in conversation English

Takazudo’s English turns in conversation drafts are rough chat text typed quickly. They contain a mix of:

  • Intentional rough chat voice — informal grammar, missing articles, unusual phrasing, em-dashes mid-thought, lowercase sentence starts, dropped words. Keep as-is. This is the author’s voice and not an error.
  • Clear typos / errors — misspellings, subject-verb agreement errors, archaic word forms used by mistake, obvious wrong-word errors. Fix these silently.

Apply the same fixes to both the doc draft (in place) and the blog MDX output, so the two sources stay consistent.

Fix examples (do fix):

  • usefullnessusefulness (spelling)
  • paragraph get dimparagraph gets dim (subject-verb agreement)
  • inconsistenceinconsistency (archaic / wrong word form for the intended meaning)
  • recievereceive, seperateseparate, etc. (common misspellings)

Do NOT fix (rough chat voice — leave alone):

  • Missing articles: it's almost same, it's same thing — chat style
  • Lowercase sentence starts after a period: but nested lists are just lists. — chat style
  • Reordered modifiers: the big another topic's start — chat style
  • Trailing tag-question forms: ..., do you? — chat style
  • Dropped helpers / non-standard verb forms: seems helping, Is it like see my drawn picture — chat style
  • Em-dash thinking pauses: zoom out --hum. — chat style
  • Concept→pronoun number agreement quirks: Modular synths... it has many knobs — chat style

Heuristic: Fix only what a copy editor would mark as an unambiguous error. If you have to think for more than a second about whether it’s an error or a stylistic choice, leave it.

Translation impact: Typo fixes in the English source do not require re-translating the matching <TransSep /> block — the Japanese translation should already convey the intended meaning. Only re-translate if the typo materially changed the meaning conveyed in the English (rare).

This step applies only to Takazudo’s turns (<ConvTakazudo> blocks). Claude’s turns (<ConvClaude>) come from the model and don’t need typo fixing.

7. Write the output file

Write the converted MDX to blog/src/articles/{slug}.mdx.

8. Verify the output

After writing, read the output file and verify:

  • Frontmatter has all required fields (title, description, author, tags, createdAt)
  • No doc site-specific syntax remains (:::, doc site imports, doc site components)
  • Admonitions are properly converted to <Note> / <Info> components
  • The markdown structure is intact
  • Tilde audit: run grep -nP "~[0-9]" on the output and confirm each match is either inside backticks, inside a table cell, or a single occurrence per paragraph. Two ~ in the same paragraph or bold span will render as strikethrough — fix per step 6c.

9. Generate thumbnail and OGP image

Generate the kumiko-pattern thumbnail SVG and OGP PNG for the article:

pnpm kumiko-gen {slug}
pnpm svg-to-png {slug}

The root script already includes --color-scheme random --zoom 5, so no extra flags are needed.

This creates:

  • blog/public/thumbnails/{slug}.svg — Thumbnail displayed in article header
  • blog/public/thumbnails/{slug}.png — OGP image for social media (1200x630px)

No frontmatter changes are needed — the blog resolves thumbnails automatically by slug.

10. Tag the article

After successful conversion, run the tag attachment workflow:

  • Use /l-tag-attach-to-article to suggest and attach tags
  • Use /l-tag-update-list if new tags are needed

If --auto was passed: Automatically apply all suggested tags (including new ones) without asking for confirmation. Still report what tags were applied.

11. Report

Tell the user:

  • The output file path
  • A summary of conversions performed (number of admonitions converted, etc.)
  • Remind them to review the article and commit when ready

Available Blog MDX Components

For reference, these are the custom MDX components available in the blog:

ComponentPurposeProps
<Note>Supplementary note (注記)title?: string (default: “注記”)
<Info>Additional info/aside (備考)title?: string (default: “備考”)
<InfoBox>Highlighted info box(children only)
<Column>Bordered column block(children only)
<Outro>End-of-article section(children only)
<Youtube>YouTube embed(see component)
<Img>Image with caption(see component)
<ExImg>Extended image(see component)
<ImgsGrid>Image grid layout(see component)
<FlowRoot>Float clearing container(children only)
<LayoutDivide>Multi-column layout(children only)
<LayoutDivideItem>Column item(children only)