Skip to content

Vocabulary API

The semantic layer (pycharter.semantic.concepts) provides types, parsers, and validators for field bindings, concept vocabularies, and lineage. Field bindings can be stored with data contracts and used for validation and governance.

See the Vocabulary guide for the conceptual overview.

Core models

FieldMapping dataclass

FieldMapping(
    version: str,
    domain_schema: str | None = None,
    field_bindings: dict[
        str, FieldBinding | FieldConceptBinding
    ] = dict(),
)

A versioned field mapping artifact for a data contract.

Maps data contract fields to ontology concepts. Supports two formats:

  • New format: domain_schema + field_bindings as FieldBinding
  • Legacy format: field_bindings as FieldConceptBinding

Attributes:

Name Type Description
version str

Field mapping version string.

domain_schema str | None

Reference to a published LinkML schema in "name:version" format. None for legacy artifacts.

field_bindings dict[str, FieldBinding | FieldConceptBinding]

Mapping of field path to its semantic annotation. Values may be FieldBinding (new) or FieldConceptBinding (legacy).

to_dict

to_dict() -> dict[str, Any]

Convert to dictionary.

Source code in src/pycharter/semantic/concepts/models.py
def to_dict(self) -> dict[str, Any]:
    """Convert to dictionary."""
    result: dict[str, Any] = {"version": self.version}
    if self.domain_schema:
        result["domain_schema"] = self.domain_schema
    result["field_bindings"] = {
        name: fb.to_dict() for name, fb in self.field_bindings.items()
    }
    return result

FieldBinding dataclass

FieldBinding(
    class_name: str,
    slot_name: str,
    tags: tuple[str, ...] = (),
    owner: str | None = None,
    lineage: Lineage | None = None,
)

Binds a physical schema field to a LinkML class and slot.

This is the class/slot-centric replacement for FieldConceptBinding. Used by the new ontology artifact format that references a published LinkML domain schema.

Attributes:

Name Type Description
class_name str

LinkML class name the field belongs to.

slot_name str

LinkML slot name within that class.

tags tuple[str, ...]

Additional field-level tags.

owner str | None

Team or person owning this field.

lineage Lineage | None

Data lineage information.

to_dict

to_dict() -> dict[str, Any]

Convert to dictionary.

Source code in src/pycharter/semantic/concepts/models.py
def to_dict(self) -> dict[str, Any]:
    """Convert to dictionary."""
    result: dict[str, Any] = {
        "class": self.class_name,
        "slot": self.slot_name,
    }
    if self.tags:
        result["tags"] = list(self.tags)
    if self.owner is not None:
        result["owner"] = self.owner
    if self.lineage is not None:
        result["lineage"] = self.lineage.to_dict()
    return result

FieldConceptBinding dataclass

FieldConceptBinding(
    concept: str,
    broader: str | None = None,
    definition: str | None = None,
    tags: tuple[str, ...] = (),
    owner: str | None = None,
    description: str | None = None,
    deprecated: bool = False,
    lineage: Lineage | None = None,
    relationships: tuple[FieldRelationship, ...] = (),
)

Semantic annotation for a single field.

Attributes:

Name Type Description
concept str

The semantic concept this field represents.

broader str | None

Parent concept in the hierarchy (deprecated -- use ontologies.yaml).

definition str | None

Human-readable definition (deprecated -- use ontologies.yaml).

tags tuple[str, ...]

Tags for categorization.

owner str | None

Team or person owning this field.

description str | None

Field-specific business description.

deprecated bool

Whether this field mapping is deprecated.

lineage Lineage | None

Data lineage information.

relationships tuple[FieldRelationship, ...]

Relationships to other fields.

to_dict

to_dict() -> dict[str, Any]

Convert to dictionary.

Source code in src/pycharter/semantic/concepts/models.py
def to_dict(self) -> dict[str, Any]:
    """Convert to dictionary."""
    result: dict[str, Any] = {
        "concept": self.concept,
    }
    if self.broader is not None:
        result["broader"] = self.broader
    if self.definition is not None:
        result["definition"] = self.definition
    if self.tags:
        result["tags"] = list(self.tags)
    if self.owner is not None:
        result["owner"] = self.owner
    if self.description is not None:
        result["description"] = self.description
    if self.deprecated:
        result["deprecated"] = self.deprecated
    if self.lineage is not None:
        result["lineage"] = self.lineage.to_dict()
    if self.relationships:
        result["relationships"] = [r.to_dict() for r in self.relationships]
    return result

