Skip to content

NERB Schema Reference

This document describes the public JSON-compatible contracts for NERB banks, extraction records, replacement databases, anonymization responses, eval refs, YAML detector configs, and shared diagnostic objects. The runtime source of truth is the code in src/nerb/schema.py, src/nerb/extraction.py, src/nerb/replacements_schema.py, src/nerb/deanonymization.py, src/nerb/reports.py, and src/nerb/evals.py.

Shared Rules

IDs use this pattern:

^[a-z][a-z0-9_]{0,79}$

IDs apply to bank IDs, entity IDs, name IDs, pattern IDs, and batch document_id values. Status values are draft, active, inactive, and deprecated. Regex flag values are ASCII, IGNORECASE, MULTILINE, DOTALL, and VERBOSE. Unicode normalization values are none, NFC, and NFKC.

metadata fields are JSON objects whose values must be JSON-compatible. Metadata above 16 KiB produces a warning; metadata above 1 MiB is an error. Descriptions are capped at 2,000 characters. Pattern values are capped at 10,000 characters.

eval_refs can appear on a bank, entity, name, or pattern. Each value is a non-empty string. Local eval execution requires relative paths under the eval base path; absolute paths, parent traversal outside the base path, remote URIs, non-regular files, and invalid UTF-8 are rejected.

JSON Bank

A JSON bank is the main agent and service format. It stores authoring metadata plus extractable literal and regex patterns in one validated object.

Top-Level Bank

Field Type Required Notes
schema_version string yes Must be nerb.bank.v1.
id ID string yes Stable bank ID.
name string yes Human-readable bank name.
description string yes Up to 2,000 characters.
version string yes Bank authoring version, independent from package version.
status status string yes Extraction includes active banks by default.
created_at string yes Timestamp string; format is not schema-enforced.
updated_at string yes Timestamp string; format is not schema-enforced.
unicode_normalization string yes none, NFC, or NFKC.
default_regex_flags array of flag strings yes Bank-level default regex flags.
entities object yes At least one entity keyed by entity ID.
metadata object yes JSON-compatible metadata.
eval_refs array of strings no Local JSONL eval references.

Additional top-level properties are rejected.

Entity

Each entity is stored under entities.<entity_id>.

Field Type Required Notes
description string yes Up to 2,000 characters.
status status string yes Extraction includes active entities by default.
regex_flags array of flag strings yes Entity-level regex flags.
names object yes At least one name keyed by name ID.
metadata object yes JSON-compatible metadata.
eval_refs array of strings no Entity-scoped JSONL eval references.

Additional entity properties are rejected.

Name

Each name is stored under entities.<entity_id>.names.<name_id>.

Field Type Required Notes
canonical string yes Canonical name returned as canonical_name.
description string yes Up to 2,000 characters.
status status string yes Extraction includes active names by default.
patterns object yes At least one pattern keyed by pattern ID.
metadata object yes JSON-compatible metadata.
eval_refs array of strings no Name-scoped JSONL eval references.

Additional name properties are rejected.

Pattern

Each pattern is stored under entities.<entity_id>.names.<name_id>.patterns.<pattern_id>.

Field Type Required Notes
kind string yes literal or regex.
value string yes Non-empty pattern value, up to 10,000 characters.
description string yes Up to 2,000 characters.
status status string yes Extraction includes active patterns by default.
priority integer yes Lower priority wins report overlap resolution.
metadata object yes JSON-compatible metadata.
eval_refs array of strings no Pattern-scoped JSONL eval references.

Literal patterns also require:

Field Type Required Notes
case_sensitive boolean yes Literal case behavior.
normalize_whitespace boolean yes Whether literal whitespace is normalized.
left_boundary string yes none or word.
right_boundary string yes none or word.

Regex patterns also require:

Field Type Required Notes
regex_flags array of flag strings yes Pattern-level regex flags.

Literal patterns must not include regex_flags. Regex patterns must not include case_sensitive, normalize_whitespace, left_boundary, or right_boundary. Additional pattern properties are rejected.

Minimal Complete Bank

