Writing docs
Write docs that ship with your package and that people and agents find by search or one level at a time.Add a topic with the CLI
Run integration add doc in your package to add a topic. It writes the topic file and declares the docs root in astryx.integration.mjs.
bashnpx astryx integration add doc deploying# Read it the way an app willnpx astryx docs deploying
textdoc contribution added[ok] deployingDeclare doc root ./docs in astryx.integration.mjs.- docs/deploying.doc.mjs- astryx.integration.mjs
- Name the topic in lowercase kebab-case, such as
deploying. Readers type the name as a command argument, so it holds only letters, digits,_, and-. - Keep the name stable: readers and links find the topic by it.
- Pick a name no Core topic uses. To take over or add to a Core topic, see
astryx docs cli/integrations/building-blocks/docs/extend-or-replace.
Write the sections
A topic is a plain object with type: 'generic', a name, a title, a one-sentence description, and sections. Each section has a title and a list of content blocks.
javascript/** @type {import('@astryxdesign/cli/authoring').ReferenceDoc} */export default {type: 'generic',name: 'deploying',title: 'Deploying',description: 'Ship an app built with Acme widgets.',sections: [{id: 'build-before-you-ship',title: 'Build before you ship',content: [{type: 'prose', text: 'Build the app, then upload the `dist` folder.'},{type: 'code', lang: 'bash', code: 'npm run build'},{type: 'list', style: 'unordered', items: ['Keep `dist` out of git.']},{type: 'table', headers: ['Variable', 'Value'], rows: [['`NODE_ENV`', '`production`']]},],}],};
- Content blocks are
prose,code,list, andtable, as shown;heading, with alevelfrom 3 to 6 and atext; andtoken-ref, which inlines a token table from another topic. idis optional: a stable key for the section. Without it, the key comes from the title. A stable CLI before 0.6.4 cannot readid; seeastryx docs cli/integrations/ship/versioning.- Replace the
Overviewplaceholder thatintegration addwrites. Every field is inastryx docs authoring.
Pick the doc kind
Every doc is a .doc.mjs file whose type says what it describes. integration add writes the right type and file for each kind.
| You document | `type` | File that `integration add` writes |
|---|---|---|
| A guide or topic | 'generic' | docs/deploying.doc.mjs |
| Your package's docs section | 'namespace' | docs/acme.doc.mjs |
| A component | 'component' | components/AcmeCarousel.doc.mjs, beside AcmeCarousel.tsx |
| A template | 'page' or 'block' | templates/acme-dashboard.doc.mjs, beside acme-dashboard.tsx |
| A theme | 'theme' | themes/ocean/oceanTheme.doc.mjs, beside oceanTheme.ts |
Only guides, topics, and your docs section go in the docs root. The others have their own guides: astryx docs cli/integrations/building-blocks/components, astryx docs cli/integrations/building-blocks/templates, and astryx docs cli/integrations/building-blocks/themes.
Keep topics in the docs root
The docs field in astryx.integration.mjs names the folder that holds your topics. The CLI reads every .doc.mjs file under it, in subfolders too.
javascriptexport default {docs: './docs'};
- Readers open a topic by its
name, not its file name. Name the file after the doc,<name>.doc.mjs, so each one is easy to find. - A topic with no
placementis a flat topic: the docs list shows it under Topics, and readers open it by its name. - To give your package its own section in the docs tree instead, see
astryx docs cli/integrations/building-blocks/docs/sections-and-placement.
Add a docs section
Give your package its own section in the docs tree with integration add doc <name> --parent <section>. The first run also writes the section's namespace doc.
bashnpx astryx integration add doc deploying --parent acme# Open your sectionnpx astryx docs acme
javascript/** @type {import('@astryxdesign/cli/authoring').NamespaceDoc} */export default {type: 'namespace',name: 'acme',title: 'Acme',summary: 'Guides for Acme.',slots: {guides: {title: 'Guides', accepts: {kinds: ['generic']}},},};
- Edit its
titleandsummary: readers see them in the docs list and at the top of your section. - The guide,
docs/deploying.doc.mjs, getsplacement: {parent: 'namespace:acme', slot: 'guides'}. Later runs with--parent acmereuse the namespace doc. package.jsongets the optional peer"@astryxdesign/cli": ">=0.6.4", because an older CLI does not read sections; seeastryx docs cli/integrations/ship/versioning.
Place a doc
A guide names its one home with placement: a namespace of your package, a slot in it, and an order. Its route is the section name, then the guide name.
javascriptplacement: {parent: 'namespace:acme', slot: 'guides', order: 10}, // route: acme/deploying
parentisnamespace:<name>, a namespace that your own package ships. You cannot place a doc in the CLI's sections or in another package's.slotis a slot that the namespace declares for the doc's kind. You can leave it out when the namespace has only one slot.orderis an integer that sorts the guides in the slot and sets their Previous and Next moves. Guides without one come last, by name.- A placed guide opens only by its route,
acme/deploying. Its bare name no longer opens it.
bashnpx astryx docs acme/deploying
Fix a failed placement
A failed placement hides the doc: it gets no route and does not show in the docs list. doctor integration docs fails with invalid_doc_graph and names what to fix.
bashnpx astryx doctor integration docs
textseverity: [fail]code: invalid_doc_graphmessage: @acme/astryx-widgets/deploying.doc.mjs: placement.parent "namespace:cli" names no namespace; @acme/astryx-widgets declares "acme".
- A
parentthat your package does not ship, such asnamespace:cli, "names no namespace". - A
slotthat the namespace does not declare "is not a slot of namespace"; the message lists the slots it does declare. - The check exits 1; see
astryx docs cli/integrations/building-blocks/docs/check-your-docs.
Link another doc
Write {@link [provider:]kind:name} in prose, list items, and table cells to link another doc. The CLI prints the command that opens it, so the link keeps working when the doc moves.
javascript{type: 'prose', text: 'Before you ship, read {@link generic:deploying}.'},{type: 'list', style: 'unordered', items: ['All guides: {@link namespace:acme}.']},{type: 'table', headers: ['Task', 'Guide'], rows: [['Ship', '{@link generic:deploying}']]},
Each link reads as a command. This link, astryx docs cli/integrations/building-blocks/docs/extend-or-replace, opens the next guide.
- The kind is
genericfor a topic or guide,namespacefor a docs section, andcommandorfunctionfor a CLI command or API function. - A link to a component or a template does not resolve. Write its name in backticks instead, such as
AcmeCarousel. - Inside backticks or a code block, link syntax prints as written.
Link another package's docs
A link without a provider resolves against your own package. To link the CLI's docs, or another package's, start the target with that package's name, such as @astryxdesign/cli:.
javascript// Resolves: the CLI's doctor command{type: 'prose', text: 'Check the app with {@link @astryxdesign/cli:command:doctor}.'},// Does not resolve: looks for a doctor command in your package{type: 'prose', text: 'Check the app with {@link command:doctor}.'},
- Name a CLI command the way you type it, spaces included, such as
@astryxdesign/cli:command:doctor integration docs. - In a topic that
extendsanother package's topic, your sections still resolve against your package, so a link to the base topic's docs needs its provider.
Fix a link that names no doc
A link that names no doc prints as written, and doctor integration docs warns. The warning names a search that finds the right target.
bashnpx astryx doctor integration docs
textseverity: [warn]code: invalid_doc_graphmessage: acme/deploying § check-before-you-ship: "command:doctor" names no doc. Find it with `astryx search doctor --type doc`, then name it as `[<provider>:]<kind>:<name>`.
- The warning keeps exit code 0, so read the report before you ship; see
astryx docs cli/integrations/building-blocks/docs/check-your-docs. - A stable CLI before 0.7.0 does not read links: it prints each one as written. See
astryx docs cli/integrations/ship/versioning.
Replace a topic
Set replaces to take over an existing topic, such as Core's getting-started. Readers who open the old name get your topic.
bashnpx astryx integration add doc acme-getting-started --replaces getting-started# The old name now opens your topicnpx astryx docs getting-started
javascriptexport default {type: 'generic',name: 'acme-getting-started',replaces: 'getting-started',title: 'Acme getting started',description: 'Install Acme widgets and render your first carousel.',sections: [/* ... */],};
The docs list shows your topic in place of the old one. Because your topic has its own name, the old name keeps resolving to it, so links and agents that learned the old name still land on your topic.
Extend a topic
Set extends to merge sections into an existing topic instead of owning it. A section with the same key replaces the base section, and a new section is added at the end.
bashnpx astryx integration add doc acme-theming --extends themenpx astryx docs theme --index
javascriptexport default {type: 'generic',name: 'acme-theming',extends: 'theme',title: 'Acme theming',description: 'Theme an app that uses Acme widgets.',sections: [{id: 'quick-start', title: 'Quick Start', content: [/* replaces the base section */]},{id: 'use-the-ocean-theme', title: 'Use the ocean theme', content: [/* added at the end */]},],};
- A section's key is its
id, or a key made from its title. Read the base topic's keys with--index. - The topic keeps the base's title and description, and readers open it by the base's name.
- Replace the
Overviewplaceholder thatintegration addwrites, or it is added to the base topic. - Extend a topic to correct or add to it. A copy made with
replacesstops getting the owner's fixes.
Check overlaps with Core topics
A topic sets replaces or extends, never both, and a placed guide sets neither. A topic that uses a Core topic's name with neither is an accidental conflict: apps keep reading the Core topic.
bashnpx astryx doctor integration docs
textseverity: [info]topic: acme-getting-startedrelationship: replacescoreTopic: getting-startedmessage: Intentional override: "acme-getting-started" replaces the Core topic "getting-started".severity: [fail]topic: tokensrelationship: accidentalcoreTopic: tokensmessage: Accidental conflict: "tokens" is already a Core topic. Rename it, declare replaces: 'tokens' to take it over, or declare extends: 'tokens' to merge sections.
- An intentional overlap prints as
[info]. An accidental one fails with exit code 1. - A topic that sets both fails as
invalid_doc, and so does a placed guide that sets either one.
Keep each read short
Readers open one section at a time, so give each section one idea and keep it to about 30 lines. npx astryx doctor warns on any read over 32 KB.
- When a section needs a second idea, split it into two sections.
- Keep a topic to a few sections. When it grows past five, split it into more guides in your docs section.
- A topic with more than one section reads as its section list. Readers open one section by its key, or the whole topic with
--full.
bash# The section listnpx astryx docs acme/deploying# One sectionnpx astryx docs acme/deploying check-before-you-ship# Everythingnpx astryx docs acme/deploying --full
Lead with the summary
A section's first prose block, or its first list item, is its summary in section lists and search results. Make it answer the section's question in one or two sentences.
- The summary is cut at about 240 characters.
- A code block first does not count: the summary comes from the next prose block.
- Open with the answer, not with background.
textbuild-before-you-ship Build before you ship - Build the app, then upload the `dist` folder to your host.
Make docs findable
Search ranks a query that matches a whole title, or an identifier in backticks, above words in body text. Title each section with the task a reader searches for.
- Name the task in the words a reader types, such as "Deploy to production". Avoid titles such as "Overview" or "Details".
- Write field names, file names, and error codes in backticks, such as
deployTarget: search treats each one as a keyword. - Other words in the summary and body match too, but rank below titles and identifiers. The summary shows under each hit, so make it answer the query.
Test with search
Test a doc the way a new reader finds it: search for the question, and check that the first hit answers it. Quote a query of more than one word.
bashnpx astryx search "place a doc" --type doc
- This query returns the section of these guides that shows how to place a doc.
- Run the same search in an app that installs your package; see
astryx docs cli/integrations/ship/test-in-an-app.
Run the docs check
Run doctor integration docs in your package to check the docs tree, every link, and overlaps with Core topics. Pass a package name to check an installed package.
bashnpx astryx doctor integration docs# In an app, check an installed packagenpx astryx doctor integration docs @acme/astryx-widgets
textChecking integration docs: @acme/astryx-widgets@1.0.0[ok] The docs tree and every link in these docs check out.[ok] No doc topics overlap with Core.
Its arguments and exit codes are in astryx docs cli/commands/doctor-integration-docs.
Know what fails the check
A doc that does not load, an accidental Core overlap, or a failed namespace or placement fails the check with exit code 1. A link that names no doc only warns, and the exit code stays 0.
| Problem | Reported as | Exit code |
|---|---|---|
| A doc that does not load, such as an unknown section field or block type | [fail] invalid_doc | 1 |
A topic with a Core topic's name and no replaces or extends | [fail] accidental | 1 |
| A placement that fails, which hides the doc | [fail] invalid_doc_graph | 1 |
| A link that names no doc | [warn] invalid_doc_graph | 0 |
A topic that sets replaces or extends | [info] replaces or extends | 0 |
Read the warnings before you publish. With --json, they are in data.issues, with severity: "warning".
Check read size
npx astryx doctor also measures every read and warns on one over 32 KB. Run it in your package or in an app that installs it; doctor integration docs does not check size.
bashnpx astryx doctor
textid: docs-progressive-disclosurestatus: [warn]label: Documentation navigation and sizemessage: acme/deploying build-before-you-ship: 46 KB, over the 32 KB one read may return
Split a section over the limit into smaller ones, each with its own key. See astryx docs cli/commands/doctor.
Check the CLI peer
integration verify fails a package that ships a docs section, a placed guide, or a doc section with an id without an @astryxdesign/cli peer of >=0.6.4. It does not run the docs check, so run both.
bashnpx astryx integration verify
text- [fail] The package ships a namespace doc or a placed guide but declares no @astryxdesign/cli peer. A stable CLI before 0.6.4 does not read the docs tree, and can hide every doc topic the package ships. Declare "@astryxdesign/cli": ">=0.6.4" in peerDependencies (optional in peerDependenciesMeta, if the CLI is not required).
integration add doc --parentwrites the peer for you.integration verifypasses a hidden guide and an accidental Core overlap; onlydoctor integration docscatches them.- Everything else it checks is in
astryx docs cli/commands/integration-verifyandastryx docs cli/integrations/ship/checks.