Concept

Bases: BaseModel

The canonical concept model (VC-5).

Promoted from the concept-graph ConceptNode — the one shape carrying tier, slots, origin, and provenance that governance and the contribution flywheel require — absorbing the SKOS extras (alt_labels, examples, exact_match, tags, replaced_by) as optional fields.

concept_key is the stable identifier used for cross-artifact references; id is the database UUID and is None until the concept is persisted. Document serialization (ontologies.yaml / persisted concept_scheme artifacts, format "1") keeps its historical keys via :meth:to_document / :meth:from_document — the document format is a stable configuration contract; only the in-memory model changed.

from_document classmethod

from_document(data: dict[str, Any]) -> Concept

Build a canonical concept from an ontologies.yaml entry.

The document keys (id, label, definition, broader) predate VC-5 and are a stable configuration contract — they map onto the canonical field names here.

Source code in src/pycharter/semantic/concepts/models.py
@classmethod
def from_document(cls, data: dict[str, Any]) -> Concept:
    """Build a canonical concept from an ``ontologies.yaml`` entry.

    The document keys (``id``, ``label``, ``definition``,
    ``broader``) predate VC-5 and are a stable configuration
    contract — they map onto the canonical field names here.
    """
    return cls(
        concept_key=str(data["id"]),
        name=str(data.get("label", data["id"])),
        description=data.get("definition"),
        parent_concept_key=data.get("broader"),
        tier=str(data.get("tier", "free")),
        tags=tuple(data.get("tags", ())),
        alt_labels=tuple(data.get("alt_labels", ())),
        notation=data.get("notation"),
        examples=tuple(data.get("examples", ())),
        exact_match=data.get("exact_match"),
        deprecated=bool(data.get("deprecated", False)),
        replaced_by=data.get("replaced_by"),
        concept_type=data.get("concept_type"),
    )

to_document

to_document() -> dict[str, Any]

Serialize to the ontologies.yaml entry shape.

Round-trip safe with the YAML schema. tier is carried in the document (only when non-default) so an explicit governance tier survives save/load and reaches the persisted concept row that bind_field matching consults. The remaining canonical-only fields (slots, origin, provenance, timestamps) are not part of the document format and are intentionally omitted.

Source code in src/pycharter/semantic/concepts/models.py
def to_document(self) -> dict[str, Any]:
    """Serialize to the ``ontologies.yaml`` entry shape.

    Round-trip safe with the YAML schema. ``tier`` is carried in the
    document (only when non-default) so an explicit governance tier
    survives save/load and reaches the persisted concept row that
    ``bind_field`` matching consults. The remaining canonical-only
    fields (slots, origin, provenance, timestamps) are not part of
    the document format and are intentionally omitted.
    """
    result: dict[str, Any] = {"id": self.concept_key, "label": self.name}
    if self.description is not None:
        result["definition"] = self.description
    if self.parent_concept_key is not None:
        result["broader"] = self.parent_concept_key
    if self.tier != "free":
        result["tier"] = self.tier
    if self.tags:
        result["tags"] = list(self.tags)
    if self.alt_labels:
        result["alt_labels"] = list(self.alt_labels)
    if self.notation is not None:
        result["notation"] = self.notation
    if self.examples:
        result["examples"] = list(self.examples)
    if self.exact_match is not None:
        result["exact_match"] = self.exact_match
    if self.deprecated:
        result["deprecated"] = self.deprecated
    if self.replaced_by is not None:
        result["replaced_by"] = self.replaced_by
    if self.concept_type is not None:
        result["concept_type"] = self.concept_type
    return result

ConceptScheme dataclass

ConceptScheme(
    id: str,
    version: str,
    description: str = "",
    base_uri: str | None = None,
    namespace: str | None = None,
    category: str = "domain",
    concepts: list[Concept] = list(),
    relationships: list[Relationship] = list(),
)

A complete concept scheme (vocabulary).

The single vocabulary artifact (D6): what used to be a separate ConceptSchemeTemplate kind is now a scheme whose category is pattern. Concepts and their edges live side by side, so a starter vocabulary and a governed one have exactly the same shape.

Mutable because concepts are appended during parsing.

concept_names property

concept_names: list[str]

Concept keys in declaration order.

to_dict