{
  "schema_version": "nerb.bank.v1",
  "id": "company_entities",
  "name": "Company Entities",
  "description": "Companies to recognize in internal documents.",
  "version": "2026.06.24",
  "status": "active",
  "created_at": "2026-06-24T00:00:00Z",
  "updated_at": "2026-06-24T00:00:00Z",
  "unicode_normalization": "none",
  "default_regex_flags": ["IGNORECASE"],
  "entities": {
    "company": {
      "description": "Organizations.",
      "status": "active",
      "regex_flags": [],
      "names": {
        "acme_corp": {
          "canonical": "Acme Corp",
          "description": "Primary account.",
          "status": "active",
          "patterns": {
            "primary": {
              "kind": "literal",
              "value": "Acme Corp",
              "description": "Exact company alias.",
              "status": "active",
              "priority": 100,
              "case_sensitive": false,
              "normalize_whitespace": true,
              "left_boundary": "word",
              "right_boundary": "word",
              "metadata": {}
            }
          },
          "metadata": {}
        }
      },
      "metadata": {}
    }
  },
  "metadata": {}
}

Extraction Records

Direct Bank scans and config-backed CLI/MCP extraction return Rust-backed records:

Field Type Notes
entity string Entity ID or source entity name.
canonical_name string Canonical name for the matched detector.
surface_name string Surface alias for the matched detector.
string string Matched document substring.
start integer Start offset. Byte offset by default.
end integer Exclusive end offset. Byte offset by default.
offset_unit string Usually byte; direct Bank.scan_text(..., offsets="char") can return char.

JSON-bank extraction enriches each record with source IDs and captures:

Field Type Notes
entity_id string JSON-bank entity ID.
name_id string JSON-bank name ID.
pattern_id string JSON-bank pattern ID.
pattern_kind string literal or regex.
captures object Current extraction records return {}.

Example JSON-bank record:

{
  "entity": "company",
  "canonical_name": "Acme Corp",
  "surface_name": "Acme Corp",
  "string": "Acme Corp",
  "start": 13,
  "end": 22,
  "offset_unit": "byte",
  "entity_id": "company",
  "name_id": "acme_corp",
  "pattern_id": "primary",
  "pattern_kind": "literal",
  "captures": {}
}

Direct Bank records are sorted deterministically by start offset, end offset, entity, canonical name, surface name, and matched string. JSON-bank records are sorted by start offset, end offset, entity_id, name_id, pattern_id, and matched string. Batch flat records add a leading document_id field.

Extraction Responses

Single-document JSON-bank extraction returns:

Field Type Notes
bank object Bank metadata: id, version, schema_version, hash.
engine object Engine metadata: name, version, cache.
source object Source metadata. Text sources include type, length, bytes; file sources also include path.
records array JSON-bank extraction records.

Batch extraction returns:

Field Type Notes
bank object Same bank metadata as single-document extraction.
engine object Same engine metadata as single-document extraction.
source object { "type": "batch", "document_count": int, "bytes": int }.
documents array Per-document objects with document_id, source, and document-local records.
records array Flat records across documents; each record includes document_id.
summary object document_count, record_count, and documents_with_records.

Batch input documents must be objects with a valid document_id or id, and exactly one of text or file_path. Default limits are 100 documents, 10 MiB per document, and 25 MiB combined text.

Report Responses

extract_report returns extraction records plus overlap resolution and context:

Field Type Notes
bank object Bank metadata.
engine object Engine metadata.
source object Source metadata.
records array Raw JSON-bank extraction records.
resolved_records array Objects with record, explanation, and context.
overlaps array Overlap groups resolved by priority.
summary object record_count, resolved_record_count, entity_counts, and name_counts.
diagnostics array Diagnostic objects, including missing expected-match warnings.

An overlap object has id, policy, span, records, resolved_record, and dropped_records. The current public report policy is priority. Lower numeric pattern priority wins; ties prefer longer matches, earlier starts, stable IDs, and matched string ordering.

Report batch responses mirror batch extraction and add flat resolved_records, flat overlaps, and per-document report objects.

Replacement Database

