Zenith Logic Foundry

IndexProfile

An IndexProfileArtifact selects entities and fields and declares which derivative indexes each field feeds. Profiles are immutable by (name, version); change the version instead of editing an existing artifact.

Artifact fields

Field Meaning
schema_version Currently 1
name / version Immutable profile identity
source_hash Canonical profile hash; the CLI accepts "" and computes it
matcher node_labels or edge_types
fields Map from property name to BM25/vector/temporal options
created_at RFC 3339 timestamp

Matchers:

{"node_labels": {"labels": ["document"]}}
{"edge_types": {"edge_types": ["mentions"]}}

BM25 options

{
  "bm25": {
    "analyzer_id": "unicode_jieba_v1",
    "language": "en",
    "analyzer_version": 1,
    "weight": 1.0,
    "k1": 1.2,
    "b": 0.75
  }
}

The Tantivy contract pins k1=1.2, b=0.75, analyzer id unicode_jieba_v1, analyzer version 1. weight must be positive.

Vector options

Vector fields require embedding.enabled=true:

{
  "vector": {
    "model_profile": "bge_m3_dense_v1",
    "chunking": {"whole_field": {"version": 1}}
  }
}

Chunking forms:

{"explicit": {"version": 1}}
{"whole_field": {"version": 1}}
{"paragraph_heading": {"version": 1}}
{"fixed_token_window": {"version": 1, "size": 128, "overlap": 16}}

Temporal options

{"temporal": "event"}
{"temporal": "valid_from"}
{"temporal": "valid_to"}

At most one valid_from and one valid_to are allowed; valid_to requires valid_from.

Complete JSON profile

{
  "schema_version": 1,
  "name": "knowledge",
  "version": 1,
  "source_hash": "",
  "matcher": {"node_labels": {"labels": ["document"]}},
  "fields": {
    "title": {
      "bm25": {"analyzer_id": "unicode_jieba_v1", "analyzer_version": 1, "weight": 2.0, "k1": 1.2, "b": 0.75}
    },
    "body": {
      "bm25": {"analyzer_id": "unicode_jieba_v1", "analyzer_version": 1, "weight": 1.0, "k1": 1.2, "b": 0.75}
    },
    "published_at": {"temporal": "event"}
  },
  "created_at": "2026-07-15T00:00:00Z"
}

Lifecycle

Profiles can be declared in the REPL as directives:

:- index_profile(knowledge, 1, {
  matcher: { node_labels: { labels: [document] } },
  fields: { body: { bm25: { analyzer_id: "unicode_jieba_v1", analyzer_version: 1, weight: 1.0, k1: 1.2, b: 0.75 } } }
}).

:- activate_index_profile(knowledge, 1).

Or through JSON-over-STDIO (see json-stdio.md): put_index_profile, activate_index_profile, list_index_profiles, index_status, wait_indexes. Activation rebuilds and publishes the relevant generation. A profile containing vector fields is rejected while embedding is disabled.