Skip to content

Schema Reference

Complete reference for every top-level key in a Kanoniv spec.

Required Structure

Every spec must contain at minimum:

yaml
api_version: kanoniv/v2
identity_version: "1.0"
entity:
  name: customer
sources:
  crm:
    adapter: csv
    location: data/contacts.csv
    primary_key: id
rules:
  - name: email_exact
    type: exact
    field: email
    weight: 1.0
decision:
  thresholds:
    match: 0.9

Top-Level Keys

KeyTypeRequiredDefaultTierDescription
api_versionstringYesLocalMust match kanoniv/v<N> (currently kanoniv/v1)
identity_versionstringYesLocalSemantic version for this spec (e.g. "1.0", "2.3.1")
entityobjectYesLocalEntity type configuration
sourcesobject | arrayYesLocalData source definitions (max 10); accepts map-style or array-style
rulesarrayYesLocalMatching rule definitions (max 50)
decisionobjectYesLocalScoring and threshold configuration
survivorshipobjectNo{ default: most_recent }LocalField survivorship strategy
blockingobjectNo{ strategy: composite, keys: [] }LocalCandidate pair blocking
metadataobjectNoLocalOwner, tags, description
governanceobjectNoCloudData governance policies
exclusionsarrayNo[]CloudRecord exclusion rules
relationsarrayNo[]CloudCross-entity relation definitions
reference_identifiersarrayNo[]CloudExternal reference ID mappings

Nested sub-keys (not top-level):

KeyNested UnderTierDescription
complianceentityCloudCompliance frameworks, PII fields, retention
hierarchyentityCloudEntity hierarchy configuration
auditdecisionCloudAudit logging configuration

Entity

The identity you're resolving. The entity name defines what kind of real-world thing your spec describes — a customer, patient, product, or vendor. This name appears in API responses, audit logs, SDK results, and everywhere the system refers to your resolved identities.

yaml
entity:
  name: customer              # Required: entity type name
  description: "B2B customers across all systems"  # Optional
FieldTypeRequiredDescription
namestringYesEntity type identifier (alphanumeric + underscore)
descriptionstringNoHuman-readable description

See Entity for compliance and hierarchy sub-blocks.

Sources

Where your data lives. Each source points to a specific data store — a CSV file, a PostgreSQL table, a Snowflake view, a dbt model — and tells the engine how to read records from it. The engine pulls records from every source, normalizes them, and feeds them into the matching pipeline. You can define up to 10 sources per spec.

yaml
sources:
  crm:
    adapter: csv
    location: data/contacts.csv
    primary_key: id
    attributes:
      name: full_name
      email: email_address
      phone: phone_number
    freshness:
      max_age_hours: 24
    schema:
      email: { type: string, pii: true }
      phone: { type: string, pii: true }
      name: { type: string }
FieldTypeRequiredDescription
namestringYesUnique source identifier (the YAML map key)
adapterstringYesAdapter type: csv, pandas, postgres, snowflake, bigquery, redshift, dbt, file, webhook, api
locationstringYesAdapter-specific location (file path, table name, connection string)
primary_keystringYesColumn used as unique record identifier
attributesmap[string, string]NoCanonical-to-source field name mapping (default: all columns, identity mapped)
freshnessobjectNoFreshness constraints (Cloud tier)
schemaobjectNoColumn type/format validation
tagsarray[string]NoSource tags for filtering
samplingobjectNoRow sampling configuration

See Sources for detailed adapter configuration.

Rules

How records are compared. Rules encode your domain knowledge about what makes two records the same entity. Each rule specifies a comparison type (exact, similarity, range, composite, or ML), the fields to compare, and a weight that reflects how strongly a match on that rule indicates a true identity match. The engine evaluates every rule against every candidate pair and aggregates the scores.

yaml
rules:
  - name: email_exact
    type: exact
    field: email
    weight: 1.0
  - name: name_fuzzy
    type: similarity
    field: name
    algorithm: jaro_winkler
    threshold: 0.88
    weight: 0.6
FieldTypeRequiredDescription
namestringYesUnique rule identifier
typestringYesexact, similarity, range, composite, ml
fieldstringYesField this rule compares
weightfloatNoScore contribution (default: 1.0)
algorithmstringConditionalRequired for similarity type
thresholdfloatConditionalRequired for similarity and range types
childrenarrayConditionalSub-rules for composite type
operatorstringConditionaland / or for composite type
normalizerstringNoPre-match normalizer: email, phone, name, nickname, domain, generic (applies to similarity and range; for exact, set inside options; also supported on Fellegi-Sunter fields)

