---
title: Dataflow devtool
description: Generate Kovo dataflow graphs, mount the visual devtool, and query the same cards through MCP.
order: 6.2
---

# Dataflow devtool

Kovo's repo-internal devtool turns a Kovo graph into two surfaces: a visual dataflow app and an MCP
tool named `kovo_explain`. Both render the same graph cards, so the page a developer reads and the
artifact an agent consumes stay aligned.

The `@kovojs/devtool` package is private in the current technical preview. Treat the imports below
as repository tooling examples, not public app dependencies.

## Build or capture a graph first

The devtool consumes graph JSON but does not require generated files to live under `src/generated`.
Example apps keep graph assertions in tests:

```sh
pnpm --filter @kovojs/example-commerce run build:demo
pnpm --filter @kovojs/example-crm test -- src/interactive-app.test.ts
pnpm --filter @kovojs/example-stackoverflow test -- src/interactive-app.test.ts
```

For a visual devtool host, pass the graph object or a build-produced graph file into
`buildBundle()`. The CLI writes that file at `dist/.kovo/graph.json`; the discovery rules are in
[Check current source and inspect artifacts explicitly](/guides/cli/#check-current-source-inspect-artifacts-explicitly).

## Mount it under a repo dev server

Inside this repository, the Vite plugin can mount the devtool under an existing dev server path such
as `/__kovo`:

<!-- kovo-sample: illustrative reason="The devtool package is repository-private until its Track 6 publication milestone; no public tarball exists yet." -->

```ts
import { devtoolMountPlugin } from '@kovojs/devtool/vite';

export default {
  plugins: [devtoolMountPlugin('/__kovo', { handlerModuleId: '/src/app-shell.ts' })],
};
```

Set `KOVO_DEVTOOL_BASE=/__kovo` so emitted links match the mount path, then run the dev server for
the host example you are testing. The exact package script is repo-local; it is not part of
`create-kovo`.

```sh
KOVO_DEVTOOL_BASE=/__kovo pnpm --filter @kovojs/example-devtool run dev
```

## Build a bundle directly in repo tooling

For repo tooling that owns the host, provide the graph JSON and source root:

<!-- kovo-sample: illustrative reason="The devtool package is repository-private until its Track 6 publication milestone; no public tarball exists yet." -->

```ts
import { readFileSync } from 'node:fs';
import { buildBundle } from '@kovojs/devtool';
import { createDevtoolApp } from '@kovojs/devtool/app';

const bundle = buildBundle({
  app: 'my-app',
  label: 'My App',
  graph: JSON.parse(readFileSync('./dist/.kovo/graph.json', 'utf8')),
  srcRoot: './src',
});

export const { app, nodeHandler } = createDevtoolApp({ bundles: [bundle] });
export default app;
```

The package is data-free: the host provides app graph and source root; the devtool derives node
cards, lanes, source previews, and edges from that input.

## Query the same graph through MCP

Run the MCP server over the same graph:

```sh
kovo-devtool mcp --graph ./dist/.kovo/graph.json --src ./src --label "My App"
```

`kovo_explain({ query, app?, limit? })` resolves exact node names when possible, then falls back to
deterministic BM25-ranked cards. Results include stable `kovo-explain/v1` text and structured
content for agents.

## Check that both surfaces match

Use the repo check that exercises the devtool against real graphs rather than rerunning the MCP
command above:

```sh
pnpm run check
```

When a graph assertion fails, fix the app facts first: route, query, mutation, domain, or generated
graph emission. The devtool should explain the graph you built, not patch around it.

## Next

- [Reading kovo check & kovo explain](/guides/kovo-explain/) - the graph and audit output behind
  the cards.
- [Testing](/guides/testing/) - where to keep graph assertions in app CI.

<details>
<summary>Spec & diagnostics</summary>

The graph/explain artifact contract and stable `kovo-explain/v1` text shape: SPEC §11.4. Machine-
auditable generation and authorable outputs: SPEC §1.3, Constitution #3.

API reference: [@kovojs/server](/api/server/).

</details>