to_dict() -> dict[str, Any]

Convert to dictionary.

The top-level format_version is the persisted artifact format (DG-2), distinct from scheme.version which is the vocabulary's content version.

Source code in src/pycharter/semantic/concepts/models.py
def to_dict(self) -> dict[str, Any]:
    """Convert to dictionary.

    The top-level ``format_version`` is the persisted artifact format
    (DG-2), distinct from ``scheme.version`` which is the vocabulary's
    content version.
    """
    result: dict[str, Any] = {
        "format_version": "1",
        "scheme": {
            "id": self.id,
            "version": self.version,
        },
        "concepts": [c.to_document() for c in self.concepts],
    }
    if self.description:
        result["scheme"]["description"] = self.description
    if self.base_uri:
        result["scheme"]["base_uri"] = self.base_uri
    if self.namespace:
        result["scheme"]["namespace"] = self.namespace
    if self.category != "domain":
        result["scheme"]["category"] = self.category
    if self.relationships:
        result["relationships"] = [
            _relationship_to_document(r) for r in self.relationships
        ]
    return result

Lineage dataclass

Lineage(
    derived_from: str | None = None,
    source_system: str | None = None,
)

Tracks the origin of a field.

Attributes:

Name Type Description
derived_from str | None

Field this was derived from (if any).

source_system str | None

System that produces this field.

to_dict

to_dict() -> dict[str, Any]

Convert to dictionary.

Source code in src/pycharter/semantic/concepts/models.py
def to_dict(self) -> dict[str, Any]:
    """Convert to dictionary."""
    return {
        "derived_from": self.derived_from,
        "source_system": self.source_system,
    }

Relationship

Bases: BaseModel

A typed, directed relationship between two concepts (VC-5 canonical).

Promoted from the concept-graph ConceptEdge: the single relationship shape shared by the graph API, the store mappers, and the codecs.

Enumerations

Concept tiers and types are metaschema-driven since VC-6 — the sets live in data/seed/vocabulary_metaschema.yaml and are served by the loader functions below (no Python enums).

get_tiers

get_tiers() -> dict[str, str]

Return all defined governance tiers with descriptions.

Source code in src/pycharter/semantic/concepts/schema_loader.py
def get_tiers() -> dict[str, str]:
    """Return all defined governance tiers with descriptions."""
    return load_vocabulary_metaschema().tiers

get_concept_types

get_concept_types() -> dict[str, str]

Return all defined concept types with descriptions.

Source code in src/pycharter/semantic/concepts/schema_loader.py
def get_concept_types() -> dict[str, str]:
    """Return all defined concept types with descriptions."""
    return load_vocabulary_metaschema().concept_types

validate_tier

validate_tier(tier: str) -> bool

Check if a governance tier is valid.

Source code in src/pycharter/semantic/concepts/schema_loader.py
def validate_tier(tier: str) -> bool:
    """Check if a governance tier is valid."""
    return tier in load_vocabulary_metaschema().tiers

validate_concept_type

validate_concept_type(kind: str) -> bool

Check if a concept type is valid.

Source code in src/pycharter/semantic/concepts/schema_loader.py
def validate_concept_type(kind: str) -> bool:
    """Check if a concept type is valid."""
    return kind in load_vocabulary_metaschema().concept_types

RelationshipType

Bases: StrEnum

Canonical relationship vocabulary (CF-6).

EQUIVALENT_TO class-attribute instance-attribute

EQUIVALENT_TO = 'equivalent_to'

Strict identity with another concept (SKOS exactMatch / OWL ≡).

CLOSE_MATCH class-attribute instance-attribute

CLOSE_MATCH = 'close_match'

Near identity (SKOS closeMatch).

RELATED_TO class-attribute instance-attribute

RELATED_TO = 'related_to'

General semantic relationship (SKOS related).

BROADER class-attribute instance-attribute

BROADER = 'broader'

The other concept is broader (SKOS broader).

NARROWER class-attribute instance-attribute

NARROWER = 'narrower'

The other concept is narrower (SKOS narrower).

SAME_AS class-attribute instance-attribute

SAME_AS = 'same_as'

Logical identity across vocabularies (OWL sameAs).

REFERENCES class-attribute instance-attribute

REFERENCES = 'references'

Foreign-key style pointer.

DERIVED_FROM class-attribute instance-attribute

DERIVED_FROM = 'derived_from'

Computed from another concept or field.

