This file contains instructions for AI agents working with the @diplodoc/cli project.
If a module contains a MODULE.md file, it is considered part of the module's context and should be consulted when working with that module. These files provide module-specific documentation, architecture decisions, and implementation details that complement the general project documentation.
@diplodoc/cli is a CLI tool for building documentation from Markdown files with Yandex Flavored Markdown (YFM) support. The project allows you to build full-fledged documentation with navigation, internal transitions, and full YFM support.
src/— source code of the projectcommands/— CLI commands (build, publish, translate)core/— core logic (config, logger, markdown, toc, etc.)extensions/— extensions (openapi, generic-includer, local-search)steps/— DEPRECATED processing steps (do not add new code here)
build/— compiled code (generated during build)lib/— libraries (generated during build)tests/— project testse2e/— end-to-end testscases/— test casesfixtures/— test fixturesmocks/— test mocks
Packaged tests contract: tests/ and vitest.integration.config.ts are shipped in the npm package (see files in package.json). Downstream consumers run the integration suite from the packaged layout against their own binary via the DIPLODOC_BINARY_PATH env variable. Therefore specs under tests/ must not depend on anything outside tests/ and the built CLI - in particular not on scripts/ or src/, which are not shipped. A spec that needs them must be excluded from the package with a !-pattern in files (see tests/e2e/translate-eval.spec.ts).
-
build — main command for building documentation
- Location:
src/commands/build/ - Subcommands and features are located in
src/commands/build/features/
- Location:
-
publish — publishing documentation
- Location:
src/commands/publish/
- Location:
-
translate — translating documentation
- Location:
src/commands/translate/
Seed reuse is not limited to lines changed in the source PR.
stableProsePairsinproviders/ai/utils/align.tsrejects unanchored prose when its enclosing section diverges. Matched root headings and bold labels ending in a colon immediately before cuts delimit sections only when their pairing is monotone; headings inside cut/note/tab containers do not. A release label can be**Releases:**, not an ATX heading. When verifying preservation, compare every unchanged region with the approved target, including the introduction before the first release cut. Checking only the old release suffix misses this case. Check copied files against their old counterparts too: a same-path diff represents the new include as entirely added. Runtranslate seedoffline to inspect per-file pairs, then exercise composition: extraction can normalize padding before link destinations. The loader restores this padding only when occurrences of the same URL agree; ambiguous padding remains unsupported.seed_partialdoes not implyPARTIAL: newly translated units can succeed while changing previously approved wording. Exact Markdown copies to new paths useSeedStoredocument snapshots: a raw source fingerprint includes vars and code mode, and matching approved targets must agree byte for byte. This preserves occurrence-specific wording even when the same source phrase has different translations in one file; the shared dictionary alone picks a single wording. Snapshots are recorded independently of unit alignment, including merged target prose and files without units. Existing paths and edited copies continue through unit translation and markup checks. Verify both branches with the real provider, including copied-file counters; a preservation run that makes zero model requests is not a quality check of newly translated text. - Location:
-
content — render a single file to stdout/file (md or html content fragment)
- Location:
src/commands/content/ - Reuses the build
Run, itsnormalize/validateandbuildConfigDefaults(src/commands/build/config.ts),MarkdownCollector/SELF_CONTAINED(md) andgetBaseMdItPlugins(html). - Root/file resolution is the pure
resolveContentConfig(src/commands/content/config-resolve.ts): picks the project root from-c's directory or CWD (falling back to the file's own dir when it lives outside that root), setsconfig.input/outputto that root withoriginAsInput = true, stores the target asconfig.file, and populatesconfig.templateitself (build'sTemplatingfeature is not run). - stdout has two modes: default wraps the result in
CONTENT_START/CONTENT_ENDmarkers (so it can be fished out of the framework banners);--raw(config.raw) emits only the content. In raw modesrc/index.tsalso skips the version/timer/completion banners viaisRawContentRun(argv)(exported from the content command).-oalways writes raw (no markers), regardless of--raw. - Note:
resolveConfigtreatsENOTDIRlikeENOENTso a single-file--inputdoesn't break config discovery. - Tests: unit specs co-located in
src/commands/content/*.spec.ts(resolution, render md/html, emit stdout/-o, watch paths/rebuild,ContentWatcher) drive Sonar coverage; e2e lives intests/e2e/content.spec.ts(out-of-process, not counted by Sonar).
- Location:
- Language: TypeScript
- Runtime: Node.js >= 22
- Testing: Vitest
- Build: esbuild
- Linting: ESLint (via
@diplodoc/lint)
# Build project
npm run build
# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Run E2E tests
npm run e2e
# Type checking
npm run typecheck
# Linting
npm run lint
npm run lint:fixThe project uses path aliases:
~/— points tosrc/- Example:
import {Program} from '~/core/program'
-
Program — main class that manages command execution
- Located in
src/commands/index.ts - Uses decorator pattern (
@withConfigDefaults)
- Located in
-
Commands — CLI commands inherit from
BaseProgram- Each command can have its own options, hooks, and handlers
-
Features — functionality is grouped into features
- Examples:
output-html,search,watch, etc. - Each feature can have its own configuration and hooks
- Examples:
-
Hooks — hook system for extending functionality
- Uses
tapablelibrary
- Uses
Every command should follow a well-defined structure to ensure maintainability and separation of concerns.
- Main logic is concisely gathered in
index.ts - Implementation is divided into separate functionalities through
features/ - Features do not depend on each other
- A command can extract part of functionality into services, located in
services/directory - Services do not depend on each other
- If multiple features need to use the same computed data, such data (and logic for working with them) should be extracted into a service
- If multiple features use the same logic for processing their own data, such logic should likely be extracted into a common utility in the
utils/directory at the same level asfeatures/andservices/ - Utils may depend on each other
- Utils cannot depend on anything outside of
utils/
index.ts— main entry point with concise core logichooks.ts— command hooks for external interaction are always described hereconfig.ts— command and feature configurations for CLI are described heretypes.ts— public types are always described here and exported from the module viaindex.ts- Only public types are exported from
types.ts - Common types used only at the module level should be described next to the entity that produces these types
- Only public types are exported from
Features represent separate functionalities of a command:
- Located in
features/[feature-name]/directory - Features are independent and do not depend on each other
- Each feature can have its own:
index.ts— feature implementationconfig.ts— feature configurationhooks.ts— feature hooks (optional)
Services contain shared business logic:
- Located in
services/[service-name]/directory - Services are independent and do not depend on each other
- Services are used when multiple features need shared computed data or logic
- Services can have:
index.ts— service implementationtypes.ts— service-specific typeshooks.ts— service hooks (optional)
Utility functions for shared logic:
- Located in
utils/directory at the same level asfeatures/andservices/ - Utils may depend on each other
- Utils cannot depend on anything outside of
utils/(no dependencies on features, services, or external modules) - Use utils when multiple features need the same data processing logic
The core/ directory contains logic common to all commands:
- Most often this logic is organized into services
- But base (abstract) classes are also possible, for example
BaseProgram - Used in external extensions in a fully bundled form, i.e., dependencies from
coreare fully bundled
The same rules apply to core/ as to commands:
types.ts— only public types are exportedhooks.ts— hooks are always described here- Service concept applies — logic is organized into services
- Common types used only at the module level should be described next to the entity that produces these types
-
File naming:
- Type files:
types.ts - Configuration:
config.ts - Main module file:
index.ts - Tests:
*.spec.tsor*.test.ts
- Type files:
-
Comments and documentation:
- All code comments must be in English
- All documentation files (ADR, AGENTS.md, README, etc.) must be in English
- JSDoc comments are used for exported functions/classes
-
Variables:
- Avoid single-letter variable names
- Don't use overly long variable names
CLI diagnostics share the YFM numbering namespace with yfmlint. YFM024 is the published empty-heading-ID rule; YFM025 is the CLI-only missing-local-anchor rule. Check both registries before assigning a number and keep their configuration independent.
-
Unit tests:
- Uses Vitest
- Tests are next to code or in
__tests__/ - Prefer using
vitest-whenfor mocking instead of standardmockImplementation
-
E2E tests:
- Located in
tests/e2e/ - Snapshots are used for output verification
- Located in
-
Test fixtures:
- Data preparation (Arrange) should be grouped into helper functions when the same setup is repeated across tests
- Prefer using
page.goto()instead ofpage.evaluate()for navigation - Avoid
page.locator(selector).first()— use more explicit and reliable selectors
core/config/— configuration managementcore/logger/— loggingcore/markdown/— Markdown processingcore/toc/— table of contents managementcore/vcs/— version control systems integrationcore/program/— base program and extension system
Main build logic is located in:
src/commands/build/handler.ts— command handlersrc/commands/build/run.ts— command executionsrc/commands/build/features/— various build features
src/commands/build/features/llms/ collects entries from the resolved TOC recursively while
excluding hidden subtrees and external links. Preserve the parent TOC item name on collected
entries: for an OpenAPI include, the parent name labels the whole API section, while
leadingPage.name labels only the generated landing page. In llms.txt, emit the companion
*.openapi.json link with the parent name immediately before its matching landing-page link.
run.openapiCompanions provides the leadingPage -> companionPath mapping.
Extensions integrate with CLI through hooks. There are two integration patterns based on initialization approach:
- Independent extensions — extensions that are not automatically initialized by CLI (can use
peerDependencyregardless of monorepo membership) - Auto-initialized extensions — extensions that CLI automatically imports and initializes on startup (require wrapper logic in
src/extensions/to avoid circular dependencies)
For details, see ADR-001: Dependent Extensions.
Auto-initialized extensions:
extensions/openapi/— OpenAPI support (wrapper for@diplodoc/openapi-extension)extensions/generic-includer/— generic includerextensions/local-search/— local search (wrapper for@diplodoc/search-extension)extensions/github-vcs/— GitHub integrationextensions/arcadia-vcs/— Arcadia integration
The project supports configuration via:
.yfmfile (YAML)- Command-line arguments
- Environment variables
Main configuration files:
YFM_CONFIG_FILENAME— configuration file name (usually.yfm)
README.md— main documentationCONTRIBUTING.md— contributor guideCHANGELOG.md— change historyadr/arch-quality.md— architectural quality principlesadr/ADR-001-dependent-extensions.md— architecture decision record for extension integration patterns
MODULE.md— if present in a module directory, this file contains module-specific documentation and is part of the module's context for AI agents- Provides module architecture, implementation details, and usage patterns
- Should be consulted when working with that specific module
- Example locations:
src/core/MODULE.md,src/commands/build/MODULE.md, etc.
- Create directory in
src/commands/[command-name]/ - Create command class inheriting from
BaseProgram - Register command in
src/commands/index.ts
- Create directory in
src/commands/build/features/[feature-name]/ - Implement feature with hooks
- Register feature in
src/commands/build/index.ts
- Create directory in
src/extensions/[extension-name]/ - Implement extension
- Register in project configuration
- The project uses a monorepo (nx)
- All changes must pass linter and tests
- Types must be correct (checked via
npm run typecheck) - When working with VCS (GitHub/Arcadia), token configuration is required in
.envor.yfm - All comments and documentation files (ADR, AGENTS.md, README, etc.) must be written in English
- The
src/steps/directory is deprecated. Do not add new code there. If you need to fix existing code, carefully move it tocommands/build/features/ - When changing TypeScript types that have a corresponding schema in
schemas/, always update the schema to match, and vice versa
