sottovoce

A FlossyPurse Studios tool

Your docs should quote code that actually runs.

sottovoce syncs real, tested code from source repos into your docs and keeps the two in sync — with the smallest possible footprint in both.

npm version MIT license
# one comment line marks the snippet; the fence below it is ordinary markdown
<!-- sotto local:src/checkout.ts#purchase -->

$ npx sottovoce sync
✓ docs/guide.md:12  ← src/checkout.ts#purchase

# run it in CI and drift stops being a silent lie
$ npx sottovoce check
drift: docs/guide.md:12

code samples rot

Docs code samples rot

The example compiles the day you paste it, then the SDK moves and the docs don't. sottovoce makes your docs reference code that actually lives in a repo — ideally one your CI already builds and runs — and keeps the two in sync. Same job as marker-based snippet tools like snipsync, with one design goal added: stay quiet.

Source files need no markers

Reference a whole file, a line range, or a named region. Regions use the // #region / // #endregion markers editors already fold on — they read as ordinary code organization.

One comment line per snippet

Not a wrapper pair. The code fence below the directive is a normal fence — sottovoce rewrites its contents in place, idempotently. Run it twice and nothing changes.

Synced code is committed

Not fetched at build time. Docs builds stay network-free, snippet changes show up in reviewable diffs, and anything indexing your docs sees real code.

Drift is a failing build

sottovoce check exits non-zero if any fence is stale or any directive is broken. Wire it into CI and a stale snippet fails the build instead of shipping a lie.

git on PATH

Install

# add it to the docs repo
npm install --save-dev sottovoce

Requires Node 20+ and git on PATH.

Quickstart

Everything here runs locally — no GitHub org, no credentials. Add sottovoce.json to your docs repo, pointing a source at a directory of example code:

{
  "docs": ["docs/**/*.{md,mdx}"],
  "sources": {
    "local": { "path": "../examples" }
  }
}

Reference a snippet in any markdown or MDX file — a directive comment followed by a code fence — then run npx sottovoce sync. Every directive's fence now holds the current code from the source. Run it again and nothing changes — that's the point.

<!-- sotto local:src/checkout.ts#purchase -->

In MDX, use {/* sotto local:src/checkout.ts#purchase */} — an HTML-style comment in an .mdx file still syncs, but prints a warning, since MDX builds fail on HTML comments.

referencing code

Referencing code

The directive form is <source>:<path>[#region] [options].

A named region

uses editor-native fold markers in the source file. Any common comment leader works (//, #, --, ;, /* */, <!-- -->), plus bare #region for C#. Marker lines never appear in output.

// #region purchase
const receipt = await checkout(cart);
// #endregion

Multiple regions from one file compose with +, so a page can show imports and a function while skipping the code between them — each region is extracted and dedented on its own, joined with one blank line.

<!-- sotto local:src/checkout.ts#imports+purchase -->

A line range is the escape hatch for code you can't annotate — fragile by nature, so prefer regions in files you control. Options are lines=A-B and lang=x; snippets are dedented to their shallowest line, blank edges trimmed, and fences widen automatically around backtick runs.

repo or path

Sources

Each named source is either a GitHub repo pinned to a ref, or a local path:

{
  "ts":  { "repo": "your-org/examples-ts", "ref": "v1.4.0" },
  "wip": { "path": "../examples" }
}

Pin ref to the release tag your docs describe — that's what keeps a docs version honest. Branches, tags, and full commit SHAs all work; if omitted, ref defaults to main. Repos are shallow-fetched into ~/.cache/sottovoce/; --offline reuses the cache without touching the network. Private repos work through your ambient git credentials.

sync, check, list

Commands

CommandWhat it does
sottovoce syncRewrites every directive's fence with the current source code, idempotently. Inserts a fence where none exists. Exits non-zero on a broken directive, even after writing every valid fence.
sottovoce checkThe drift alarm. Exits non-zero if any fence is stale or any directive is broken. --diff prints what changed under each drift: line.
sottovoce listPrints every directive the docs globs can see, grouped by file. Flags [UNKNOWN SOURCE], [NO FENCE], and [INVALID]. Parse-only, offline, always exits 0. --json emits the same inventory as JSON.

Broken directives never destroy content — the existing fence is left untouched and the problem is reported.