IMPLEMENTS class-attribute instance-attribute

IMPLEMENTS = 'implements'

Concrete realization of another concept.

DESCRIBES class-attribute instance-attribute

DESCRIBES = 'describes'

Property / attribute of another concept.

IS_A class-attribute instance-attribute

IS_A = 'is_a'

Kind-of relationship (taxonomy).

HAS class-attribute instance-attribute

HAS = 'has'

Composition / ownership.

DEPENDS_ON class-attribute instance-attribute

DEPENDS_ON = 'depends_on'

Functional dependency.

PRECEDES class-attribute instance-attribute

PRECEDES = 'precedes'

Temporal ordering.

CAUSES class-attribute instance-attribute

CAUSES = 'causes'

Triggers / leads to.

GOVERNS class-attribute instance-attribute

GOVERNS = 'governs'

Constrains / regulates.

Parsing

parse_field_bindings

parse_field_bindings(
    ontology_data: dict[str, Any],
) -> FieldMapping

Parse a field mapping dictionary into a FieldMapping.

Auto-detects whether the payload uses the new LinkML-backed format (domain_schema + class/slot bindings) or the legacy concept-centric format (fields + concept bindings).

Parameters:

Name Type Description Default
ontology_data dict[str, Any]

Field mapping data as dictionary.

required

Returns:

Type Description
FieldMapping

FieldMapping with parsed bindings.

Raises:

Type Description
OntologyError

If the data is invalid.

Source code in src/pycharter/semantic/concepts/parser.py
def parse_field_bindings(ontology_data: dict[str, Any]) -> FieldMapping:
    """Parse a field mapping dictionary into a FieldMapping.

    Auto-detects whether the payload uses the new LinkML-backed format
    (``domain_schema`` + class/slot bindings) or the legacy concept-centric
    format (``fields`` + concept bindings).

    Args:
        ontology_data: Field mapping data as dictionary.

    Returns:
        FieldMapping with parsed bindings.

    Raises:
        OntologyError: If the data is invalid.
    """
    if not isinstance(ontology_data, dict):
        raise OntologyError(
            f"Field mapping data must be a dictionary, got {type(ontology_data).__name__}"
        )

    if "domain_schema" in ontology_data:
        return _parse_new_format(ontology_data)
    return _parse_legacy_format(ontology_data)

parse_field_bindings_file

parse_field_bindings_file(file_path: str) -> FieldMapping

Load and parse a field mapping file (YAML or JSON).

Parameters:

Name Type Description Default
file_path str

Path to field mapping file.

required

Returns:

Type Description
FieldMapping

FieldMapping with parsed bindings.

Raises:

Type Description
OntologyError

If the file cannot be read or parsed.

Source code in src/pycharter/semantic/concepts/parser.py
def parse_field_bindings_file(file_path: str) -> FieldMapping:
    """Load and parse a field mapping file (YAML or JSON).

    Args:
        file_path: Path to field mapping file.

    Returns:
        FieldMapping with parsed bindings.

    Raises:
        OntologyError: If the file cannot be read or parsed.
    """
    path = Path(file_path)

    if not path.exists():
        raise OntologyError(f"Ontology file not found: {file_path}", path=file_path)

    suffix = path.suffix.lower()

    if suffix in (".jsonld", ".json"):
        return _parse_jsonld_file(path, file_path)

    if suffix not in (".yaml", ".yml"):
        raise OntologyError(
            f"Unsupported file format: {suffix}. "
            "Supported: .yaml, .yml, .jsonld, .json",
            path=file_path,
        )

    try:
        with open(path, encoding="utf-8") as fh:
            data = yaml.safe_load(fh)
    except yaml.YAMLError as exc:
        raise OntologyError(f"Invalid YAML: {exc}", path=file_path) from exc

    if not isinstance(data, dict):
        raise OntologyError(
            f"Ontology file must contain a dictionary, got {type(data).__name__}",
            path=file_path,
        )

    return parse_field_bindings(data)

Validation

validate_field_mapping

validate_field_mapping(
    artifact: FieldMapping,
) -> list[dict[str, str]]

Validate a FieldMapping instance.

Performs the same checks as validate_field_mapping_payload but on a parsed artifact.

Parameters:

Name Type Description Default
artifact FieldMapping

Parsed FieldMapping.

required

Returns:

Type Description
list[dict[str, str]]

