Package Exports
- llm-stream-guard
- llm-stream-guard/audit
Readme
llm-stream-guard
Security filter for LLM streams — redact secrets and PII, enforce tool-call policy, sanitize errors. Works on raw bytes (TransformStream) and parsed event streams. Declarative JSON/YAML policies and a CLI for offline scans.
A standalone, zero-dependency TypeScript security filter for LLM proxy and agent pipelines. Byte mode: chunk-safe secret redaction on raw SSE. Event mode: tool allow/deny, arg blocking, PII & error sanitization on parsed streams. Policy files +
llm-stream-guard scanfor CI prep.
Status: Stable 1.0.0 — frozen SARIF rule IDs, onFinish stream summaries, doctor CLI, Phase 10 contract tests. Start at Getting started. See API stability and Migration 0.x → 1.0 before upgrades.
New to LLM streaming? Read Getting started (~15 min) → Concepts & glossary → Documentation map for your role.
Contents
- New to LLM streams?
- Why stream guard?
- Two modes
- Architecture
- GuardEvent model
- Violation modes
- Install
- First success in 30 seconds
- Quickstart
- Policy files & CLI
- Mode decision guide
- Documentation
- How this compares
- Non-goals
- Development
New to LLM streams?
If you have never worked with streaming LLM APIs (SSE, deltas, tool calls), start here — no prior guard knowledge required:
| Step | Doc | Diagram |
|---|---|---|
| 1 | Getting started — install, first byte guard, first tool gate | Journey |
| 2 | Concepts & glossary — SSE, GuardEvent, modes | Stream anatomy |
| 3 | Documentation map — pick a path by role (proxy dev, agent dev, CI) | — |
Full reference: Policy · CLI · Cookbook
Why stream guard?
When proxying or running agents, unsafe content leaks downstream in predictable ways:
- Secrets in text deltas — API keys, bearer tokens, JWTs echoed in model output.
- Dangerous tool args — shell injection, exfil URLs, oversized JSON before execution.
- Unauthorized tool names — models invoke tools outside your allowlist.
- Raw provider errors — internal URLs and stack traces forwarded to browsers.
Many filters scan raw bytes only and miss precise policy on assembled tool_call.done JSON. This library targets both byte and event modes with zero runtime dependencies.
- Mid-chunk splits — secrets split across TCP reads use a rolling buffer + prefix holdback (LSG-C).
- Tool policy timing — evaluate names early; validate args on
donewhen JSON is complete (LSG-T). - Violation modes —
block,warn, orauditwithonViolationfor SIEM-friendly logs.
Two modes
| Mode | API | When |
|---|---|---|
| Byte | createByteGuard() |
Proxy forwards provider-shaped SSE without parsing |
| Event | guardEvents() |
Parsed stream — assemble, AI SDK, or custom mapper |
Architecture
Raw upstream content enters through byte guard or event guard; composable rules redact or block before your proxy, UI, or tool executor sees output.
Optional pairing with llm-stream-assemble (parse → guard) — cookbook only, no npm coupling:
Lifecycle and concurrency
Create one GuardContext per stream — never share across concurrent requests. Stateless helpers (pipeGuard, internal transform pipeline) compose into stateful entry points.
Diagram sources: docs/img/ (Mermaid .mmd + committed SVG). Regenerate with pnpm diagrams:build.
GuardEvent model
Independent event union — not StreamEvent, not provider types:
| Type | Shape |
|---|---|
text |
{ type, phase: delta | done, text } |
tool_call |
{ type, phase, id?, name?, args?, argsText? } |
reasoning |
{ type, phase, text } |
error |
{ type, message, code? } |
finish |
{ type, reason? } |
Full spec: docs/proposal.MD.
Violation modes
| Mode | Byte mode (secrets) | Event mode (secrets + PII) | Tool policy |
|---|---|---|---|
block |
Redact secrets | Redact secrets/PII | Safe substitute + policy_violation finish |
warn |
Redact secrets | Redact secrets/PII | Block tool + onViolation |
audit |
Redact secrets + onViolation on match |
Redact + onViolation on match |
Pass tool through + onViolation |
Install
pnpm add llm-stream-guard
# or npm install llm-stream-guardRequirements: Node.js 18+ · Bun / Deno / Workers (Web Streams)
Maintainers: run pnpm release:prep before tagging and npm publish. GitHub Release notes from CHANGELOG.md.
First success in 30 seconds
git clone git@github.com:01laky/llm-stream-guard.git
cd llm-stream-guard
pnpm install
./scripts/setup-githooks.sh
pnpm verifyThen pipe bytes through the byte guard:
import { createByteGuard } from "llm-stream-guard";
const guarded = sourceStream.pipeThrough(createByteGuard({ redactSecrets: true, mode: "warn" }));Quickstart
Proxy (byte mode)
import { createByteGuard } from "llm-stream-guard";
return new Response(
upstream.body!.pipeThrough(
createByteGuard({ redactSecrets: true, sanitizeErrors: true, mode: "warn" }),
),
{ headers: { "Content-Type": "text/event-stream" } },
);redactSecrets and sanitizeErrors are active on createByteGuard() options.
Agent (event mode)
import {
allowTools,
blockToolArgs,
guardEvents,
redactSecrets,
sanitizeErrors,
} from "llm-stream-guard";
for await (const event of guardEvents(
parsedEvents,
{ mode: "block", onViolation: (v) => console.warn(v.rule, v.message) },
redactSecrets(),
allowTools(["search", "read_file"]),
blockToolArgs(/rm\s+-rf/),
sanitizeErrors(),
)) {
if (event.type === "tool_call" && event.phase === "done") {
await executeTool(event);
}
}Transform ordering
Recommended pipeline:
redactSecrets() → redactPII()? → allowTools/denyTools → blockToolArgs → maxToolArgsBytes → sanitizeErrors()Reversing order is explicit — see docs/integration-cookbook.md.
Policy files & CLI
Declarative policies map to the same rule factories as manual stacks. Built-in profiles: proxy-strict, agent-gate, audit-only.
Policy file (policies/agent-gate.json)
{
"version": "1",
"policyVersion": "team-alpha-v3",
"mode": "block",
"rules": [
{ "allowTools": { "names": ["search", "read_file", "grep"] } },
{ "maxToolArgsBytes": { "max": 65536 } },
{ "sanitizeErrors": {} }
]
}Programmatic (loadPolicy / createGuardFromPolicy)
import { createGuardFromPolicy, loadPolicy } from "llm-stream-guard";
const guard = createGuardFromPolicy(loadPolicy("./policies/agent-gate.json"));
for await (const event of guard.guard(parsedEvents)) {
await handle(event);
}
const byteGuard = guard.createByteGuard();CLI
npx llm-stream-guard validate policies/agent-gate.json
npx llm-stream-guard resolve policies/examples/extends-agent.json
npx llm-stream-guard scan --policy policies/agent-gate.json test/fixtures/events/
cat capture.log | npx llm-stream-guard scan --policy policies/proxy-strict.json -
npx llm-stream-guard diff policies/v1.json policies/v2.json --check
npx llm-stream-guard profiles list
npx llm-stream-guard doctor
npx llm-stream-guard audit static --policy policies/agent-gate.json --manifest tools/manifest.json| Env variable | Effect |
|---|---|
GUARD_MODE |
Override policy mode (block / warn / audit) |
GUARD_POLICY_PATH |
Default --policy path for CLI scan |
Schema reference: schemas/policy-v1.json. Example policies: policies/.
Policy pitfalls: overlapping allow/deny lists (POLICY_E009); empty allowlist with mode: block (POLICY_E010 / POLICY_E008).
Mode decision guide
Pick byte vs event mode in ~30 seconds:
Use the modes diagram above, or:
- Raw SSE to browser, no parser →
createByteGuard() - Tool gate before execute →
guardEvents()+ rule factories - Parse with assemble / AI SDK first → map to
GuardEvent, thenguardEvents()
Documentation
Start here (1.0.0)
| Guide | Audience |
|---|---|
| Getting started | First-time users — install, byte vs event, common mistakes |
| Concepts & glossary | LLM streaming vocabulary + guard terms |
| Documentation map | Learning paths by persona |
| Policy reference | All rule types, error codes, profiles |
| CLI reference | Every command, flags, exit codes |
| Troubleshooting | Symptom → cause → fix |
| Upgrade guide | 0.x → 1.0 semver jumps |
| API stability | 1.x semver guarantees |
| Migration 0.x → 1.0 | SARIF, onFinish, Action pins |
CI & static audit
Policy drift detection, static tool manifest scanning, and a composite GitHub Action for PR gates:
- CI & GitHub Action guide — matrix workflows, SARIF upload
- Static scanning — manifest formats, drift, dangerous patterns
- Pre-commit recipe — local hook with
audit static --quiet - GitHub Action README — consumer inputs/outputs
Integration cookbook (1.0.0)
End-to-end recipes for byte proxies (Hono, Express, Workers), agent tool gates, policy-driven setup, assemble/AI SDK mappers, dual-stream audit, MCP mapping, LiteLLM hooks, CI scans, and migration from regex middleware:
- Integration cookbook — 13 sections, LSG-CBK01–34
- Runnable examples registry — typechecked under
examples/(git only, not npm tarball) - Migration from regex middleware
- MCP tool gate recipe
- LiteLLM / gateway byte hook
Reference
- Product & technical proposal
- Schemas README (npm tarball)
- Security reporting · SECURITY.md
- Threat model
- Performance · SARIF rule IDs
- Testing strategy
- Publishing checklist (maintainers)
- Architecture diagrams
- How this compares
- FAQ
- Contributing
Related: llm-stream-assemble — stream parsing and assembly (separate package).
How this compares
| llm-stream-guard | Enterprise middleware | llm-stream-assemble | |
|---|---|---|---|
| Scope | Stream security filter | Broad platform | Stream parsing |
| Byte + event | Both first-class | Often bytes-only | Events (after parse) |
| Tool policy | First-class | Varies | Assembly only |
| Dependencies | Zero runtime | Varies | Zero runtime |
Full matrix: docs/comparison.md.
Non-goals
- No HTTP client, auth, or agent loop
- No tool execution or UI components
- No LLM-as-judge classifier
- No hard dependency on assemble, AI SDK, or LangChain
- No provider adapters (use assemble or your parser)
See docs/proposal.MD.
Development
pnpm install
./scripts/setup-githooks.sh
pnpm verify| Command | Description |
|---|---|
pnpm verify |
format + typecheck + build + test + fixtures + smoke |
pnpm verify:deps |
fail if runtime dependencies are added |
pnpm release:prep |
pre-tag checks (version, CHANGELOG, dist, npm pack) |
pnpm diagrams:build |
regenerate README SVGs from Mermaid sources |
pnpm fixtures:check-policies |
validate example + profile policies |
pnpm fixtures:audit-policy-registry |
policy fixture REGISTRY parity |
pnpm test |
Vitest (LSG-S/B/E/C/R/T/P/POL/CBK, LSG-REL) |
pnpm examples:typecheck |
Typecheck cookbook examples against dist/ |
pnpm examples:smoke |
minimal-node install smoke after build |
pnpm cookbook:check-examples |
examples README registry parity |
pnpm bench:smoke |
local byte/event timing (informational) |
pnpm build |
tsup → ESM + CJS + declarations |
Author
Ladislav Kostolny — 01laky@gmail.com · GitHub @01laky
License
MIT — see LICENSE. Copyright (c) 2026 Ladislav Kostolny.