> ## Documentation Index
> Fetch the complete documentation index at: https://toolgrain.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Development and verification

> Set up the repository and choose the right development and CI checks.

Use this guide when changing Toolgrain itself. To build an application, start
with the [quickstart](https://github.com/keshavkatwe/toolgrain/blob/main/README.md#quickstart) and [examples](https://toolgrain.mintlify.site/examples.md).
Read [CONTRIBUTING](https://github.com/keshavkatwe/toolgrain/blob/main/.github/CONTRIBUTING.md) before opening a pull request.

## Set up the repository

Use Node.js 24.20.0 or a newer supported 24.x release, and Bun **1.3.14** for
repository tooling. The Bun tooling pin is separate from the supported
application runtime, which starts at **1.4.4**. See the
[support policy](https://toolgrain.mintlify.site/project/support-policy.md) for all supported versions.

```sh theme={null}
git clone https://github.com/keshavkatwe/toolgrain.git
cd toolgrain
bun install --frozen-lockfile
bun run build
```

Create a branch before editing. Root commands orchestrate workspaces through
Turborepo; packages compile ESM and declarations with TypeScript. Public exports
point to `dist`, so build before running examples or importing workspace packages.

## Develop with an MCP client

Use two terminals from the repository root:

```sh theme={null}
# Terminal 1: library watch builds and example development servers.
bun run dev

# Terminal 2: Inspector starts the compiled stdio example.
bun run --cwd apps/stdio-example inspect
```

Root `dev` runs every library watcher and example development server, with
concurrency 16. Initial library builds run in dependency order. Framework examples
use their native development commands. Individual workspace commands start only
that workspace; see the [example index](https://toolgrain.mintlify.site/examples.md) for ports and scripts.

After a successful rebuild, disconnect and reconnect in Inspector to start a
fresh server using the updated compiled files. Keep application diagnostics on
stderr: stdout belongs to MCP. Inspector is a separate launcher, outside the
watch task.

## Choose the relevant checks

| Command | What it checks |
| - | - |
| `bun run check` | Root Biome formatting, lint, and imports |
| `bun run check-types` | Workspace TypeScript checks |
| `bun run test` | Library tests without coverage |
| `bun run test:coverage` | Library tests with coverage thresholds and protocol integrity |
| `bun run test:examples` | Real-process example integration tests |
| `bun run build` | Compiled library exports and example builds |
| `bun run test:package` | Compiled imports, declarations, and fresh packed consumers |
| `bun run test:size` | Archive size, file inventory, and required legal/debugging files |
| `bun run test:audit` | Lockfile-wide dependency advisories |
| `bun run test:ci` | Repository verification and report-generation tests |
| `bun run test:docs` | MDX syntax, frontmatter, navigation, local links/anchors, and documentation assets |
| `bun run release:check` | Manifest and Bun workspace version alignment |

Run checks that cover the change. API, transport, and packaging changes need the
corresponding runtime and compiled-consumer checks. Documentation-only changes
need working links, accurate examples, and formatting; packaged README changes
also need archive-size checks. CI selects the applicable checks from the actual
Git diff; unknown changes and unavailable history retain the full baseline.

Document package-entrypoint exports and the fields, overloads, and callbacks
consumers encounter through them with JSDoc. Explain defaults, validation,
cancellation, and resource ownership where relevant. Internal module exports and
type machinery do not need API JSDoc; keep implementation comments focused on
non-obvious behavior. Check emitted declarations and IDE hovers, including inferred
accessor results. Keep vendored protocol schemas unchanged. Inline documentation
ships with packages, so check archive sizes after adding it.

Biome is configured once at the root. `bun run check:fix` and `bun run format`
write formatting changes; keep unrelated files out of your pull request.

## Find the right workspace

| Location | Responsibility |
| - | - |
| `packages/mcp` | Tool API, validation, context, auth contracts, and protocol dispatch |
| `packages/protocol` | Pinned upstream wire definitions and provenance |
| `packages/http` | Shared HTTP behavior and Web handlers |
| `packages/node` | Stdio, Node HTTP adapters, and managed listener |
| `packages/jwt`, `packages/clerk` | Endpoint authorization integrations |
| `packages/repo-tools` | Unpublished build, test, package, and release verification |
| `apps` | Independent runnable examples and their integration tests |
| `docs` | Public usage, compatibility, support, and maintainer guides |
| `brand` | Approved artwork, tokens, sources, and licensing |

Keep tests and fixtures alongside the behavior they verify. Repository tooling,
examples, and legal/provenance files are part of the reproducible public source;
builds do not require a private repository. See [architecture](https://toolgrain.mintlify.site/project/architecture.md)
for internal boundaries and [AGENTS](https://github.com/keshavkatwe/toolgrain/blob/main/AGENTS.md) for contributor invariants.

## Record release intent

Use `bun run changeset` for changes to published libraries, including their
packaged READMEs. Use `bun run changeset --empty` for repository-only work.
`bun run release:status` previews the plan without changing versions. Follow the
[release guide](https://toolgrain.mintlify.site/project/releases.md); versioning and publication belong to reviewed
Release PRs.

## Continuous integration

Pull requests always report `Package checks` and `Support checks`. Both use
the same conservative change classifier:

| Changed files | Required work |
| - | - |
| Documentation, artwork, contributor templates, or Changeset records only | Formatting, version alignment, and the lockfile audit; site sources and artwork also trigger `test:docs` |
| Packaged README, changelog, license/notice, or editorial package metadata | The checks above, library builds, archive contents/sizes, and fresh npm/Node runtime consumers |
| Runtime source, examples, dependencies/lockfile, package exports/engines, verification tooling, workflows, or unknown paths | Complete baseline and supported runtime/platform checks |

Only `description`, `homepage`, and `keywords` qualify as editorial manifest
changes. Mixed changes take the strongest profile. Renames consider both paths.
Manual and release verification always request the complete baseline.

`test:docs` compiles MDX without evaluating page JavaScript and checks required
frontmatter, navigation coverage, literal local links/anchors, and assets. It
does not build Mintlify's rendered site, execute examples, evaluate dynamic URLs,
or fetch external links. Keep the Mintlify validation and visual review described
in the [documentation instructions](https://github.com/keshavkatwe/toolgrain/blob/main/docs/README.md).

The complete baseline retains type checks, 95% library coverage, example smoke
tests, builds, package imports/declarations, fresh consumers, sizes, audits, and
repository-tooling tests on Node 24.20.0 and Bun 1.3.14. The support workflow runs
Node and Bun functional consumers on Linux, macOS, and Windows. Compiler checks
run on Linux: npm declarations stay in the baseline; Bun installations check
minimum/development compilers with minimum/development Zod in separate jobs.

On `main`, the publication workflow chooses the release mode and owns the checks.
Ordinary changes call the scoped baseline/support workflows. Publication calls
complete release verification instead, including intermediate TypeScript and
stable dependency drift checks, so a release commit does not start a second
standalone baseline and platform matrix. Node 26 and prerelease probes run only
on the weekly schedule and manual verification runs. See the
[support matrix](https://toolgrain.mintlify.site/project/support-policy.md#required-ci).

MCP package verification reuses its compiled consumer and runtime fixtures in
isolated temporary directories. It checks TypeScript 5.5.4 and the development
compiler against both Zod 4.6.6 and the development Zod version, including Classic
and Mini inference and rejected definitions. Runtime checks run once per Zod
version under Node with source maps enabled and check a TypeScript stack location.
The isolated MCP copy includes its sources. Pinned compatibility dependencies are development tooling;
verification requires no additional downloads or workspace dependency changes.

Root `bun run test:package` also schedules an uncached clean installation task
after the six library package checks. Turbo flags such as `--filter`, `--force`,
and `--dry=json` retain their normal behavior. A package filter that excludes the
root excludes this installation task, too; dry runs perform no installations.

The check packs all six libraries with Bun and serves their unchanged archives
through a temporary loopback registry scoped to `@toolgrain`. Six fresh npm
consumers each install one library as their only direct Toolgrain dependency,
letting npm resolve its declared dependencies and versions. Each imports the
installed library and checks its declaration fixture with both minimum and
development TypeScript, with strict mode and `skipLibCheck: false`. This catches dependencies hidden by installing every
library together. A separate full consumer exercises both protocol revisions
over stdio, Web HTTP, Node HTTP, and the managed HTTP transport, including input
validation, rich results, and a context provider. JWT and Clerk initialize with
test configuration; signed-token and opaque-token verification uses offline
responses. Both eras also exercise stdio cancellation and HTTP disconnects.
No live credentials or external authorization calls are used.

The default check uses npm and Node and retains all verification. Internal
`clean-install --checks=runtime` jobs omit compiler installations and declaration
checks, transpile the same shared fixture with the pinned minimum compiler, and
run isolated imports and all functional tests. `--checks=types` checks installed
declarations without repeating functional flows. Both modes retain fresh,
isolated installs and dependency-tree inspection. Reports record the selected
checks, installer, runtime, and platform. Node source-map verification remains
required in the full package baseline. Post-publication consumers retain the
default complete checks under both npm/Node and Bun.

This check needs npm, Bun, tar, registry access for external dependencies, and loopback
access. Zod and Node types default to development versions; declarations check
TypeScript 5.5.4 and the development compiler. Weekly probes can select another
compiler and current Zod 4. All consumers share disposable package-manager caches. Workspace links and unresolved local
runtime dependencies are rejected. Temporary files and listeners are cleaned up;
a pass/fail report is saved to `reports/clean-install.json` in the existing CI
artifact. After building, run just this check with `bun run test:clean-install`
or `node packages/repo-tools/src/cli.mjs clean-install`. Nothing is published.

### Coverage checks

`bun run test:coverage` runs through Turborepo, building each workspace before
its tests. MCP, Node, and HTTP use Vitest V8 coverage over every `src/**/*.ts`
file, including files not imported by tests. Thresholds apply separately to
statements, branches, functions, and lines in each package: 95% for MCP, Node, HTTP, JWT, and Clerk. A test failure or missed threshold fails CI.

Protocol runs its vendored-schema integrity test without instrumenting upstream
code. Examples run their real-process integration tests through `bun run test:examples`,
separately from library coverage. They have no coverage instrumentation or floors. Type-only and
re-export-only modules have no executable statements to measure.

Reports are written to each measured package's `coverage/` directory: terminal
summary, HTML (`coverage/index.html`), LCOV, and JSON summary. Turbo caches and
restores these reports using `outputs: ["coverage/**"]`. CI uploads available
reports as the `test-and-coverage-reports` artifact, including after test failures, for
14 days. Ordinary `bun run test` remains available without instrumentation.
Reports are generated even when tests fail (`reportOnFailure: true`).
The 95% floors leave room for defensive paths without requiring contrived tests.
Coverage measures executed code, not assertion quality or complete behavior.

CI also writes JSON test results for every workspace and a combined Actions
summary showing check outcomes, failed tests, and coverage against thresholds.
Independent test suites continue after another suite fails. The same report is
posted as a PR comment for branches in this repository by a separate job with
PR write permission; test execution retains read-only permissions. Fork PRs use
the Actions summary and downloadable artifact. Reports link to the run logs.

### Package size and dependency auditing

`bun run test:size` builds and checks the six library packages through Turbo.
Each check packs the workspace with Bun 1.3.14 into a temporary directory,
without running lifecycle scripts or publishing anything. It measures compressed
tarball bytes, unpacked file bytes, and file count, and writes the complete file
inventory and result to `packages/<name>/reports/size.json`. Runtime dependencies
are not included in these sizes. Required protocol schemas, licenses, and
provenance remain included.

`package-size.config.json` sets a packed and unpacked byte budget for each
library. Initial budgets allow approximately 20% growth above the current build,
rounded up to KiB. Either exceeded budget fails CI. The archive must retain every
declared export target, every compiled JavaScript/declaration file in `dist`, and
the protocol's schemas, licenses, and provenance explicitly listed in the config.
Missing required files and unexpected package files fail the check. Intentional growth
requires reviewing and updating the relevant budget. Size checks run uncached
to inspect the actual package contents on every run. They depend on the libraries'
own builds and still run when an unrelated application build fails.

MCP's `sourceMaps` size policy additionally requires JavaScript maps, declaration
maps, and the TypeScript sources in the archive. Verification rejects malformed
maps, missing or incorrect source targets, and missing mapping comments. Packaged
sources are limited to existing `src/**/*.ts` files; other libraries retain their
existing restrictions. MCP's budgets are 103 KiB packed and 355 KiB unpacked.
The packed limit allows approximately 20% growth above the 0.1.2 archive,
including its API documentation, package metadata, README, and changelog.
Every library archive must include its package-root README and LICENSE; protocol
and Clerk also require their package-root NOTICE files. Size budgets include the
required legal notices.

`bun run test:audit` queries Bun's advisory service for the complete `bun.lock`.
It runs outside Turbo caching because advisories change independently of Git.
High or critical findings fail the check, as do connection failures and malformed
scanner responses. The report is written to `reports/audit.json`; it does not
claim to attribute advisories to individual workspaces.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.