Skip to main content

API and documentation development

Start with architecture and maintenance for module boundaries, extension workflows, ownership rules and test-isolation requirements. The CLI reference documents invocation and exit-status contracts.

For complete client recipes, method effects, and isolated examples, see embedding Workstation.

All supported consumer imports come from @dovocode/workstation. The generated API reference covers builders, resource types, configuration loading, locks, manifest serialization, and the process runner.

Read-only config loading

import { findConfig, loadConfig } from "@dovocode/workstation";

const path = await findConfig();
const config = await loadConfig(path, "studio");
console.log(config.context.machine, config.resources.length);

Loading evaluates your TypeScript and hashes local custom-tool sources; it does not install resources. Arbitrary side effects in your own config are still ordinary TypeScript side effects. lockConfig queries package managers and writes the lock, while writeManifest persists resolved declarations.

resourceId supplies the stable identity and fingerprint hashes the full resolved declaration. ProcessRunner executes commands without an implicit shell and returns exit status/output. Internal reconciliation modules are not exported as a supported package API.

Generate and preview the docs

pnpm install --frozen-lockfile
pnpm docs:dev

This starts the Docusaurus development server with live reload. Open the URL it prints (normally http://localhost:3000/workstation/). The handbook reads Markdown from docs/; website/sidebars.ts defines the learning sequence and navigation.

For a production build, including API reference, search index, and legacy redirects:

pnpm run docs
pnpm --filter @dovocode/workstation-docs serve

Use the printed HTTP URL rather than opening index.html through file://: the site uses /workstation/ as its base path. The output is dist/docs. A package build may clean dist, so regenerate the docs afterward. pnpm docs:api generates only the TypeDoc reference under ignored website/static/api; this also makes the API available during local Docusaurus development. Local full-text search is generated by a production build, not the development server.

The root package remains the published CLI/library. The private website workspace owns the Docusaurus and React dependencies; they are not added to consumer runtime dependencies. Docusaurus expects its generated client modules in the default module mode, so this workspace deliberately omits type: "module" while the root package retains ESM. No publishing is performed by these build/preview commands.

Publish the GitHub Pages site

The public handbook lives at https://dovocode.github.io/workstation/. It uses Docusaurus for the handbook, with local full-text search, ordered chapter navigation, syntax highlighting, and light/dark themes. The generated TypeDoc API reference is available at /workstation/api/ with its own API search. The Docusaurus configuration and styling live under website/; typedoc.json controls the generated API.

node scripts/finalize-docs.mjs adds redirects from the previously published TypeDoc guide/API URLs and verifies the search index and static output. Maintain website/legacy-routes.json when changing a previously published guide or API path. Docusaurus treats broken internal links as build errors.

With Git push access to dovocode/workstation, publish reviewed documentation:

pnpm docs:publish

This rebuilds the site, checks its static assets, then commits and pushes only the rendered output to gh-pages using a temporary checkout. It leaves your working branch intact, preserves publication history, and refuses to replace an existing branch without the generated-site marker. Concurrent pushes fail normally rather than force-pushing. The temporary checkout is removed afterward. Commit source changes before publishing so the publication commit identifies the correct source revision. The script publishes the current working tree's build.

Repository Settings → Pages must use Deploy from a branch, gh-pages, and / (root). GitHub deploys the branch after each publication. .nojekyll prevents Jekyll processing. The branch contains public rendered documentation only, not source checkouts, dependency directories, or private workstation state.

This is an explicit publication command; a source push alone does not update the website. pnpm run docs remains the local build command. The publication script uses Git credentials and does not require permission to create Actions workflows.

Edit API comments at their declarations and guides under docs/. Named functions and methods in the implementation also carry JSDoc describing their responsibility and relevant effects. Inline iteration callbacks are covered by their enclosing function rather than becoming separate API pages.

Run corepack pnpm check, corepack pnpm test, and corepack pnpm run docs before submitting documentation or API changes. Source lives under src/api, src/config, src/resources, src/rendering, src/reconciliation, and src/persistence.

Fallow code-quality checks

The pinned fallow development dependency provides Rust-based repository analysis. Install dependencies with corepack pnpm install, then run:

corepack pnpm quality # Fresh coverage, then the full Fallow gate
corepack pnpm test:coverage # Refresh coverage without running Fallow
corepack pnpm quality:dead-code # Unused exports and dependencies
corepack pnpm quality:dupes # Clone groups
corepack pnpm quality:health # Complexity and refactoring targets
corepack pnpm quality:audit --base HEAD # Review local changes against HEAD

Use an appropriate fetched base ref for branch reviews. Fallow exits 1 for findings and 2 for execution errors. These checks complement, not replace, check and documentation validation. The full gate generates fresh Istanbul-compatible JSON coverage with Vitest's V8 provider, then passes it explicitly to Fallow for measured per-function risk scores. Run this gate before relying on standalone health or audit reports; cached coverage may refer to older source locations. No thresholds are relaxed and no blanket baseline hides findings. Detailed refactoring suggestions can still appear in a passing report; they are advisory, not failed rules. CI runs this full quality gate on Linux x64 in addition to the existing platform test/build matrix. Coverage reports remain local build artifacts, not source files.

.fallowrc.json declares the library, CLI and build scripts as entry points. postject is a dependency exception because scripts/build-native.mjs invokes its binary using a computed filesystem path. The private documentation workspace also declares React, the MDX React runtime, and Docusaurus theme-common as required framework/search peers; generated modules import them, so these three dependencies are explicitly accounted for rather than removed as unused. The TypeDoc CSS file is an explicit asset entry because TypeDoc loads it through its JSON configuration. Fallow's local .fallow/ cache is ignored. Before deleting a reported unused export, inspect its public API and test consumers with corepack pnpm exec fallow dead-code --trace src/file.ts:symbol. Do not run automatic fixes without reviewing their changes, especially on resource ownership and recovery code. See the official Fallow guide.

Native config-import regression

node scripts/test-standalone-build.mjs checks a native build with an empty PATH, temporary home and no dependencies or package manifest. It verifies generated content and repeat-run convergence; only temporary fixture state is reconciled. CI runs it after building each native platform binary.

After corepack pnpm build:native, run node scripts/test-native-imports.mjs. It creates and removes an isolated project, imports the built library by package name, and lists tasks through both CLI distributions. No workstation state is applied. CI runs it for all four native platforms. An optional binary path lets the same fixture verify a previously released executable.

The SEA-only Jiti build adapter uses Node's filesystem ESM loader through vm.compileFunction, retaining asynchronous module support instead of replacing imports with synchronous require. This Node API is experimental and may emit an ExperimentalWarning when first used; warnings are not globally suppressed. The adapter checks the pinned Jiti source signature and fails the build if it changes, so dependency updates require reviewing this integration.

RPM backend integration tests

The regular test suite uses fake command results and does not change system packages. With Docker running, exercise actual DNF 5 (Fedora), DNF 4 (Amazon Linux 2023), and legacy YUM (Amazon Linux 2) in disposable containers:

WORKSTATION_RPM_INTEGRATION=1 corepack pnpm exec vitest run test/rpm.integration.test.ts

This downloads the images and tests locking, installation, verification, repeat runs, removal, and upgrades/downgrades when an older package is available. It also verifies multi-package installation and removal in one native transaction. The test containers are removed afterward; downloaded images remain cached.

APT, pacman and Flatpak integration tests

WORKSTATION_APP_INTEGRATION=1 corepack pnpm exec vitest run test/app-packages.integration.test.ts test/apt-batch.integration.test.ts

These use disposable Ubuntu, Arch Linux and Fedora containers, including native multi-package installs/removals. Flatpak uses tiny local test apps and a runtime, exercising user/system installs, pinned updates, rollback to a retained commit, and removal without downloading desktop runtimes. On ARM Docker hosts, Arch runs under x86 emulation; the test adapter disables only pacman's downloader syscall sandbox because QEMU cannot install its seccomp filters. Production Workstation commands retain pacman's normal sandboxing. The containers are removed afterward; image caches and temporary fixtures remain. MAS mutation tests use recorded command responses and do not install, update, purchase, or remove apps from your Apple Account.

Publish a release

The build.yml workflow publishes to npm only for pushed v* tags, after all four Linux/macOS builds pass. The tag must equal v plus the version in package.json. Stable versions use npm's latest tag; prereleases use next. Branch pushes, pull requests, and manual workflow runs do not publish.

Authentication uses npm trusted publishing with GitHub OIDC and provenance, without a stored npm token. The npm package must trust GitHub repository dovocode/workstation, workflow filename build.yml, with publishing allowed and no environment restriction.

Use Conventional Commits for new commits, for example feat(packages): add a package backend, fix(migration): restore completion links, or docs: clarify setup requirements. Record user-visible changes in CHANGELOG.md under Unreleased as part of each change. Existing history does not need to be rewritten.

To release, update the package version and move the Unreleased changes into a dated changelog section. Verify the release, commit it with chore(release): <version>, then push the matching tag only when npm publication is intended. For example, after preparing version 0.1.1:

corepack pnpm check
corepack pnpm test
corepack pnpm build:native
corepack pnpm run docs
git add package.json CHANGELOG.md
git commit -m "chore(release): 0.1.1"
git push origin main
git tag -a v0.1.1 -m "chore(release): 0.1.1"
git push origin v0.1.1

Use a new version for each release; npm versions cannot be overwritten. Do not tag the already-published 0.1.0 expecting it to publish again.