Documentation system
SkillDocs & knowledgeThe clice documentation system — generated feature/config pages, the en↔zh translation contract, and the pixi commands driving them. Read BEFORE editing anything under docs/.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Documentation system skill
What this skill tells your AI
The instructions your AI receives, as published by clice-io/clice in .claude/skills/docs/SKILL.md and read by ahel’s review.
Layout and sources of truth
docs/en/— English pages. Handwritten pages (design/, guide/, dev/, index.md) are edited directly; feature pages (features/*.md) contain GENERATED regions rendered from snapshot fixtures, and guide/configuration.md is rendered from the config schema. Never edit inside a<!-- BEGIN GENERATED ... -->region — edit the fixture doc header (see the write-tests skill) or the config annotations instead.docs/zh/— Chinese pages, equally real and equally hand-edited (by a person or a model). Each zh page must stay segment-isomorphic to its en counterpart: same sequence of markdown blocks, translated text in the translatable blocks, code blocks and HTML comments byte-identical.check,reportandrecordnever write these files;translate <page>overwrites the named zh page, andreviewrewrites the zh pages it is given — every zh page when given none.docs/meta/translations/— one JSON per page pair: an ordered list of{kind, en-hash, zh-hash}pairs, each attesting "these two segments were last reviewed as translations of each other". Maintained exclusively byrecord; never edit by hand.- Each tree has its own hand-maintained
sidebar.yaml. docs/public/clice-config.schema.json— committed output ofclice inspect --config-schema; CI checks freshness.
Commands (pixi)
| command | what it does |
|---|---|
pixi run check-feature-docs | feature pages match their fixtures (CI) |
pixi run update-feature-docs | rewrite feature GENERATED regions |
pixi run check-config-docs | configuration page matches the schema (CI) |
pixi run update-config-docs | rewrite the configuration page |
pixi run check-doc-translations | hard gate: zh isomorphic to en, all pairs attested |
pixi run report-doc-translations | translator worklist: drifted segments with texts |
pixi run record-doc-translations | re-attest hash pairs after deliberate edits |
pixi run review-doc-translations | model review of zh pages, segment by segment |
Translation contract (tools/docs/translate.ts)
Pages split into segments: headings, paragraphs, blockquotes, list items,
table rows, and index.md's YAML frontmatter are translatable; everything
else (code blocks, HTML comments including GENERATED markers) is verbatim
and must be byte-identical across the two trees, as must any fenced code
or HTML comment nested inside a translatable segment (a snap example
under a generated capability's paragraph). Segment shapes must match too: heading depth,
ordered vs. bulleted list, task-list state, table column count and
alignment, and the mapping/sequence skeleton of index.md's frontmatter.
A table row and a later heading that share their text in en (a
capability's status row and its section) must share it in zh — check
fails on a pair named two ways. The inline literals of a segment — code
spans, link and image targets (in order), issue references, frontmatter
values other than its copy (layout, theme, icon, link, src, ...) — must
be identical on both sides. No text is stored twice — the mapping holds
hashes only. Old wording of a drifted segment comes from git history of
the markdown page.
Workflow for any edit touching translated pages:
- Edit the en page (or zh — the contract is symmetric: polishing one side requires re-reviewing the other).
pixi run report-doc-translations— lists every broken pair with the current en and zh texts side by side.- Update the counterpart page so both sides correspond again.
pixi run formatfirst, thenpixi run record-doc-translations— the formatter canonicalizes markdown (table padding, emphasis style, CJK spacing) and changes segment hashes, so recording before it means re-recording after. Record rewrites the mapping; the diff of the JSON shows exactly which pairs were re-attested. Never run record without having reviewed what report showed: record blesses whatever is on disk.- Commit markdown + mapping together;
checkmust be green.
This applies to generated regions too: after update-feature-docs changes
an en feature page, the zh page must receive the translated equivalent in
the same PR — batched at the end of the branch, see below.
Machine drafting: DEEPSEEK_API_KEY=... node tools/docs/translate.ts translate [page...] produces isomorphic zh drafts via the DeepSeek API
(no args = only pages missing a zh counterpart; explicit pages overwrite,
feeding the current zh text to the model as terminology reference).
Fenced code inside segments is masked out of the round trip and restored
byte-for-byte; inline code, link targets, issue references and
frontmatter control values must come back unchanged. A segment the model
cannot render validly — or a row/heading pair it names two ways — is
left in English and the run exits non-zero naming the page — rerun
translate on it after review. The key comes from the environment and
is never stored. Drafts still go through review and record.
Chinese wording: what is translated and what stays English
The zh tree reads as Chinese technical writing, not as glossed English. The reader is a C++ developer who searches the web in English, so the rule is: translate the prose, keep the names people search for.
Translate:
- Page, section and capability titles, table headers and cells, list
items, descriptions. Feature names have fixed Chinese names — use the
ones the overview page uses (代码补全, 悬停, 签名帮助, 代码导航,
文档链接, 语义 Token, 内联提示, 折叠范围, 文档符号, 格式化, 诊断,
代码操作; Lint stays Lint). LSP request names stay as code when
quoted (
textDocument/hover), the feature is named in Chinese. - C++ concepts that have an established Chinese term: 结构化绑定, 范围 for 循环, 概念, 模板特化, 显式实例化, 折叠表达式, 参数包, 注入类名. On the first use in a page, give the English in full-width parentheses when the English is what one would search for: 结构化绑定 (structured bindings), 最令人烦恼的解析(most vexing parse).
- Status words: 支持 / 部分支持 / 不支持.
Keep English (never transliterate):
- Product and tool names: VS Code, Neovim, Zed, CMake, Bazel, clang, clang-format, clangd, GCC, MSVC, LLVM.
- Acronyms: LSP, AST, PCH, PCM, CDB, TU, ADL, CTAD, DAG, ABI, URI, C++23.
- Anything in code font: identifiers, keywords, file paths, config keys
and TOML sections, command lines, diagnostics text quoted from the
compiler. Code font follows the English exactly: a span the English
sets in backticks stays in backticks, and the Chinese adds none of its
own —
checkcompares the inline literals of every segment pair. - Terms that are commonly used untranslated by Chinese C++ developers
and whose translations are less recognizable: Lambda, Token, Concept
when naming the language feature (概念 in prose is fine),
this, Preamble, Overload set. When in doubt, keep the English term and add a short Chinese gloss rather than invent a translation.
Style: full-width punctuation inside Chinese sentences, a space between CJK and Latin text (prettier enforces it), no machine-translation calques ("这个" for "the", passive-voice chains), sentences that say what the English says rather than word for word.
Reviewing existing Chinese pages: pixi run review-doc-translations [page...] (default: every page) feeds each translatable segment with
its current Chinese to a model and writes the corrected Chinese back,
one chunk of segments per call (a paired row and heading always in the
same chunk), code blocks masked out — the model never sees a code block,
and a reply that breaks a segment's shape, alters an inline literal, or
names a row and its heading differently keeps the current text. The
default backend is the codex CLI with every tool switched off, so the
contributor-written text it reads can reach neither the host filesystem
nor the network (--jobs=N parallel calls, --effort=LEVEL);
--backend=deepseek uses the API. Review the diff, then format and
record. Prefer this over handing a model whole pages: the code blocks
would only burn its context.
Syncing docs at the end of a branch
Generated regions and translations are synced once per branch, right
before the pre-push checks of the pr skill — not after every fixture or
page edit, and not in the main conversation: delegate it to a subagent so
the report output and page texts never enter the main context. Give the
subagent this skill and git diff --name-only origin/main...HEAD; its
brief is:
- If snap fixtures with doc headers or config annotations changed:
pixi run update-feature-docsandpixi run update-config-docsrewrite the en GENERATED regions. pixi run report-doc-translationslists every broken pair with both texts. Translate each new or drifted en segment into the zh page, keeping the skeleton (same block kind, list marker, heading depth, nested code byte-identical) and the terminology of the surrounding page; delete zh segments whose en segment is gone. For whole new pages, or dozens of drifted pages, thetranslatemode below drafts them when a DeepSeek key is available — otherwise translate by hand.pixi run format, thenpixi run record-doc-translations, thenpixi run check-doc-translations,check-feature-docsandcheck-config-docs— all green.- Report back: pages touched, how many segments were translated, and anything deliberately left as is.
docs/ contains no changelog content at all — neither per-page
"Changelog" sections nor standalone changelog pages. Both were removed
deliberately (2026-09) as redundant maintenance burden; do not reintroduce
them. Feature history lives in git/PRs; LLVM upgrade notes live in the
upgrade-llvm skill's llvm-changelog.md. For future deliberately
untranslated pages, the tool has an UNTRANSLATED_PREFIXES hook
(currently empty): listed pages need no zh counterpart and no mapping.
What belongs in a "Known Limitations" section
Design-level, user-visible trade-offs that are stable on a months timescale, written in behavior terms — they answer the reader's "why does it work this way". Bugs never go there: they live in the internal bug inventory and simply disappear when fixed; putting them in docs creates staleness debt. Feature coverage gaps are already expressed by the generated status tables. The flow is one-way: an internal item graduates into a doc limitation only once it is decided to be design (or long-term deferral), and a doc limitation is removed only when the design changes. Never reference internal IDs, file paths, or timelines in docs.
The contract went live 2026-09-02: all pages machine-drafted
(deepseek-v4-pro), recorded, check green, and the gate wired into the
CI docs check. The legacy hand-written zh tree it replaced survives in
git history.
Signals
- GitHub stars
- 1k
- Forks
- 81
- Last commit
- Sep 2026
- Hacker News mentions
- 20
Advanced
- Catalog kind
- skill
- Gateway key
docs-clice-io- Source
- github.com/clice-io/clice