Streaming parsers for AI interfaces.
Cacheplane helps applications render structured model output while it is still arriving. LLMs routinely stream JSON and Markdown mid-token, mid-string, mid-list, or mid-table. Traditional parsers wait for the whole document; Cacheplane gives you a typed tree that grows in place, with stable node identity so UI layers can render partial output without losing memoization.
| Package | npm | Use it for | Highlights |
|---|---|---|---|
@cacheplane/json-stream |
JSON arriving a chunk at a time from a model, socket, or tool call | Per-node partial/complete status, chunk-boundary safe, JSON Pointer lookup, zero dependencies |
|
@cacheplane/partial-json |
JSON streamed from an LLM or any incremental source | Partial strings and numbers, JSON Pointer lookup, push and pull APIs, structural-sharing snapshots | |
@cacheplane/partial-markdown |
Markdown streamed into chat, agent logs, reports, or AI writing surfaces | Headings, lists, task lists, tables, citations, link references, math, raw HTML, inline formatting, stable AST identity |
Both packages are:
- Built for Node
>=20 - TypeScript-first
- ESM and CJS bundled
- Zero runtime dependencies
- Marked side-effect free
- Published independently under
@cacheplane/*
AI products increasingly render model output as it streams: tool arguments, structured extraction results, reports, citations, markdown answers, task lists, and agent traces. The hard part is not just accepting incomplete input. The hard part is giving the UI a stable representation while the input is still changing.
Cacheplane parsers are designed around that constraint:
- Truncation tolerant: incomplete input is normal, not an exception path.
- Stable node identity: a node keeps the same object reference as future chunks update it.
- Streaming status: every public node exposes
pending | streaming | complete. - Evented updates: push-style parsers return node creation, value update, and completion events.
- Structural-sharing snapshots:
materialize()returns plain values while preserving references for unchanged subtrees.
The result is a parser layer that works naturally with React memoization, Angular OnPush, Solid signals, editor views, virtualized renderers, and custom agent UIs.
Install the package you need:
npm install @cacheplane/partial-json
npm install @cacheplane/partial-markdownParse JSON while it streams:
import { createPartialJsonParser, materialize } from '@cacheplane/partial-json';
const parser = createPartialJsonParser();
parser.push('{"items":[{"title":"Alpha"},{"title":"Bet');
const first = parser.getByPath('/items/0/title');
const second = parser.getByPath('/items/1/title');
console.log(first?.status); // "complete"
console.log(second?.status); // "streaming"
console.log(materialize(parser.root!));Parse Markdown while it streams:
import { createPartialMarkdownParser } from '@cacheplane/partial-markdown';
const parser = createPartialMarkdownParser();
parser.push('# Plan\n\n- [ ] Parse stream');
parser.push('\n- [x] Render stable tree\n');
for (const block of parser.root?.children ?? []) {
console.log(block.type, block.status);
}See the package READMEs for full API details:
Each package exposes two APIs over the same parser core.
Use this for UI streaming, agent output renderers, and anything that wants long-lived node references.
const parser = createPartialJsonParser();
const events = parser.push(chunk);
parser.root;
parser.getByPath('/path/to/node');
parser.finish();push() and finish() return parser events:
node-createdvalue-updatednode-completed
Use this for reducers, deterministic state transitions, undo/redo stacks, and tests that prefer immutable state objects.
let state = create();
state = push(state, chunk);
state = finish(state);
const value = resolve(state);packages/
json-stream/ Published package: @cacheplane/json-stream
partial-json/ Published package: @cacheplane/partial-json
partial-markdown/ Published package: @cacheplane/partial-markdown
apps/ Reserved for deployable apps
libs/ Reserved for private workspace libraries
tools/ Reserved for repo-internal scripts
docs/
specs/ Design specs for larger changes
plans/ Implementation plans for larger changes
Tests live next to package source files under packages/*/src.
Install dependencies:
pnpm installRun the full local verification suite:
pnpm verifyCommon commands:
pnpm lint
pnpm typecheck
pnpm test
pnpm test:coverage
pnpm buildPackage-scoped commands:
pnpm --filter @cacheplane/json-stream test
pnpm --filter @cacheplane/json-stream build
pnpm --filter @cacheplane/json-stream publint
pnpm --filter @cacheplane/json-stream attw
pnpm --filter @cacheplane/partial-json test
pnpm --filter @cacheplane/partial-json build
pnpm --filter @cacheplane/partial-json publint
pnpm --filter @cacheplane/partial-json attw
pnpm --filter @cacheplane/partial-markdown test
pnpm --filter @cacheplane/partial-markdown build
pnpm --filter @cacheplane/partial-markdown publint
pnpm --filter @cacheplane/partial-markdown attwBuild output is written to packages/*/dist.
Parser behavior is public API. When changing it:
- Add or update focused tests in the affected package.
- Preserve node identity across pushes unless the README explicitly says a reference can be replaced.
- Keep
pending | streaming | completetransitions intentional and tested. - Update the package README when behavior, guarantees, warnings, or unsupported syntax changes.
- Update the package
CHANGELOG.mdfor released user-visible changes. - Run
pnpm verifybefore opening a PR.
For packaging changes, also run the package's publint and attw scripts.
These catch common npm, ESM, CJS, and TypeScript declaration regressions before
publish.
Packages are versioned and released independently. Releases are tag-routed via the publish workflow:
json-stream-v0.0.4publishes@cacheplane/json-stream@0.0.4partial-json-v0.2.1publishes@cacheplane/partial-json@0.2.1partial-markdown-v0.3.2publishes@cacheplane/partial-markdown@0.3.2
See RELEASING.md for the release process.
- Open issues in the Cacheplane GitHub repository.
- Check package changelogs before upgrading:
Monorepo-level changes (CI, tooling, workspace structure) are tracked in the root CHANGELOG.md. Per-package release notes live in each package's own CHANGELOG.md.
MIT