From f14794e412b14ff4957329bddcf6c96ef57d0e99 Mon Sep 17 00:00:00 2001 From: Keerthana Date: Sat, 8 Aug 2026 12:09:06 +0530 Subject: [PATCH 01/11] Add PII Sovereign Guardrail kit --- kits/pii-sovereign-guardrail/.gitignore | 6 + kits/pii-sovereign-guardrail/README.md | 87 +++ kits/pii-sovereign-guardrail/agent.md | 68 +++ .../pii-sovereign-guardrail/apps/.env.example | 7 + .../apps/actions/orchestrate.ts | 41 ++ .../apps/app/globals.css | 45 ++ .../apps/app/layout.tsx | 19 + .../pii-sovereign-guardrail/apps/app/page.tsx | 311 +++++++++++ .../apps/lib/lamatic-client.ts | 30 ++ .../apps/lib/local-demo.ts | 27 + .../apps/next-env.d.ts | 5 + .../apps/next.config.mjs | 4 + .../apps/package-lock.json | 495 ++++++++++++++++++ .../pii-sovereign-guardrail/apps/package.json | 22 + .../apps/tsconfig.json | 37 ++ .../constitutions/default.md | 28 + .../flows/pii-guardrail.ts | 124 +++++ .../pii-sovereign-guardrail/lamatic.config.ts | 36 ++ .../model-configs/pii-guardrail_generate.ts | 10 + .../pii-guardrail_mask-entities.ts | 10 + .../pii-guardrail_mask-entities_system.md | 27 + .../pii-guardrail_mask-entities_user.md | 3 + 22 files changed, 1442 insertions(+) create mode 100644 kits/pii-sovereign-guardrail/.gitignore create mode 100644 kits/pii-sovereign-guardrail/README.md create mode 100644 kits/pii-sovereign-guardrail/agent.md create mode 100644 kits/pii-sovereign-guardrail/apps/.env.example create mode 100644 kits/pii-sovereign-guardrail/apps/actions/orchestrate.ts create mode 100644 kits/pii-sovereign-guardrail/apps/app/globals.css create mode 100644 kits/pii-sovereign-guardrail/apps/app/layout.tsx create mode 100644 kits/pii-sovereign-guardrail/apps/app/page.tsx create mode 100644 kits/pii-sovereign-guardrail/apps/lib/lamatic-client.ts create mode 100644 kits/pii-sovereign-guardrail/apps/lib/local-demo.ts create mode 100644 kits/pii-sovereign-guardrail/apps/next-env.d.ts create mode 100644 kits/pii-sovereign-guardrail/apps/next.config.mjs create mode 100644 kits/pii-sovereign-guardrail/apps/package-lock.json create mode 100644 kits/pii-sovereign-guardrail/apps/package.json create mode 100644 kits/pii-sovereign-guardrail/apps/tsconfig.json create mode 100644 kits/pii-sovereign-guardrail/constitutions/default.md create mode 100644 kits/pii-sovereign-guardrail/flows/pii-guardrail.ts create mode 100644 kits/pii-sovereign-guardrail/lamatic.config.ts create mode 100644 kits/pii-sovereign-guardrail/model-configs/pii-guardrail_generate.ts create mode 100644 kits/pii-sovereign-guardrail/model-configs/pii-guardrail_mask-entities.ts create mode 100644 kits/pii-sovereign-guardrail/prompts/pii-guardrail_mask-entities_system.md create mode 100644 kits/pii-sovereign-guardrail/prompts/pii-guardrail_mask-entities_user.md diff --git a/kits/pii-sovereign-guardrail/.gitignore b/kits/pii-sovereign-guardrail/.gitignore new file mode 100644 index 000000000..246d974f3 --- /dev/null +++ b/kits/pii-sovereign-guardrail/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +.next/ +.env +.env.local +*.log +.vs/ diff --git a/kits/pii-sovereign-guardrail/README.md b/kits/pii-sovereign-guardrail/README.md new file mode 100644 index 000000000..2451e8648 --- /dev/null +++ b/kits/pii-sovereign-guardrail/README.md @@ -0,0 +1,87 @@ +# PII Sovereign Guardrail + +Enterprise middleware that masks personally identifiable information (PII) +before it reaches an external LLM provider (OpenAI, Anthropic, etc.), and +rehydrates it in the response — so raw personal data never leaves your +infrastructure in identifiable form. + +## The problem + +Enterprise legal and security teams routinely block GenAI rollouts because +raw user input — names, emails, phone numbers, addresses — ends up in a +third-party model vendor's logs. That's a real compliance blocker, not a +hypothetical one, for regulated industries like banking, healthcare-adjacent +SaaS, and legal tech. + +## How it works + +Two detection layers, because neither alone is honest coverage: + +1. **Layer 1 — deterministic (regex).** Catches structurally predictable + PII: emails, API keys/secrets, phone numbers, credit card numbers. Fast, + free, and reliable for well-formed matches. +2. **Layer 2 — probabilistic (LLM-based NER).** Catches unstructured PII + regex can't: names, addresses, free-text personal references. Each + detection is tagged with a confidence level. + +Both layers' detections are masked with indexed placeholders +(`[REDACTED_EMAIL_0]`, `[REDACTED_NAME_1]`, ...) before the prompt is sent +to the target model. After the model responds, the placeholders are swapped +back to their real values — a process that happens entirely within this +flow, never externally. + +See [`agent.md`](./agent.md) for the full architecture and an honest list +of what this does and does not cover, and +[`constitutions/default.md`](./constitutions/default.md) for the hard +guardrails the flow must never violate (e.g. fail closed, never persist +the token map). + +## Structure + +``` +pii-sovereign-guardrail/ +├── lamatic.config.ts # kit metadata +├── agent.md # capability doc (read this first) +├── constitutions/default.md # hard guardrails +├── flows/pii-guardrail.ts # flow graph (⚠️ see note below) +├── scripts/ # masking/rehydration logic (real, working) +├── prompts/ # Layer 2 NER prompts +├── model-configs/ # LLM configs per node +└── apps/ # Next.js demo — live masking visualization +``` + +> ⚠️ **`flows/pii-guardrail.ts` needs one manual step.** The node graph in +> that file is a best-effort scaffold of the documented Lamatic export +> shape, not a byte-for-byte real export. Before deploying: build the node +> sequence described in `agent.md` inside Lamatic Studio's visual editor, +> wire in the `@scripts` / `@prompts` / `@model-configs` files from this +> kit, deploy, then use Studio's **Export** to regenerate this file for +> real. Everything else in this kit (masking logic, prompts, demo app) is +> a complete, working implementation. + +## Running the demo locally + +```bash +cd kits/pii-sovereign-guardrail/apps +cp .env.example .env.local # fill in once you've deployed the flow in Studio +npm install +npm run dev +``` + +The app works out of the box in **demo mode** (Layer 1 only, no LLM call, +no API keys needed) so you can see the redaction pipeline immediately. +Once `PII_GUARDRAIL_FLOW_ID` is set to a real deployed flow, it automatically +switches to the full two-layer pipeline. + +## What this does NOT do + +- It is not a certified DLP system — for HIPAA/PCI-scope data, pair it with + dedicated compliance tooling. +- Layer 2 is probabilistic. It significantly improves coverage over regex + alone but is not a guarantee of catching every unstructured PII mention. +- It does not provide audit logging by itself — pair it with your existing + observability stack (e.g. Langfuse, which Lamatic already integrates with). + +## Tags + +`security` `compliance` `pii` `data-sovereignty` `middleware` `enterprise` diff --git a/kits/pii-sovereign-guardrail/agent.md b/kits/pii-sovereign-guardrail/agent.md new file mode 100644 index 000000000..17d7eca39 --- /dev/null +++ b/kits/pii-sovereign-guardrail/agent.md @@ -0,0 +1,68 @@ +# PII Sovereign Guardrail — Agent Identity + +## What this agent does + +The PII Sovereign Guardrail sits between your application and any external LLM +provider (OpenAI, Anthropic, etc.). It intercepts outbound prompts, masks +personally identifiable information (PII) before the prompt ever leaves your +infrastructure, sends the sanitized prompt to the target model, and then +rehydrates the original values back into the response before it's returned +to the caller. + +The goal isn't "detect 100% of PII" — no system honestly can, and any kit +that claims otherwise is overselling. The goal is to give engineering and +compliance teams a **documented, auditable boundary**: a clear answer to +"what does this catch, and what doesn't it catch" so they can make an +informed decision about what still needs a human review step. + +## Capabilities + +1. **Deterministic masking (Layer 1)** — pattern-based detection for + structurally predictable PII: email addresses, API keys / secret tokens, + phone numbers, credit card numbers. This layer is fast, free, and has + effectively zero false negatives for well-formed instances of these + patterns. +2. **Probabilistic masking (Layer 2)** — an LLM-based named-entity + recognition pass that catches unstructured PII regex structurally cannot: + personal names, physical addresses, and free-text personal references + ("my account under John Smith", "reach me at..."). Each detection carries + a confidence label. +3. **Token re-hydration** — a per-request token map (never persisted, + never sent externally) restores the original values into the model's + response before it reaches the caller. +4. **Redaction receipt** — the response includes a `tokensRedacted` count + and a breakdown by layer/type, so callers can audit what was masked on + every request. + +## What this agent is NOT + +- Not a replacement for a proper DLP (Data Loss Prevention) system in + regulated environments (HIPAA/PCI-scope data needs dedicated tooling). +- Not guaranteed to catch every unstructured mention of PII — Layer 2 + is probabilistic and should be treated as a strong second line of + defense, not a certainty. +- Not a logging/audit-trail solution by itself — pair it with your existing + observability stack if you need compliance-grade audit logs. + +## Flow + +`flows/pii-guardrail.ts` implements: + +``` +rawUserPrompt, targetModel + │ + ▼ +[codeNode] maskDeterministic → regex pass: emails, keys, phones, cards + │ + ▼ +[LLMNode] maskEntities → NER pass: names, addresses, free-text PII + │ + ▼ +[LLMNode] generate → sends masked prompt to targetModel + │ + ▼ +[codeNode] rehydrate → restores original values from token map + │ + ▼ +secureResponse, tokensRedacted +``` diff --git a/kits/pii-sovereign-guardrail/apps/.env.example b/kits/pii-sovereign-guardrail/apps/.env.example new file mode 100644 index 000000000..845f4efc0 --- /dev/null +++ b/kits/pii-sovereign-guardrail/apps/.env.example @@ -0,0 +1,7 @@ +# Get these from Lamatic Studio → Settings → API Keys (see repo CONTRIBUTING.md) +LAMATIC_API_KEY= +LAMATIC_PROJECT_ID= +LAMATIC_API_URL= + +# Flow ID for the deployed pii-guardrail flow (Studio → Flow → Details panel) +PII_GUARDRAIL_FLOW_ID= diff --git a/kits/pii-sovereign-guardrail/apps/actions/orchestrate.ts b/kits/pii-sovereign-guardrail/apps/actions/orchestrate.ts new file mode 100644 index 000000000..5fa329808 --- /dev/null +++ b/kits/pii-sovereign-guardrail/apps/actions/orchestrate.ts @@ -0,0 +1,41 @@ +"use server"; +import { guardrailFlowId, createLamaticClient } from "../lib/lamatic-client"; + +export interface GuardrailResult { + secureResponse: string; + maskedPromptSent: string; + tokensRedacted: { + total: number; + deterministic: number; + probabilistic: number; + }; + // Populated only in local demo mode (no deployed flow ID yet), so + // reviewers can see the redaction pipeline working before wiring up + // a real Lamatic Studio deployment. + demoMode?: boolean; +} + +export async function runGuardrail( + rawUserPrompt: string, + targetModel: string +): Promise { + if (!guardrailFlowId) { + // No deployed flow yet — fall back to a local demo so the app is + // still usable out of the box. Swap this out once PII_GUARDRAIL_FLOW_ID + // is set in .env.local. + const { runLocalDemoGuardrail } = await import("../lib/local-demo"); + return { ...runLocalDemoGuardrail(rawUserPrompt), demoMode: true }; + } + + const lamatic = createLamaticClient(); + const response = await lamatic.executeFlow(guardrailFlowId, { + rawUserPrompt, + targetModel + }); + return { + secureResponse: response.secureResponse, + maskedPromptSent: response.maskedPromptSent, + tokensRedacted: response.tokensRedacted, + demoMode: false + }; +} \ No newline at end of file diff --git a/kits/pii-sovereign-guardrail/apps/app/globals.css b/kits/pii-sovereign-guardrail/apps/app/globals.css new file mode 100644 index 000000000..08831bf61 --- /dev/null +++ b/kits/pii-sovereign-guardrail/apps/app/globals.css @@ -0,0 +1,45 @@ +:root { + --bg: #0c0f12; + --panel: #14181d; + --panel-raised: #191e24; + --border: #262b31; + --text: #e9ecef; + --text-dim: #8b939c; + --accent: #34d8a6; + --accent-dim: #1f7a5c; + --redact: #eb6a4e; + --redact-bar: #05070a; + --font-ui: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; + --font-mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, + monospace; +} + +* { + box-sizing: border-box; +} + +html, +body { + padding: 0; + margin: 0; + background: var(--bg); + color: var(--text); + font-family: var(--font-ui); +} + +body { + min-height: 100vh; +} + +::selection { + background: var(--accent-dim); + color: white; +} + +button { + font-family: inherit; +} + +a { + color: var(--accent); +} diff --git a/kits/pii-sovereign-guardrail/apps/app/layout.tsx b/kits/pii-sovereign-guardrail/apps/app/layout.tsx new file mode 100644 index 000000000..48836c2a4 --- /dev/null +++ b/kits/pii-sovereign-guardrail/apps/app/layout.tsx @@ -0,0 +1,19 @@ +import "./globals.css"; + +export const metadata = { + title: "PII Sovereign Guardrail — Lamatic AgentKit", + description: + "Enterprise middleware that masks PII before it reaches an external LLM, and rehydrates it in the response." +}; + +export default function RootLayout({ + children +}: { + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} diff --git a/kits/pii-sovereign-guardrail/apps/app/page.tsx b/kits/pii-sovereign-guardrail/apps/app/page.tsx new file mode 100644 index 000000000..1f69262a9 --- /dev/null +++ b/kits/pii-sovereign-guardrail/apps/app/page.tsx @@ -0,0 +1,311 @@ +"use client"; + +import { useState } from "react"; +import { runGuardrail, type GuardrailResult } from "../actions/orchestrate"; + +const EXAMPLE_PROMPT = + "Hi, this is John Whitfield. My email is john.whitfield@acme-corp.com and my number is (415) 555-0192. Can you draft a reply to my landlord about the lease at 42 Elm Street, Austin?"; + +const MODELS = ["gpt-4o-mini", "gpt-4o", "claude-sonnet-4-6"]; + +function RedactedText({ text }: { text: string }) { + // Splits on [REDACTED_TYPE_n] placeholders and renders them as literal + // redaction bars — the signature visual for this kit. Nothing under a + // bar left the building in its real form. + const parts = text.split(/(\[REDACTED_[A-Z_]+_\d+\])/g); + return ( + + {parts.map((part, i) => { + const match = part.match(/^\[REDACTED_([A-Z_]+)_\d+\]$/); + if (!match) return {part}; + return ( + + {match[1]} + + ); + })} + + ); +} + +export default function Page() { + const [rawPrompt, setRawPrompt] = useState(EXAMPLE_PROMPT); + const [targetModel, setTargetModel] = useState(MODELS[0]); + const [loading, setLoading] = useState(false); + const [result, setResult] = useState(null); + const [error, setError] = useState(null); + + async function handleRun() { + setLoading(true); + setError(null); + try { + const res = await runGuardrail(rawPrompt, targetModel); + setResult(res); + } catch (err) { + setError(err instanceof Error ? err.message : "Something went wrong."); + } finally { + setLoading(false); + } + } + + return ( +
+
+ LAMATIC AGENTKIT · SECURITY LAYER +
+

+ PII Sovereign Guardrail +

+

+ Raw personal data never leaves your infrastructure. Everything + under a bar below is masked before it reaches an external model, + and restored only in the final response. +

+ +
+ {/* Input panel */} +
+ +