A replacement database is a local JSON object with schema version nerb.replacements.v1. It stores default replacement policy, optional per-entity policy, replacement candidate sets, and assignments. When store_originals is true, the database contains sensitive originals and must be treated as sensitive local state.

Top-Level Replacement DB

Field Type Required Notes
schema_version string yes Must be nerb.replacements.v1.
id ID string yes Local database ID.
description string yes Up to 2,000 characters.
version integer yes Positive integer incremented by save operations.
created_at string yes Timestamp string; format is not schema-enforced.
updated_at string yes Timestamp string; format is not schema-enforced.
metadata object yes JSON-compatible metadata.
defaults object yes Default replacement policy.
entities object yes Per-entity policy overrides keyed by replacement entity ID.
replacement_sets object yes Pseudonym candidate sets keyed by replacement set ID.
assignments object yes Stable assignment rows keyed by opaque assignment key.

Additional top-level properties are rejected.

Replacement Policy

defaults must contain the base policy fields. replacement_set_id is optional for redaction policies, but required in the effective policy when replacement_mode is pseudonym. entities.<entity_id> may contain any non-empty subset of the same fields.

Field Type Notes
unicode_normalization string none, NFC, or NFKC.
assignment_scope string name, canonical, or surface. JSON banks usually use name; config-backed workflows use canonical or surface.
replacement_mode string redact or pseudonym.
redaction_template string Format string supporting {entity}, {ENTITY}, and {ordinal:04d}.
collision_policy string Currently error.
store_originals boolean Enables reversible de-anonymization when true.
allow_new_assignments boolean When false, unknown entities produce diagnostics instead of assignments.
replacement_set_id ID string Optional for redaction; required for effective pseudonym policies.

Assignment scopes:

  • name: uses JSON-bank entity_id and name_id; aliases share one assignment and de-anonymization restores the canonical value.
  • canonical: uses entity plus normalized canonical_name; useful for YAML detector configs.
  • surface: uses entity plus normalized matched string; useful when exact source-surface restoration matters.

Replacement Sets

Each replacement set contains description, reuse, candidates, and optional metadata. Candidates are objects with id, non-empty value, and metadata. Pseudonym mode allocates from the configured candidate set and rejects exhausted or ambiguous candidate pools.

Assignments

Assignment keys use this opaque format:

<entity>|<scope>|sha256:<64 lowercase hex>

Assignment rows contain assignment_key, entity_id, identity, replacement, redaction, timestamps, use_count, and metadata. original is present only when the effective policy stores originals. Fingerprints, assignment keys, source IDs, originals, replacement values, and hashes are linkable or sensitive. Default CLI response metadata redacts them, while the transformed text contains replacement values by design. Default Python and MCP anonymization response metadata include replacement values because those values are also present in the transformed text; they still redact originals, raw assignment keys, fingerprints, and hashes.

Anonymization Responses

anonymize_text, anonymize_file, anonymize_config_text, and anonymize_config_file return nerb.anonymize_response.v1 payloads.

Field Type Notes
schema_version string nerb.anonymize_response.v1.
bank object Safe metadata with bank_ref, schema_version, and version; hashes/IDs require sensitive metadata.
replacement_db object Safe DB metadata: replacement_db_ref, schema_version, version, modified, saved.
source object Text/file metadata. File paths are omitted by default and replaced with source_ref.
text string Transformed text.
applied_replacements array Per-replacement metadata.
summary object record_count, applied_count, and diagnostic_count.
diagnostics array Non-fatal diagnostics.

Default Python and MCP applied_replacements entries include opaque assignment_ref, entity, mode, original_span, replacement_span, and replacement. CLI output strips replacement unless --include-sensitive-metadata is set. include_originals adds original strings. include_sensitive_metadata adds raw assignment keys, source record IDs, DB data, hashes, and file paths where available.

Config-backed anonymization uses Rust Bank.scan_text() records from YAML detector configs. It does not run JSON-bank report resolution. Because config records do not include name_id, use assignment_scope: "canonical" or assignment_scope: "surface" for config-backed replacement DBs.

De-Anonymization Responses

deanonymize_text and deanonymize_file return nerb.deanonymize_response.v1 payloads.

