/CLAUDE.md
CLAUDE.md at /CLAUDE.md
Path: CLAUDE.md
Zudo Slack Wisdom
Documentation site built with zudo-doc — a zfb-based documentation framework with MDX, Tailwind CSS v4, and Preact islands. This project is intentionally minimal: one config file (zfb.config.ts) plus markdown content — layout, chrome, and islands all ship from @takazudo/zudo-doc in node_modules.
Tech Stack
zfb — documentation build framework
MDX — content format, authored under
src/content/Tailwind CSS v4 — compiled by zfb's embedded Tailwind engine (no
@tailwindcss/viteplugin, notailwindcssdependency);src/importsstyles/ global. css tailwindcss/preflight+tailwindcss/utilitiesand zfb's internal resolver serves bothPreact — for interactive islands only (with compat mode for React API)
zfb semantic highlighting — native build-time fenced-code rendering plus lazy
@takazudo/zfb-md-wasmfor HtmlPreview; both emithi-*classes resolved through--zd-syntax-*design tokens@takazudo/zudo-doc — the package that owns everything: layout, chrome, islands, default
@themedesign tokens, and (viapackageOwnedRoutes, on by default) the doc routes themselves
Commands
pnpm dev— runs the zfb dev server (port 4321) and the doc-history API server (port 4322) concurrently viarun-p(pnpm dev:zfb/pnpm dev:historyindividually)pnpm dev:network— same, but zfb binds--host 0.0.0.0for LAN access (pnpm dev:zfb:networkindividually); the doc-history server stays loopback-only and LAN clients reach it through zfb's/dev proxydoc- history/ * Trusted networks only: this also serves your git doc-history — including UNPUBLISHED local commits — to anyone on the LAN via the
/proxydoc- history/ * run-pswallows trailing args, so other zfb flags don't forward throughpnpm dev— pass them directly instead:pnpm run dev:zfb -- <flags>pnpm build— static HTML export todist/pnpm check— TypeScript type checkingpnpm preview— serve the builtdist/pnpm b4push— full local quality gate before pushing (seescripts/): mdx format check, template drift check, pin parity check, wrangler pin check,run- b4push. sh pnpm check,pnpm build, HTML validation, link checkpnpm format:md/pnpm format:md:check— format (or check formatting of).md/.mdxfiles undersrc/content/pnpm check:pin-parity— verify the@takazudo/zfb*package group stays on one exact version (scripts/)check- pin- parity. mjs pnpm check:wrangler-pin— verify the installedwranglermatches the version the installed@takazudo/zfbbinary expects (scripts/)check- wrangler- pin. mjs pnpm check:template-drift— diff host files (pages/,src/, thestyles/ global. css claudeSkillsfiles) against the matchingcreate-zudo-docrelease, fetched on demand and cached undernode_modules/.cache/(scripts/); genuine intentional divergences go incheck- template- drift. sh .template-drift-allowlistpnpm check:html— validate built HTML (.htmlvalidate.jsonrules) viapnpm dlx html-validatepnpm check:links— broken-link check on builtdist/+ absolute-link check on MDX source (scripts/); known exceptions go incheck- links. js .check-links-allowlistpnpm setup:doc-skill— generate thezudo-slack-wisdomskill (see "Doc Skill" below) + symlink it into the user-scope skills directory
Key Directories
zfb.config.ts # THE one config file — zudoDoc({ ...only fields you chose })
pages/
├── index.tsx # 1-line re-export of the package home route
└── docs/[[...slug]].tsx # self-contained doc-route stub (required for `pnpm dev`)
[locale]/docs/[[...slug]].tsx # same, for non-default locales
src/
├── chrome-bindings.tsx # optional typed primary chrome / named header / MDX bindings
├── content/
│ └── docs/ # MDX content (this project's showcase docs)
│ └── docs-ja/ # Japanese MDX content (mirrors docs/)
└── styles/
└── global.css # @import chain + a token-override slot — that's it Everything else — layout, header, sidebar, footer, doc chrome, islands, and the default design tokens — lives in node_modules/@takazudo/zudo-doc. For supported markup replacement, create src/ with defineChromeBindings, set chromeBindingsModule, and use the primary Header / Footer / Sidebar / Toc / Breadcrumb / DocPager slots or the named headerRightComponents registry. The generated default, locale, and doc-history route shapes already consume the same binding object; do not fork a route stub for presentational customization. npx zudo-doc eject <component> only copies source: heed its primary, nested-chrome, or content-layer remediation before expecting the copy to render. Settings you didn't set explicitly in zfb.config.ts use the package's documented defaults — hover zudoDoc's ZudoDocConfig argument in your editor to see every field and its @default.
Content Conventions
Frontmatter
Schema is the zudo-doc package default (buildDocsSchema, shipped by @takazudo/zudo-doc, validated by zfb check; override via buildDocsSchema in zfb.config.ts if ever needed). Unknown keys are passed through, not rejected.
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Page title, rendered as the page h1 |
description | string | No | Subtitle / meta description |
category | string | No | Category override (defaults to the containing directory) |
sidebar_position | number | No | Sort order within category (lower = higher). Always set this for predictable ordering |
sidebar_label | string | No | Custom text for sidebar display (overrides title) |
tags | string[] | No | Cross-category grouping tags |
search_exclude | boolean | No | Exclude from search results |
pagination_next / pagination_prev | string | null | No | Override next/prev page link (null to hide) |
draft | boolean | No | Exclude from build entirely |
unlisted | boolean | No | Built but noindexed, hidden from sidebar/nav |
hide_sidebar | boolean | No | Hide the left sidebar, center content |
hide_toc | boolean | No | Hide the right-side table of contents |
wide | boolean | No | Widen the content column |
doc_history | boolean | No | Per-page override for the docHistory feature |
standalone | boolean | No | Hidden from sidebar nav but still indexed |
slug | string | No | Custom URL slug override |
generated | boolean | No | Build-time generated content (skips the bilingual-translation requirement below) |
category_no_page | boolean | No | Category has no landing page (just groups items) |
category_sort_order | "asc" | "desc" | No | Sort order for pages within the category |
File Names & Links
Kebab-case file names:
my-article.mdx, notmyArticle.mdxormy_article.mdx.Relative links between docs: use the
.mdxextension so the remark plugin can resolve and validate them at build time:[Link text](./sibling-page.mdx) [Link text](../other-category/page.mdx) [Link text](../other-category/page.mdx#anchor)Absolute hrefs that bypass the base path, and links to files that don't exist, are both caught by
pnpm check:links.
Mermaid Diagrams
Mermaid is enabled (bundled by @takazudo/zudo-doc, no extra dependency needed). Use fenced code blocks:
```mermaid
graph TB
A --> B
```Admonitions
Available in all MDX files without imports, via directive syntax: :::note, :::tip, :::info, :::warning, :::danger, :::caution, :::details. Each accepts an optional bracketed title: :::note[Custom Title].
Docusaurus-style {title="..."} is NOT supported. MDX parses the braces as a JS expression, so it either fails the build with ReferenceError: title is not defined or is silently ignored. Always use the bracketed form.
Headings
Do NOT use h1 (#) in doc content — the page title from frontmatter is rendered as h1. Start content headings from h2 (##).
Built-in MDX components
@takazudo/zudo-doc ships a few globally-available MDX components — usable in any .mdx file with no import. The seeded getting- already uses one:
<CategoryNav category="..." />— a card-grid list of the pages in a docs category (this is the one seeded intogetting-).started/ index. mdx <CategoryTreeNav category="..." />— the same listing as a compact nested tree, better for deeper hierarchies.<SiteTreeNavDemo />— a full-site documentation tree (the MDX-available wrapper of theSiteTreeNavisland).
Admonitions (above), tabbed content (<Tabs> / <TabItem>, <CodeGroup>), and block math (<MathBlock>) work the same way — no import. Full reference: https://zudo-doc.takazudomodular.com/docs/components/
i18n & Bilingual Rule
English (default):
/— content indocs/ . . . src/content/ docs/ Japanese:
/— content inja/ docs/ . . . src/content/ docs- ja/ Japanese docs mirror the English directory structure (same relative path under
docs-ja/)Both
pages/docs/[[...slug]].tsxandpages/[locale]/docs/[[...slug]].tsxare self-contained doc-route stubs shipped by the generator — required sopnpm devdoesn't 404 on doc pages (a zfb dev-mode limitation on package-injected dynamic routes). Don't delete them.
Bilingual rule: every content PR that adds or changes a doc page carries both the English (docs/) and Japanese (docs-ja/) versions of that page. Code blocks, Mermaid diagrams, and any other non-prose content must be byte-identical between the two languages — only the surrounding prose is translated. If a Japanese version doesn't exist yet, create it in the same PR.
Exception: pages with generated: true in frontmatter (the claude/, claude-md/, claude-skills/ auto-generated categories — see "Doc Skill" below and claudeResources in "Enabled Features") do not require a Japanese translation; they're regenerated on every build and are EN-only by design.
Content Categories
Top-level directories under src/, mapped to header nav entries via categoryMatch in the headerNav list in zfb.config.ts. Every category has an index.mdx:
getting-started/— Overview, what this site coversworker-backend/— Cloudflare Worker backend patterns (bot tokens / signing secrets stay server-side)messaging/— Slack messaging APIsevents/— Slack Events APIlists/— Slack Lists API (the deep, research-backed section per the epic)data-surfaces/— Data surface patterns
Auto-generated directories (no header nav entry, managed by the claudeResources build integration — see "Doc Skill" below):
claude/,claude-md/,claude-skills/— regenerated on everypnpm build; do not hand-edit
Content Creation Workflow
Adding a New Article
Create the English
.mdxfile in the appropriate category undersrc/content/ docs/ Add frontmatter with at least
titleandsidebar_positionWrite content starting with
## h2headings (not# h1)Create the matching Japanese file under
src/at the same relative pathcontent/ docs- ja/ Keep code blocks and Mermaid diagrams identical between languages — only translate prose
Run
pnpm format:mdto format the MDX filesRun
pnpm b4push(or at leastpnpm build+pnpm check:links) to verify the site builds and links resolve
Adding a New Category
Create the directory under
src/(kebab-case) and the mirrored directory undercontent/ docs/ src/content/ docs- ja/ Create
index.mdxin both withtitle,description, andsidebar_positionAdd a
headerNaventry inzfb.config.tswithcategoryMatchpointing at the directory nameRun
pnpm b4pushto verify
Doc Skill
pnpm setup:doc-skill (scripts/) generates the zudo-slack-wisdom skill from this site's built docs and symlinks it into the user-scope skills directory (~/.claude/skills/ and/or ~/.codex/skills/). The generated . / . directories are gitignored — do not track or hand-edit them; re-run pnpm setup:doc-skill to refresh. The src/ pages consumed by that skill are written by the claudeResources build integration on every pnpm build; edit the site's .claude/ sources (CLAUDE.md, skills, commands, agents), not those generated pages, to change their content.
Enabled Features
search — Full-text search via Pagefind
i18n — English + Japanese bilingual content (see above)
claudeResources — Auto-generated docs for Claude Code resources (
.claude/→src/)content/ docs/ claude* claudeSkills — Seeds the
.helper skills (version-bump, design-system, translate)claude/ skills/ zudo- doc- * skillSymlinker — Powers
pnpm setup:doc-skill(see "Doc Skill" above)sidebarResizer — Draggable sidebar width
sidebarToggle — Show/hide desktop sidebar
tocToggle — Show/hide the table of contents
imageEnlarge — Click-to-enlarge images
dynamicPageTransition — Animated page transitions
docHistory — Document edit history
llmsTxt — Generates llms.txt for LLM consumption
cjkFriendly — CJK-aware typography (line breaking, spacing) for the Japanese content
Hosting & CI/CD
Hosting: Cloudflare Workers static assets (adapter:
@takazudo/zfb-adapter-cloudflare), served athttps:/ / zudo- slack- wisdom. takazudomodular. com Deploy config, PR preview checks, and the production deploy workflow are set up by a separate sub-issue (deploy config:
wrangler.toml,main-deploy.yml,pr-checks.yml) — not part of this quality-gates taskSecrets (GitHub Actions):
CLOUDFLARE_API_TOKEN,CLOUDFLARE_ACCOUNT_ID,IFTTT_PROD_NOTIFY(optional — production-deploy notification)