List of error dicts with 'path' and 'message' keys.

list[dict[str, str]]

Empty list means valid.

Source code in src/pycharter/semantic/concepts/validator.py
def validate_field_mapping(artifact: FieldMapping) -> list[dict[str, str]]:
    """Validate a FieldMapping instance.

    Performs the same checks as validate_field_mapping_payload but on a
    parsed artifact.

    Args:
        artifact: Parsed FieldMapping.

    Returns:
        List of error dicts with 'path' and 'message' keys.
        Empty list means valid.
    """
    return validate_field_mapping_payload(artifact.to_dict())

validate_field_mapping_payload

validate_field_mapping_payload(
    ontology_data: dict[str, Any],
) -> list[dict[str, str]]

Validate raw field mapping data before parsing.

Checks structural requirements: - Must have 'version' field - Must have 'field_bindings' dict - Each field must have 'concept' - Relationship types must be valid - No circular broader references

Parameters:

Name Type Description Default
ontology_data dict[str, Any]

Raw field mapping dictionary.

required

Returns:

Type Description
list[dict[str, str]]

List of error dicts with 'path' and 'message' keys.

list[dict[str, str]]

Empty list means valid.

Source code in src/pycharter/semantic/concepts/validator.py
def validate_field_mapping_payload(
    ontology_data: dict[str, Any],
) -> list[dict[str, str]]:
    """
    Validate raw field mapping data before parsing.

    Checks structural requirements:
    - Must have 'version' field
    - Must have 'field_bindings' dict
    - Each field must have 'concept'
    - Relationship types must be valid
    - No circular broader references

    Args:
        ontology_data: Raw field mapping dictionary.

    Returns:
        List of error dicts with 'path' and 'message' keys.
        Empty list means valid.
    """
    errors: list[dict[str, str]] = []

    if not isinstance(ontology_data, dict):
        errors.append({"path": "", "message": "Ontology must be a dictionary"})
        return errors

    # Check version
    if "version" not in ontology_data:
        errors.append(
            {"path": "version", "message": "Missing required field 'version'"}
        )

    normalized, normalization_warnings = normalize_field_bindings(ontology_data)
    for warning in normalization_warnings:
        errors.append({"path": "linkml_schema", "message": warning})

    # Check field_bindings (canonical)
    fields = normalized.get("field_bindings")
    if fields is None:
        errors.append(
            {
                "path": "field_bindings",
                "message": "Missing required field 'field_bindings'",
            }
        )
        return errors

    if not isinstance(fields, dict):
        errors.append(
            {
                "path": "field_bindings",
                "message": "'field_bindings' must be a dictionary",
            }
        )
        return errors

    valid_rel_types = set(load_vocabulary_metaschema().relationship_types.keys())

    for field_name, field_bindings in fields.items():
        prefix = f"field_bindings.{field_name}"
        # Canonical map keys are bare author field names ('quantity');
        # the normalizer converts legacy '$'-refs and this validator runs
        # on the normalized payload, so a surviving '$' key is an error.
        if str(field_name).startswith("$"):
            errors.append(
                {
                    "path": prefix,
                    "message": (
                        "Field binding key must be a plain field name "
                        "(e.g. 'quantity'), not a JSONata literal"
                    ),
                }
            )

        # Walks the artifact shape ({primary: ..., annotations: [...]})
        # as well as the flat payload. Wrapping the artifact entry in a
        # list and looking for `concept` on it reported every
        # well-formed contract as missing its concept, which is why
        # callers had to filter this rule out to validate one at all.
        walked = iter_entry_bindings(field_bindings)
        if not walked and not isinstance(field_bindings, dict | list):
            errors.append(
                {
                    "path": prefix,
                    "message": f"Field '{field_name}' must be a list of bindings",
                }
            )
            continue

        for binding_idx, field_data in enumerate(walked):
            item_prefix = f"{prefix}[{binding_idx}]"
            if not isinstance(field_data, dict):
                errors.append(
                    {
                        "path": item_prefix,
                        "message": "Binding must be a dictionary",
                    }
                )
                continue

            # concept is required (accept legacy "concept_id" as fallback)
            if not field_data.get("concept") and not field_data.get("concept_id"):
                errors.append(
                    {
                        "path": f"{item_prefix}.concept",
                        "message": "Missing required field 'concept'",
                    }
                )

            # tags must be a list
            tags = field_data.get("tags")
            if tags is not None and not isinstance(tags, list):
                errors.append(
                    {"path": f"{item_prefix}.tags", "message": "'tags' must be a list"}
                )

            # lineage must be a dict
            lineage = field_data.get("lineage")
            if lineage is not None and not isinstance(lineage, dict):
                errors.append(
                    {
                        "path": f"{item_prefix}.lineage",
                        "message": "'lineage' must be a dictionary",
                    }
                )

            # relationships must be a list of dicts with valid types
            relationships = field_data.get("relationships")
            if relationships is not None:
                if not isinstance(relationships, list):
                    errors.append(
                        {
                            "path": f"{item_prefix}.relationships",
                            "message": "'relationships' must be a list",
                        }
                    )
                else:
                    for i, rel in enumerate(relationships):
                        rel_prefix = f"{item_prefix}.relationships[{i}]"
                        if not isinstance(rel, dict):
                            errors.append(
                                {
                                    "path": rel_prefix,
                                    "message": "Relationship must be a dictionary",
                                }
                            )
                            continue
                        if (
                            not rel.get("target_field")
                            and not rel.get("target_concept_id")
                            and not rel.get("target")
                        ):
                            errors.append(
                                {
                                    "path": rel_prefix,
                                    "message": "Missing target_field, target_concept_id, or target",
                                }
                            )
                        rel_type = rel.get("type")
                        if rel_type is not None and rel_type not in valid_rel_types:
                            errors.append(
                                {
                                    "path": f"{rel_prefix}.type",
                                    "message": f"Invalid relationship type '{rel_type}'. "
                                    f"Valid: {sorted(valid_rel_types)}",
                                }
                            )

    # Check for circular broader references
    if isinstance(fields, dict):
        errors.extend(_check_circular_broader(fields))

    return errors