See Rules for algorithm details and examples.

Decision

How scores become outcomes. After rules produce a weighted score for each candidate pair, the decision block determines what happens next. Pairs above the match threshold are automatically merged. Pairs between review and match go to the review queue for human verification. Pairs below review are rejected. The decision block also controls how conflicts are resolved when one record matches multiple candidates.

yaml
decision:
  scoring:
    method: weighted_sum
  thresholds:
    match: 0.9
    review: 0.7
    reject: 0.3
  conflict_strategy: prefer_high_confidence
  review_queue:
    enabled: true
    webhook: "https://hooks.example.com/review"
    sla_hours: 48
  audit:
    log_all_comparisons: false
    log_decisions: true
    log_conflicts: true
FieldTypeRequiredDefaultDescription
scoringobjectNo{ method: weighted_sum }Scoring configuration (see below)
scoring.methodstringNoweighted_sumScoring method: weighted_sum, ml_ensemble, custom
thresholds.matchfloatYesMinimum score for automatic match
thresholds.reviewfloatNoMinimum score for manual review
thresholds.rejectfloatNoBelow this score, pairs are rejected
thresholds.mergefloatNomatch * 1.5Real-time entity merge threshold (used by POST /v1/resolve/realtime)
conflict_strategystringNoprefer_high_confidenceHow to resolve conflicting matches: prefer_high_confidence, prefer_recent, manual_review
review_queueobjectNoReview queue settings
auditobjectNoAudit logging configuration (Cloud tier)

See Decision for scoring math and examples.

Survivorship

Which value wins. When multiple sources describe the same entity, survivorship determines which source's value makes it into the golden record for each field. You set a global strategy — trust CRM first, use the most recent update, or pick the most complete record — and override it per field where a different source is authoritative.

yaml
survivorship:
  default: source_priority
  overrides:
    - field: email
      strategy: most_recent
    - field: phone
      strategy: most_complete
    - field: name
      strategy: source_priority
      priority: [crm, billing, support]
FieldTypeRequiredDefaultDescription
defaultstringNomost_recentGlobal strategy: source_priority, most_recent, most_complete, aggregate, custom
overridesarrayNo[]Per-field strategy overrides
overrides[].fieldstringYesField name to override
overrides[].strategystringYesStrategy for this field
overrides[].priorityarray[string]No[]Source priority order (for source_priority)
overrides[].functionstringNoAggregate function: max, min, sum, avg, union, intersection

See Survivorship for strategy details and examples.

Blocking

How the engine reduces comparison space. Without blocking, every record is compared against every other record — O(n²) comparisons. Blocking groups records into buckets by shared field values (exact match, phonetic encoding, or n-gram overlap) and only compares records within the same bucket. This makes reconciliation feasible on large datasets.

yaml
blocking:
  strategy: composite
  keys:
    - [email]
    - [last_name, zip_code]
  fallback:
    enabled: true
    sample_rate: 0.01
FieldTypeRequiredDefaultDescription
strategystringNocompositeBlocking strategy: single, composite, lsh, ml_predicted
keysarray[array[string]]No[]Blocking key groups (each group is a list of fields)
fallbackobjectNoFallback configuration for non-blocked pairs
fallback.enabledboolNofalseEnable fallback sampling
fallback.sample_ratefloatNoSample rate for fallback pairs

Compliance

Regulatory guardrails for sensitive data. Compliance settings declare which frameworks apply (GDPR, HIPAA, SOC2, CCPA), which fields contain PII, how long records are retained, and whether audit logging is required. These settings flow through the entire pipeline — PII fields are automatically masked in non-admin API responses, and the retention policy triggers automatic cleanup.

Compliance is nested under entity, not a top-level key.

yaml
entity:
  name: customer
  compliance:                  # Cloud tier
    frameworks: [GDPR, HIPAA]
    pii_fields: [email, phone, ssn, date_of_birth]
    audit_required: true
    retention_days: 365

See Entity for full compliance reference.

Hierarchy