Field Type Notes
schema_version string nerb.deanonymize_response.v1.
replacement_db object Safe DB metadata.
source object Text/file metadata. File paths are omitted by default and replaced with source_ref.
text string Restored text.
applied_restorations array Per-restoration metadata.
summary object match_count, applied_count, and diagnostic_count.
diagnostics array Non-fatal diagnostics and warnings.

Redaction tokens are restored by default. Pseudonym restoration requires restore_pseudonyms=true or --restore-pseudonyms and emits a warning because it is exact string replacement. If store_originals was false or a replacement maps to multiple originals, de-anonymization returns diagnostics instead of guessing.

Eval JSONL

Eval references are UTF-8 JSONL files. Blank lines are ignored. Each non-empty line must be one JSON object with one of these type values: positive, negative, or provenance.

Positive records require exact expected matches:

Field Type Required Notes
type string yes Must be positive.
text string yes UTF-8 text to extract from.
matches array yes Non-empty array of expected match objects.
metadata object yes JSON-compatible metadata.

Positive match objects require string, start, and end. They may also include entity, entity_id, name, name_id, pattern_id, pattern_kind, and captures. start and end are non-negative byte offsets, end >= start, and string must equal the UTF-8 text slice at [start:end]. When both entity and entity_id are present, they must agree.

Capture objects are keyed by capture name and contain only string, start, and end.

Negative records assert that scoped extraction should return no records:

Field Type Required Notes
type string yes Must be negative.
text string yes UTF-8 text to extract from.
reason string yes Human-readable reason for the negative case.
metadata object yes JSON-compatible metadata.

Provenance records are counted but do not affect pass/fail:

Field Type Required Notes
type string yes Must be provenance.
source_type string yes Provenance source category.
observed_at string yes Timestamp string; format is not schema-enforced.
evidence string yes Human-readable evidence.
metadata object yes JSON-compatible metadata.

Example eval ref:

{"type":"positive","text":"Send this to Acme Corp.","matches":[{"string":"Acme Corp","start":13,"end":22}],"metadata":{"case":"fixture_positive"}}
{"type":"negative","text":"The acme of performance was impressive.","reason":"Common-word false positive guard.","metadata":{}}
{"type":"provenance","source_type":"crm","observed_at":"2026-06-03T00:00:00Z","evidence":"Fixture eval record for Acme Corp.","metadata":{}}

Eval Responses

eval_bank returns:

Field Type Notes
summary object passed, positive and negative totals, and failure counts.
by_entity object Counts keyed by entity ID.
by_name object Counts keyed by entity_id/name_id.
by_pattern object Counts keyed by entity_id/name_id/pattern_id.
provenance object Total provenance count and counts by source_type.
failures array Eval ref, record index, record type, expected/actual data, and diagnostics.

Diagnostic Objects

Diagnostics are JSON objects with stable core fields:

Field Type Required Notes
severity string yes error, warning, or info.
code string yes Stable diagnostic code such as schema.required or eval.positive_failed.
path string yes JSON Pointer-style path or an empty string.
message string yes Human-readable diagnostic message.
why string no Optional explanation.
suggested_fix string no Optional fix guidance.
suggested_patch array no Optional RFC 6902 JSON Patch operations.
metadata object no Optional JSON-compatible metadata.

YAML Detector Config

YAML detector configs are compact maps used by config-backed CLI and MCP extraction:

ARTIST:
  _flags: IGNORECASE
  Pink Floyd: 'Pink\sFloyd'
  The Who: '[Tt]he\sWho'

GENRE:
  _flags: [IGNORECASE, MULTILINE]
  Rock: '(?:progressive\s)?rock'

The top level must be a mapping of non-empty entity names to mappings. Each entity mapping must contain at least one detector pattern. _flags is reserved for regex flags and may be a flag string or an array of flag strings. All other keys are non-empty detector names and all pattern values must be regex strings.

Empty top-level configs are valid for config authoring, but every non-empty entity must contain at least one detector pattern. Config extraction compiles through the same Rust-backed Bank scanner and returns the direct record schema above.