Taxonomy

classify_concept

classify_concept(concept_name: str) -> str

Classify a concept into a governance tier.

Core concepts get their registered tier. Unknown concepts are classified as free-form (Tier 3).

Parameters:

Name Type Description Default
concept_name str

Name of the concept

required

Returns:

Type Description
str

The governance tier for this concept

Source code in src/pycharter/semantic/concepts/taxonomy.py
def classify_concept(concept_name: str) -> str:
    """
    Classify a concept into a governance tier.

    Core concepts get their registered tier. Unknown concepts
    are classified as free-form (Tier 3).

    Args:
        concept_name: Name of the concept

    Returns:
        The governance tier for this concept
    """
    if concept_name in CORE_CONCEPTS:
        return CORE_CONCEPTS[concept_name]["tier"]
    return "free"

register_core_concept

register_core_concept(
    name: str,
    tier: str,
    broader: str | None = None,
    description: str = "",
) -> None

Register a new core concept in the taxonomy.

Parameters:

Name Type Description Default
name str

Concept name

required
tier str

Governance tier

required
broader str | None

Parent concept name (optional)

None
description str

Human-readable description

''
Source code in src/pycharter/semantic/concepts/taxonomy.py
def register_core_concept(
    name: str,
    tier: str,
    broader: str | None = None,
    description: str = "",
) -> None:
    """
    Register a new core concept in the taxonomy.

    Args:
        name: Concept name
        tier: Governance tier
        broader: Parent concept name (optional)
        description: Human-readable description
    """
    CORE_CONCEPTS[name] = {
        "tier": tier,
        "broader": broader,
        "description": description,
    }

See also

Vocabulary facade (VC-7)

One entry point for vocabulary work — schemes, concepts, suggestions, bindings, health, and context packs behind a single object:

Vocabulary

Vocabulary(
    store: SemanticStoreClient,
    *,
    session: Any | None = None,
)

Facade over the vocabulary services (VC-7).

Construct with a connected :class:SemanticStoreClient (and, for the session-backed services, a SQLAlchemy session), or use :meth:from_url to wire both from a connection string.

Source code in src/pycharter/vocabulary.py
def __init__(
    self,
    store: SemanticStoreClient,
    *,
    session: Any | None = None,
) -> None:
    """Bind the facade to a connected store and optional session."""
    self._store = store
    self._session = session

store property

The underlying semantic store client.

schemes property

schemes: SchemeArtifacts

Versioned concept-scheme artifacts (save/get/list/set_status).

concepts property

concepts: ConceptManager

Concept CRUD over the live graph.

bindings property