Parent-child relationships between entities. Hierarchies model organizational structures — a parent company with regional subsidiaries, a hospital system with individual clinics, a franchise with locations. Field values can flow from parent to child through inheritance rules, ensuring consistency across the tree without duplicating data in every record.

Hierarchy is nested under entity, not a top-level key.

yaml
entity:
  name: customer
  hierarchy:                   # Cloud tier
    parent_field: parent_company_id
    depth: 3
    inheritance: [industry, region]
FieldTypeRequiredDefaultDescription
parent_fieldstringYesField containing parent reference
depthintegerNo5Maximum hierarchy depth
inheritancearray[string]No[]Fields inherited down the hierarchy

See Entity for hierarchy configuration.

Audit

What gets logged about every decision. Audit configuration controls whether the engine records match/review/reject decisions, the per-rule scores that produced each decision, and optionally the raw field values involved. Essential for compliance reporting, debugging false positives, and understanding why any two records were or weren't merged.

Audit is nested under decision, not a top-level key.

yaml
decision:
  thresholds:
    match: 0.9
  audit:                       # Cloud tier
    log_all_comparisons: false
    log_decisions: true
    log_conflicts: true
FieldTypeRequiredDefaultDescription
log_all_comparisonsboolNofalseLog every pairwise comparison, including NoMerge (non-match) decisions
log_decisionsboolNotrueLog Merge and Review decisions (enabled by default)
log_conflictsboolNofalseLog survivorship conflict resolution outcomes

When no audit block is present, log_decisions defaults to true so Merge and Review decisions are audited automatically. When compliance.audit_required is true, all decisions are force-audited regardless of these flags.

Metadata

Informational context about the spec itself. Metadata has no effect on reconciliation — it exists for organizational purposes. Track who owns the spec, which environment it targets, when it was last updated, and what it does. Metadata is returned in API responses and included in audit logs, making it easy to trace a decision back to the spec version that produced it.

yaml
metadata:
  owner: [email protected]
  tags: [production, customer, v2]
  description: "Production customer identity spec"
  created: "2026-01-15"

Governance

Policies that enforce data quality and change management. Governance rules make certain best practices mandatory: every source must declare freshness constraints, every source must declare a schema for field-presence drift detection, and sources must carry required tags. When require_schema is enabled and drift is detected at reconciliation time, the pipeline aborts. These policies are checked during validation and enforced in CI/CD.

yaml
governance:                  # Cloud tier
  require_freshness: true
  require_schema: true
  required_tags: [production]

See Governance for policy configuration.

Exclusions

Records to filter out before matching begins. Exclusions remove test accounts, demo data, invalid records, and any other noise from the reconciliation pipeline. Excluded records never enter candidate pair generation, which improves both data quality and performance. Each exclusion targets a specific field and matches by regex pattern or an exact values list.

yaml
exclusions:                  # Cloud tier
  - field: email
    pattern: ".*@test\\.com$"
    reason: "Test accounts"
  - field: name
    values: ["Test User", "Demo Account"]
    reason: "Known test records"

Relations

Connections between different entity types. Relations don't affect how individual entities are resolved — they define how resolved entities relate to each other across specs. A customer belongs to a company, a company has invoices, an employee is part of a department. After reconciliation, these relationships enable cross-entity queries and graph-based analysis.

yaml
relations:                   # Cloud tier
  - name: company_contacts
    from_entity: customer
    to_entity: company
    join_key: company_id
    cardinality: many_to_one
    propagate_match: false

Reference Identifiers

Links to external identifier systems. Reference identifiers map your canonical records to well-known registries — DUNS numbers, LEI codes, tax IDs, VAT numbers. They serve two purposes: cross-referencing (look up a canonical entity by its DUNS number) and deterministic matching (two records sharing the same reference identifier value are immediately merged with confidence 1.0, short-circuiting all other matching rules).

yaml
reference_identifiers:       # Cloud tier
  - name: duns_number
    source: dnb
    field: duns
  - name: lei_code
    source: gleif
    field: lei

Note: The match_weight field is accepted in the spec for forward compatibility but does not currently affect scoring. All reference ID matches produce confidence 1.0. See Governance - Reference Identifiers for full details.

Validation Limits

ConstraintLimit
Max sources10
Max rules50
Max blocking keys5
Rule weight range0.0 - 1.0
Threshold range0.0 - 1.0
Max hierarchy depth10
Max exclusion patterns100

The identity and delegation layer for AI agents.