MemClaw / docs
Tutorials

Content Policy: PII screening & the business-vs-personal gate

Configure the dashboard's Content Policy tab — screen every write for PII, PCI & secrets, and keep personal content out of the shared corporate graph.

Governed memory means deciding what should never land in the shared store in the first place. Two questions are worth asking on every write:

  • Does this leak PII? An email, a card number, an API key copied into a memory crosses a team boundary and becomes a recall away from anyone.
  • Is this even business content? A personal aside ("remind me to book a dentist") doesn't belong in the corporate knowledge graph at all.

The Content Policy tab answers both, per organization, at write time. This guide walks through every control, what each one does, and a sensible starting configuration.

Where it lives: the dashboard's Manage → Content Policy tab. It has two sub-tabs: Policy (the controls below) and Recent Actions (the audit trail of what got flagged, masked, or dropped).

Everything is opt-in. A fresh organization screens nothing — both gates default to off. You turn on what you need; nothing changes silently.

Give it a few minutes. Settings are cached per worker, so a change can take a short while to take effect across every instance.


Step 1 — Enable PII screening

The PII, PCI & Secrets card has one master switch — Enable PII screening (off by default: "Off = no screening. On = screen every write per the action below."). Turn it on, then pick what happens when something is detected.

Action on detection

ActionWhat it does
Flag onlyStores the memory with a contains_pii warning + an audit entry. Nothing is blocked or altered — a safe way to measure exposure before you enforce. (The default when you first enable screening.)
MaskRedacts the sensitive spans in place and stores the rest. jane@acme.com becomes a redacted span; the surrounding memory survives.
DropRejects the whole write — nothing persists. The caller gets a 422.

A good rollout is Flag only → review Recent Actions for a week → switch to Mask or Drop once you see what your agents actually write.

Categories

Seven detectors, each a checkbox: Email addresses · Phone numbers · Payment cards (PCI) · IBAN / bank accounts · National IDs (SSN, etc.) · API keys · Secrets / credentials.

Leave them all unchecked to screen everything — that's the secure default ("None selected — all categories are screened"). Only narrow the set if you have a deliberate reason to ignore a category.

Two detection paths, one setting. PII is caught two ways: a deterministic, span-aware scanner (regex + Luhn/IBAN/entropy validation) that runs before enrichment and is the only path precise enough to mask; and a free-form LLM signal during enrichment that catches PII phrased in prose. The free-form path's recall is only as good as your enrichment model — if you rely on Mask/Drop for free-form text, configure a capable enrichment.model. When the LLM path can't pinpoint spans, Mask falls back to Flag.


Step 2 — Enable the business-vs-personal gate

The Business vs Personal card classifies each write as business or personal and applies a disposition to the personal ones. Flip Enable business-vs-personal gate on ("Off = store everything. On = apply the disposition below to personal content."), then choose:

Non-business dispositionWhat happens to personal content
Store normallyNo filtering — the classification is recorded for visibility, nothing else.
Keep privateRetained only in the creating agent's scope (scope_agent) — invisible to the team/fleet.
DropNot stored at all — keeps the corporate graph clean.

"Business" is work, projects, customers, code, decisions, operations — anything an organization keeps in shared memory. "Personal" is private individual matters unrelated to work. The classifier returns one or the other on every write.


Step 3 — (Optional) Turn on the fast pre-gate

The accurate backstop runs after enrichment. The fast pre-gate is an optimization that runs before it — a cheap classifier that rejects confidently-personal content before you pay to enrich and embed it. It only matters for the Drop disposition, so its controls light up only when Drop is selected (otherwise you'll see "Applies to the Drop disposition only — ignored for the current one").

  • Enable fast pre-gate"Reject confident personal content before enrichment/embedding — cheaper and faster than the post-enrichment gate, which stays the accurate backstop." Pure cost/latency win; the post-enrichment gate still catches anything the fast pass lets through.

  • Fail closed when the classifier is unavailable — this is the compliance lever, and it's worth understanding:

    • Off (the default) — fail open. If the pre-gate classifier can't run, the write is stored and the post-enrichment gate is relied on as the backstop. Availability over strictness.
    • On — fail closed. If the classifier can't run, the write is rejected with a 503. Strictness over availability.

    Treat the pre-gate as a hard control? Turn fail-closed on — otherwise a classifier outage silently lets personal content through the fast path. Want writes to never blocked by an LLM hiccup? Leave it off.


Step 4 — Watch it work: Recent Actions

The Recent Actions sub-tab is the audit trail of every enforcement decision — so "what is the policy actually catching?" is a tab, not a guess. You'll see entries like:

  • pii_flag / pii_mask / pii_drop — PII detected and handled per your action.
  • nonbusiness_keep_private / nonbusiness_drop — personal content scoped down or rejected by the post-enrichment gate.
  • nonbusiness_pregate_drop — rejected early by the fast pre-gate.
  • nonbusiness_pregate_unavailable — a fail-closed 503 because the classifier was down.

This is where you confirm a rollout before tightening it — start in Flag / Store, read the log, then enforce.


A sensible starting point

SettingStart withTighten to
PII screeningOn, Flag only, all categoriesMask (or Drop for regulated data)
Categoriesall (none checked)narrow only with a reason
Business-vs-personalOn, Store normallyKeep private or Drop
Fast pre-gateoffOn once you move to Drop
Fail closedoffOn if the gate is a compliance control

Enforce only after Recent Actions shows you what real traffic looks like.


Configuring it without the dashboard

The tab edits per-organization settings in core-api. Self-hosted? Set the same keys directly via PUT /api/settings?tenant_id=<org> with a partial governance block (unsent keys are left unchanged):

{
  "governance": {
    "pii": {
      "enabled": true,
      "action": "mask",
      "categories": { "email": true, "credit_card": true }
    },
    "non_business": {
      "enabled": true,
      "disposition": "drop",
      "pregate": { "enabled": true, "fail_closed": true }
    }
  }
}

Defaults are opt-in (enabled is false everywhere). Stick to the allowed values or the save is rejected with a 422:

KeyType / allowed valuesDefault
governance.pii.enabledboolfalse
governance.pii.action"flag" | "mask" | "drop""flag"
governance.pii.categories.<name> — one per category (email, phone, credit_card, iban, national_id, api_key, secret)boolfalse (none ⇒ all screened)
governance.non_business.enabledboolfalse
governance.non_business.disposition"store" | "keep_private" | "drop""store"
governance.non_business.pregate.enabledboolfalse
governance.non_business.pregate.fail_closedboolfalse (fail-open)

What you've got

Two gates on the front door of shared memory, both off until you ask for them:

  • PII screening — flag, mask, or drop emails, cards, IBANs, national IDs, keys, and secrets, caught before they cross a boundary.
  • The business-vs-personal gate — keep personal content out of the corporate graph, with an optional fast pre-gate and a fail-open/closed choice for when the classifier is down.
  • Recent Actions — the audit trail that turns "is the policy working?" into something you can read.

For the concepts behind this — scopes, trust tiers, keystones, and where PII detection fits — see Governed memory and the Governance concept guide.


caura-memclaw · Apache 2.0 — governed memory in the open. ⭐ Star on GitHub · Join Discord · memclaw.net