bindings: MappingManager

Field-to-concept mapping management.

from_url classmethod

from_url(connection_string: str) -> Vocabulary

Build a connected facade from a database URL.

Supports the semantic store's SQLite and PostgreSQL backends; the same connection powers both the store surfaces and the session-backed services.

Source code in src/pycharter/vocabulary.py
@classmethod
def from_url(cls, connection_string: str) -> Vocabulary:
    """Build a connected facade from a database URL.

    Supports the semantic store's SQLite and PostgreSQL backends;
    the same connection powers both the store surfaces and the
    session-backed services.
    """
    from pycharter.db.models.base import get_session
    from pycharter.stores.factory import open_store

    store = open_store("semantics", connection_string)
    return cls(store, session=get_session(connection_string))

health

health(**kwargs: Any) -> SemanticHealthServiceProtocol

Construct the semantic-health service bound to this session.

Source code in src/pycharter/vocabulary.py
def health(self, **kwargs: Any) -> SemanticHealthServiceProtocol:
    """Construct the semantic-health service bound to this session."""
    from pycharter.semantic.health.factory import make_semantic_health_service

    return make_semantic_health_service(
        session=self._require_session("health"), **kwargs
    )

calibration

calibration(**kwargs: Any) -> Any

Fit reliability weights from recorded suggestion decisions (VC-12).

Source code in src/pycharter/vocabulary.py
def calibration(self, **kwargs: Any) -> Any:
    """Fit reliability weights from recorded suggestion decisions (VC-12)."""
    from pycharter.semantic.ai.calibrator import fit_from_decisions

    return fit_from_decisions(self._require_session("calibration"), **kwargs)

suggestions

suggestions(
    *, calibrated: bool = False, **kwargs: Any
) -> SuggestionPipeline

Construct the AI suggestion pipeline (provider from config/env).

Parameters:

Name Type Description Default
calibrated bool

When True, fit :func:fit_from_decisions weights from this facade's session and hand them to the pipeline so confidence reflects the acceptance history (VC-12).

False
**kwargs Any

Forwarded to :class:SuggestionPipeline.

{}
Source code in src/pycharter/vocabulary.py
def suggestions(
    self, *, calibrated: bool = False, **kwargs: Any
) -> SuggestionPipeline:
    """Construct the AI suggestion pipeline (provider from config/env).

    Args:
        calibrated: When True, fit :func:`fit_from_decisions` weights
            from this facade's session and hand them to the pipeline
            so confidence reflects the acceptance history (VC-12).
        **kwargs: Forwarded to :class:`SuggestionPipeline`.
    """
    from pycharter.semantic.ai.suggestion_pipeline import SuggestionPipeline

    if calibrated and "calibration" not in kwargs:
        kwargs["calibration"] = self.calibration()
    return SuggestionPipeline(**kwargs)

context

context(
    anchor_key: str,
    *,
    scheme_id: str,
    depth: int = 2,
    token_budget: int = 2000,
    **kwargs: Any,
) -> ContextPack

Build a token-efficient context pack around an anchor concept.

Parameters:

Name Type Description Default
anchor_key str

concept_key of the anchor concept.

required
scheme_id str

UUID of the scheme whose graph is read.

required
depth int

Traversal depth around the anchor.

2
token_budget int

Approximate token ceiling for the pack.

2000
**kwargs Any

Forwarded to :func:pycharter.semantic.concepts.queries.context.build_context_pack.

{}
Source code in src/pycharter/vocabulary.py
def context(
    self,
    anchor_key: str,
    *,
    scheme_id: str,
    depth: int = 2,
    token_budget: int = 2000,
    **kwargs: Any,
) -> ContextPack:
    """Build a token-efficient context pack around an anchor concept.

    Args:
        anchor_key: ``concept_key`` of the anchor concept.
        scheme_id: UUID of the scheme whose graph is read.
        depth: Traversal depth around the anchor.
        token_budget: Approximate token ceiling for the pack.
        **kwargs: Forwarded to
            :func:`pycharter.semantic.concepts.queries.context.build_context_pack`.
    """
    from pycharter.semantic.concepts.graph.service import ConceptGraphService
    from pycharter.semantic.concepts.graph.sqlalchemy_repository import (
        SqlAlchemyConceptGraphRepository,
    )
    from pycharter.semantic.concepts.queries.context import build_context_pack

    session = self._require_session("context")
    graph = ConceptGraphService(
        SqlAlchemyConceptGraphRepository(session)
    ).get_graph(scheme_id)
    return build_context_pack(
        graph,
        anchor_key,
        depth=depth,
        token_budget=token_budget,
        **kwargs,
    )

