@danxbot/docs

中文文档
0.1.72发布于 2026/11/06MITTypeScriptES Module近 30 天下载 7676

Repo-agnostic docs package (DX-3336/DX-3337): a typed, versioned node-file format, a loader that builds an in-memory graph from a docs root, and a fail-loud check CLI.

原始使用文档
文档目录16 节
  1. What the docs are for (schema v3)
  2. Node file format
  3. Node types
  4. part_of — the one navigation relation
  5. see_also — the one cross-link
  6. Page sections
  7. Optional fields
  8. Only one schema version is read
  9. Install
  10. Usage
  11. For agents: tree → search → show (DX-3581, PLN-12 architect…
  12. For agents: promoting a plan into docs (DX-3674)
  13. Demo (DX-3369)
  14. The docs app ( serve / build )
  15. Check rules
  16. Tests

@danxbot/docs

Repo-agnostic docs package for the PLN-12 documentation system. Nothing in this package is danxbot-specific (R-1): any repo can adopt it and store its documentation as typed node files, one file per node.

What the docs are for (schema v3)

Docs explain what a system does and why, in words a non-engineer can follow: its parts, the real things people ask about within them, how things happen, the rules and decisions behind them, and how to run things locally. They then point engineers at where to look. They never map individual classes, API routes, schemas or code contracts — that couples the docs to the code, guarantees drift, and repeats what the code already says (PLN-12 R-11).

A node is a substantial topic someone would look up — the system, a major part of it, or a real part of that part (an app, a component, a domain idea) — with a full page (PLN-12 R-13). A rule, a decision, a caveat, a sequence of steps or a set of states is never its own node: it is a section of the page it belongs to. A node that would hold only one sentence belongs as a bullet or a section inside its parent's page instead of a node of its own — check enforces a fifty-word floor on a System/Area/Topic body precisely so a docs tree can't quietly fill up with these thin, single-sentence nodes again.

Node file format

A node file is markdown with YAML frontmatter:

---
id: area.issues
type: Area
title: Issue cards
summary: Issue cards track work as it moves from an idea to finished and merged.
schema_version: 3
part_of: system.danxbot
look_in: [src/issues]
color: iris
rules:
  - Status is always derived from lifecycle timestamps, never written directly.
---

Issue cards are the unit of work danxbot hands to its agents...

Required fields: id (stable, kebab/dot form, e.g. area.issues or topic.ready-at), type, title, summary (capped at SUMMARY_MAX_LENGTH, 200 characters), schema_version (must be exactly SCHEMA_VERSION_MAX, currently 3), and part_of (a single parent node id — required on every type except System, and forbidden on System, the one root of the tree).

Node types

Each type has a plain-language label and a one-line explanation, exported as NODE_TYPE_INFO so every view shows those words instead of a bare type name.

TypeShown asAnswers
SystemThe systemWhat this system is, who it is for, and what it does for them
AreaPart of the systemA major part of the system, and what it is responsible for
TopicTopicA real part of an area people ask about — an app, a component or a domain idea — explained in full
GuideHow toStep-by-step instructions for a task
PathLearning pathA reading order through the docs for one kind of reader

Concept, Flow, Lifecycle and Decision are gone as node types — see "Page sections" below for where their content now lives.

part_of — the one navigation relation

part_of is the only relation that shapes the tree every view lays out. It is a single required scalar (never a list), so "exactly one parent" is the shape itself, not a rule that has to count: a docs root has exactly one System (the root, with no part_of), and every other node has exactly one part_of parent, with no cycles. Which type may be part-of which is fixed (PART_OF_TARGET_TYPES):

A …may be part_of a …
AreaSystem only
Topican Area, or another Topic
Guidea System, an Area, or a Topic
PathSystem only

A Path is never anyone's part_of parent.

see_also is a plain list of other node ids, rendered as inline "See also" text links on the page — never a ring node, never a typed relation. It replaces v2's uses, leads-to, explained-by and step-of.

Page sections

A page's structured content is data, not free markdown, so the app can render each section with the right component (a sequence diagram, a state diagram, ...). Every section below is optional, and (other than Path, whose only content is its steps[]) any of System/Area/Topic/Guide may carry any of them:

FieldShapeRenders as
why_it_mattersa plain stringa short callout
how_it_works{actor, action, target?, notes?}[]a sequence diagram
states{subject, states: {id, label?}[], transitions: {from, to, trigger?, guard?}[]}a state diagram — every transitions[].from/.to must name a declared states[].id
rulesa non-empty string lista rules list
decisions{choice, why, rejected?, trade_off?}[]a "why it's built this way" list
watch_out_fora non-empty string lista caveats list

Optional fields

see_also[] (node ids), look_in[] (engineer pointers at area level: a directory, package or service name — a source file such as src/orders/service.ts, or a file-and-symbol pointer such as src/orders.ts#placeOrder, is refused), provenance ({plans?, cards?, commits?}), audience[] (developer | operator | integrator | agent), icon (an @danxbot/ui icon name), color (a key into @danxbot/ui's palette — PALETTE_KEYS: iris, aqua, mint, amber, rose, azure, slate).

Type-specific structured fields: System nodes may declare value_props[] ({icon, title, summary, color?}) — its own selling points, separate from its Areas; Path nodes require steps[] ({node, note?}, node referencing another node's id) and carry no page sections at all. Every other type carries only the common fields above plus the page sections table.

The full schema is defined once, in code, at src/schema.ts — that is the single source of truth for the validator, the loader and any later consumer (search, the docs app).

Only one schema version is read

There is no reader for older versions and no automatic migration. A file whose schema_version is not exactly the current one is refused by check with a message saying so — a v2 file (with Concept, Flow, Lifecycle or Decision nodes, or a relations[] list) and a v1 file (with Component, Contract, Invariant or Domain nodes, code anchors or verified_at) must both be rewritten as a v3 node (CLAUDE.md Core Principle 1 — fail loud, no legacy reader, no version-conditional logic).

Install

npm install @danxbot/docs

Usage

import { loadDocsGraph, loadDocsRoot, runChecks } from "@danxbot/docs";

// Fail-loud: throws DocsValidationError if anything is wrong.
const graph = loadDocsGraph("./docs");

// Or collect every problem yourself (this is what the CLI does):
const loadResult = loadDocsRoot("./docs");
const problems = runChecks(loadResult);
npx tsx src/cli.ts check ./docs                        # dev
danxbot-docs check ./docs                               # after `npm run build`
danxbot-docs search ./docs "how does X work" [--limit N]  # compact YAML, for agents
danxbot-docs tree ./docs [--root <id>] [--depth N]      # compact YAML of the part-of hierarchy, for agents
danxbot-docs show ./docs <id>                           # one node's full content, for agents
danxbot-docs serve ./docs [--port N]                    # the docs app, live (default port 4300)
danxbot-docs build ./docs ./out                         # the docs app, as a static site
danxbot-docs demo [--port N]                            # serves the bundled example project — see below
danxbot-docs promotion-guide                            # the generic "draft a changeset from a plan" protocol, for agents

For agents: tree → search → show (DX-3581, PLN-12 architecture §6)

The short instruction an agent is pointed at ships as AGENTS.md; this section is the longer explanation.

An agent gains context on a docs root in three steps, never by reading every file:

  1. tree to orient. danxbot-docs tree ./docs prints the whole part_of hierarchy at depth 2 (the System and its Areas and Topics) as compact YAML: id, type, title, summary, file and a real children count per node — enough to see the shape of the system and pick a branch, without reading any page body. --root <id> narrows to one branch (depth counted from that node); --depth N widens or narrows how far the walk descends. An unknown --root fails loud, naming the nearest real ids.
  2. search to find. danxbot-docs search ./docs "<query>" (see above) ranks nodes (BM25 over title, summary and body, with stop words dropped, words stemmed, a bonus for a phrase a page actually says, and a small boost for graph proximity), returning one line per match: id, type, title, summary, the page's file, its size in bytes and lines, and look_in when the page declares code pointers (DX-5582). No body and no ancestor or related lists: the size says whether to read the file whole or in slices. The same answer comes from the platform MCP's docs_search for this checkout, another docs root or a team repo's hosted docs. Six matches by default; --limit N for more.
  3. show <id> to read. danxbot-docs show ./docs <id> prints that ONE node in full: its complete frontmatter (every section it carries — rules, decisions, how_it_works, states, watch_out_for, ...) and its markdown body, plus its ancestor chain and its direct children — both reduced to id + summary only, never expanded. Reading stays granular: show never pulls in a child's own content, so the next step is always another explicit tree/search/show call, not an ever-growing dump. An unknown id fails loud, naming the nearest real ids.

Read a source file directly only when show's look_in pointers say to look there — the docs themselves never name classes, routes or symbols (R-11), so there is nothing to dig for inside the page content itself.

For agents: promoting a plan into docs (DX-3674)

A separate, generic protocol from the read-side one above: how to turn a FINISHED PLAN into one docs changeset against an existing root — reading the whole plan, reading the landed commits, deciding create/update/merge/ supersede against the current graph, and validating with check before committing. It ships as PROMOTION.md; an agent reads it with danxbot-docs promotion-guide rather than needing to know where inside node_modules this package physically unpacked. This package is repo-agnostic and knows nothing about WHICH plan or WHERE to push the result — the dispatch that points an agent at this guide supplies that.

Demo (DX-3369)

The package ships a realistic example docs project — Ringlet, a fictional service for selling event tickets — at examples/ringlet/, separate from the neutral test fixtures. It is written at schema v3's granularity: a handful of substantial Areas, each with a few Topics, plus Guides and learning Paths — never a thin node holding just one sentence. It names no classes, routes or schemas; each area points engineers at where to look instead.

One command serves it:

npm run demo               # dev, via tsx — reads examples/ringlet live
node dist/cli.js demo      # after `npm run build` — same, from the built CLI

Both are exactly danxbot-docs demo [--port N] under the hood (default port 4300, same as serve) — a thin wrapper around serve pointed at the bundled examples/ringlet directory, resolved from the package's own install location rather than the current working directory, so it works from anywhere the package is installed or checked out.

The docs app (serve / build)

serve and build both need the app's own assets pre-built once via npm run build:app (or npm run build, which does both the CLI and the app) — they read dist/app rather than compiling anything on the fly. serve is a plain node:http static file server: no database, no framework. It re-reads the given docs root and rebuilds the embedded data on every request to /, so editing a node file shows up on the next browser reload with no restart. build writes the same app as a fully static site: the built assets plus one index.html with that docs root's data embedded, deployable to any static host. Both refuse (fail loud, R-3) to serve/build an invalid docs root — exactly the same validation check runs.

The app itself: a children-only focus web (a page's part_of children fan out around it; a cross-link is an inline "See also" text link, never a ring node), one page per node (zero-context summary first, then its page sections rendered with the matching component, "where to look" pointers and provenance), and search results rendered as small clickable graphs (the same engine search uses). Real chrome throughout — nav, part-of breadcrumbs, a command-palette search, appearance controls (theme/text size/contrast/ motion), deep links — built entirely from @danxbot/ui, responsive down to phone width. Source under src/app/ (the React app) and src/server/ (the CLI-facing serve/build layer); see src/app-data.ts for the one contract between them.

Check rules

check exits non-zero and lists every problem, one per line, with the file it was found in:

  • schema_violation — schema errors: missing/invalid frontmatter, a field that fails the schema, a removed node type, a part_of missing on a non-System node or present on a System, a look_in naming a source file or a symbol
  • unsupported_schema_version — a schema_version other than the current one (never auto-migrated — CLAUDE.md Core Principle 1)
  • unreadable_file — a .md file or a directory under the root that cannot be read (a dangling symlink, a permission error); it is reported and the rest of the tree still loads (DX-5597)
  • duplicate_id — the same id declared by more than one file
  • dangling_relation — a part_of or see_also pointing at an unknown id
  • part_of_cycle — a part_of cycle
  • part_of_target_type — a part_of parent of a type the tree's shape doesn't allow (see the part_of table above)
  • multiple_systems — more than one System in a docs root
  • summary_too_long — a summary over the 200-character cap
  • path_unknown_node — a Path step naming an unknown node id
  • unknown_icon_name — an icon (node-level or on a value_props entry) that isn't a real @danxbot/ui icon name
  • unknown_color — a color (node-level or on a value_props entry) that isn't a PALETTE_KEYS palette key
  • thin_page — a System/Area/Topic body under the fifty-word floor a real page needs (R-13); Guides and Paths are exempt
  • how_it_works_code_symbol — a how_it_works actor or target written as code (name::method, name(), name->method, or a source-file or file-and-symbol shape) instead of a role in the system (R-11); prose fields are never scanned, and a bare class name is left to PROMOTION.md's audience test

Tests

tests/fixtures/valid/ is a small neutral example project (every node type, every page section, look_in, color, icon and value_props each exercised at least once) that passes check cleanly. tests/fixtures/invalid/ has one fixture directory per check rule above, each proving that rule alone fires, plus: v1-node and v2-node (both retired schema versions, refused the same way), removed-type (a v3 file using a type v3 deleted), multiple-problems-one-file (two rules firing on the same file at once), and look-in-file-symbol (a schema-level look_in shape refusal). examples/ ringlet/ (see "Demo" above) is a separate, much larger project meant for a human to browse, not as a minimal test fixture — it is also covered by its own test asserting it passes check with zero problems, and by tree-show-ringlet.test.ts, which exercises tree and show against it (card AC "tests cover both commands on the Ringlet example").

版本与发布记录

@danxbot/docs 共发布 55 个版本,首次发布于 2026/09/30;过去 12 个月发布了 55 个版本。

版本发布日期距今
0.1.72latest2026/11/065 天前
0.1.702026/11/065 天前
0.1.682026/11/065 天前
0.1.672026/11/065 天前
0.1.662026/11/055 天前
0.1.652026/11/055 天前

关于 @danxbot/docs 的常见问题

@danxbot/docs 是什么?

Repo-agnostic docs package (DX-3336/DX-3337): a typed, versioned node-file format, a loader that builds an in-memory graph from a docs root, and a fail-loud check CLI.

如何安装 @danxbot/docs?

在项目目录运行 npm install @danxbot/docs,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 danxbot-docs,可以用 npx danxbot-docs 直接运行。

@danxbot/docs 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@danxbot/docs 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@danxbot/docs 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@danxbot/docs 可以商用吗?

@danxbot/docs 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@danxbot/docs 的下载量有多少?

根据 npm 官方下载统计,@danxbot/docs 在 2026/10/12 – 2026/11/10 这 30 天内被下载 7,676 次,日均约 256 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@danxbot/docs 还在维护吗?

最新版本 0.1.72 发布于 2026/11/06(5 天前);至今共发布 55 个版本,其中过去 12 个月发布了 55 个;首次发布于 2026/09/30。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。