SchemeArtifacts

SchemeArtifacts(store: SemanticStoreClient)

Versioned-artifact verbs over concept-scheme documents.

Reached as :attr:SemanticStoreClient.schemes; holds no state of its own beyond the owning store reference.

Source code in src/pycharter/semantic_store/_scheme_artifacts.py
def __init__(self, store: SemanticStoreClient) -> None:
    """Bind the surface to its owning store."""
    self._store = store

save

save(
    name: str,
    version: str,
    document: dict[str, Any],
    *,
    created_by: str | None = None,
    sync_graph: bool = True,
) -> str

Persist a scheme document snapshot (and sync the live graph).

Parameters:

Name Type Description Default
name str

Scheme key (exact; no normalization is applied).

required
version str

Content version string.

required
document dict[str, Any]

concept_scheme document ({format_version, scheme, concepts}).

required
created_by str | None

Audit author.

None
sync_graph bool

When True (default) the live concept graph is upserted to match the saved document.

True

Returns:

Type Description
str

Snapshot ID.

Raises:

Type Description
ArtifactExistsError

On a duplicate (name, version).

UnsupportedFormatVersion

For an unknown format_version.

Source code in src/pycharter/semantic_store/_scheme_artifacts.py
def save(
    self,
    name: str,
    version: str,
    document: dict[str, Any],
    *,
    created_by: str | None = None,
    sync_graph: bool = True,
) -> str:
    """Persist a scheme document snapshot (and sync the live graph).

    Args:
        name: Scheme key (exact; no normalization is applied).
        version: Content version string.
        document: ``concept_scheme`` document
            (``{format_version, scheme, concepts}``).
        created_by: Audit author.
        sync_graph: When True (default) the live concept graph is
            upserted to match the saved document.

    Returns:
        Snapshot ID.

    Raises:
        ArtifactExistsError: On a duplicate ``(name, version)``.
        UnsupportedFormatVersion: For an unknown ``format_version``.
    """
    gated = upgrade("concept_scheme", document)
    # Validate the document parses before persisting anything.
    scheme = scheme_from_document(gated)
    # Stores persist the section document (KM-6: the manifest
    # envelope is the file format, not the store format).
    stored = {"format_version": "1", **unwrap_manifest("concept_scheme", gated)}
    snapshot_id = self._store.store_scheme_document(
        name, version, stored, author=created_by
    )
    if sync_graph:
        self._sync_graph(name, version, scheme, author=created_by or "api")
    return snapshot_id

get

get(
    name: str, version: str | None = None
) -> dict[str, Any] | None

Return the envelope for a snapshot (latest when unpinned).

Source code in src/pycharter/semantic_store/_scheme_artifacts.py
def get(self, name: str, version: str | None = None) -> dict[str, Any] | None:
    """Return the envelope for a snapshot (latest when unpinned)."""
    row = self._store.get_scheme_document(name, version)
    return _envelope(row) if row else None

list

list(name: str | None = None) -> list[dict[str, Any]]

Return envelope summaries (no document bodies).

Source code in src/pycharter/semantic_store/_scheme_artifacts.py
def list(self, name: str | None = None) -> list[dict[str, Any]]:
    """Return envelope summaries (no document bodies)."""
    return [_envelope(r) for r in self._store.list_scheme_documents(name)]

list_versions

list_versions(name: str) -> list[str]

Return stored versions for name, version-sorted.

Source code in src/pycharter/semantic_store/_scheme_artifacts.py
def list_versions(self, name: str) -> list[str]:
    """Return stored versions for ``name``, version-sorted."""
    return self._store.list_scheme_document_versions(name)

set_status

set_status(
    name: str,
    version: str,
    status: str,
    *,
    updated_by: str | None = None,
) -> None

Set a snapshot's lifecycle status.

Source code in src/pycharter/semantic_store/_scheme_artifacts.py
def set_status(
    self,
    name: str,
    version: str,
    status: str,
    *,
    updated_by: str | None = None,
) -> None:
    """Set a snapshot's lifecycle status."""
    self._store.set_scheme_document_status(
        name, version, status, updated_by=updated_by
    )