knowledge_graph package
Reviewed against commit 8a2cb42ad on 2026-10-23.
Reference: package page (55 modules, 21,436 lines, plus the context_pack subpackage) · key modules: graph_client, sync, canonical_schema, context_injector, architecture_writer, context_pack. For how this package fits the whole system, see the overview.
The story
Orchestrata's volks (agents) work on code, and code is a graph: files contain classes, classes define methods, functions call one another, modules import each other. orchestrata_ultimate.knowledge_graph exists to make that graph explicit and queryable. Its package docstring once read "backed by Neo4j graph database"; that is history. Neo4j was retired on 2026-07-27, and the graph now lives in the orchkg database on orchgraph, a Memgraph fork. "neo4j" survives only as the name of the Bolt driver package the clients import. Instead of every volk re-reading source files, the pipeline maintains one persistent graph representation of the codebase that agents can query, enrich, and audit — 55 modules in all (as of commit 8a2cb42ad), including the context_pack/ subpackage. This is the OPERATIONAL knowledge graph (orchkg) — distinct from the shared semantic/RAG graph, the memgraph database that the semantic_graph package owns. Until 2026-07 the client, syncer, config and node-mixin names carried a Neo4j prefix; they are now GraphClient, GraphSyncer, GraphClientConfig and graph_node_mixins.py.
Data enters the graph along two ingestion paths. The analysis path starts at ASTAnalyzer, which orchestrates CodeParser (Python and Prolog sources), ClassExtractor, and FunctionExtractor to turn files into the typed node dataclasses in types_nodes.py (ModuleNode, ClassNode, FunctionNode, and friends); DependencyAnalyzer adds import-level dependency edges. The bulk path is GraphSyncer in sync.py, which ingests the repo's serialized AST JSON directly, creating file/class/function nodes and DEFINES/CONTAINS/CALLS/IMPORTS relationships. Either way, everything lands in orchkg through GraphClient — a client composed from two Protocol mixins (node creation and file queries), with per-node-type Cypher mapping in nodes.py, relationship builders in relationships.py, and DDL from schema.py and, canonically, canonical_schema.py (the SPEC-106 FR-001 single source of truth for identity and merge keys). FileSynchronizer and the debounced FileWatcher keep the graph current as source changes on disk.
Once populated, the graph pays off on the read side. QueryEngine and SearchEngine are the general query/search APIs (behind the IQueryEngine and other Protocols in interfaces.py). The most important consumer is ContextInjector: before a volk works a task, it enriches the CXP packet with graph context, and its inject_for_task path runs the deterministic SPEC-106 pipeline in context_pack/ — frame the request, select and rank relevant nodes per task type, then pack them into a token budget as an editable ContextPack. After the LLM responds, GraphContextValidator checks the response against the context that was injected. Around this core sit auditing and hygiene layers: SpikeAuditor writes a graph audit trail of CXP packet routing, AnomalyDetector finds and corrects graph inconsistencies, TemporalManager and VersioningManager provide history and git-tag-style entity versions, TestResultsStore records pytest runs for impact analysis, and KGPortfolioManager handles portfolio-level views.
The package collaborates outward in several directions: it speaks CXP (the cxp package) both as an auditor of packets and as a service — server.py is the service entry point (run as the orchestrata-knowledge-graph container, port from KG_GRPC_PORT), built on CXP's endpoint config and servicer; the transport is the cxpt direct transport, since grpcio was retired on 2026-08-07 (the env key keeps its old name); it borrows the memory package's token counter for budgeted packing; it bridges into Prolog reasoning through KnowledgePrologBridge and PAMIntegration; and the kernel and orchestrator packages lean on it for volk work context, checkpoint absorption, and design/RTM storage (KGDesignStore).
Key responsibilities
- Model the codebase as a graph — turn Python/Prolog source into typed nodes (
ModuleNode,ClassNode,FunctionNode, …) and DEFINES/CONTAINS/CALLS/IMPORTS/INHERITS edges in the operational graph (orchkgon orchgraph). - Two ingestion paths — live AST analysis (
ASTAnalyzer+ extractors) and bulk serialized-AST sync (GraphSyncer), converging on one schema and one node identity. - Keep the graph fresh — debounced file watching (
FileWatcher) + re-sync (FileSynchronizer), withAnomalyDetectorcorrecting drift. - Canonical identity & schema —
canonical_schema.pyowns the deterministiccode_entity_id, merge keys, DDL, and live conformance checking (SPEC-106 FR-001). - Read surface —
QueryEngine,SearchEngine, andKGCodeContextserve the orchestrator/kernel/session subsystems. - Task-aware context injection —
ContextInjector+ the deterministiccontext_pack/pipeline (frame → select → pack) build budgeted, editableContextPacks for volk tasks;GraphContextValidatorvalidates the LLM response. - Audit, history & portfolio — CXP routing audit trail, temporal/versioned entity history, test-impact records, and portfolio dashboards.
- Outward integrations — CXP service entry point (
server.py), Prolog/PAM++ bridges, design/RTM storage (KGDesignStore).
Class diagram
The package has four principal clusters. Only public/principal classes are shown, with their real attributes and methods (generated from the AST, render-verified).
Ingestion & analysis
The live-analysis front door: ASTAnalyzer drives the extractors and CodeParser to produce the typed node dataclasses; DependencyAnalyzer derives module dependency graphs.
Storage & read surface
Everything writes through the thin async GraphClient. GraphSyncer bulk-loads serialized AST JSON; QueryEngine and SearchEngine are the read APIs on top of the same client.
Context injection (SPEC-106)
ContextInjector.inject_for_task runs the deterministic pipeline: RequestFrame frames the request, RankedSubgraph holds the selected/ranked nodes, and ContextPack is the budgeted, snapshot-hashed, editable result. GraphContextValidator checks the LLM response afterwards, returning a ValidationResult.
Audit, history & portfolio
The hygiene and analytics layer: CXP routing audit, drift detection/correction, temporal + git-tag-style versioning, test-impact records, and portfolio dashboards.
Type & inheritance hierarchy
The package's enums, exception tree, and Protocol/mixin composition (generated from the AST, render-verified):
Module dependency diagram
Internal module imports within orchestrata_ultimate.knowledge_graph (generated from the AST, render-verified):
Module inventory
| Module | Purpose |
|---|---|
__init__.py |
Package facade — code analysis, dependency tracking, temporal versioning, portfolio management over the operational graph (orchkg); formerly "backed by Neo4j". |
anomaly_detector.py |
Anomaly detection and correction for the KG (AnomalyType, Anomaly, CorrectionResult, AnomalyReport, AnomalyDetector). |
ast_analyzer.py |
AST analyzer — orchestrates CodeParser, ClassExtractor, FunctionExtractor (ASTAnalyzer). |
canonical_schema.py |
Canonical KG schema — the single DDL source (SPEC-106 FR-001): code_entity_id, get_all_ddl, apply, check, ConformanceReport. |
class_extractor.py |
Class extraction from Python AST (ClassExtractor). |
code_parser.py |
Parses Python and Prolog source files to extract structure (CodeParser, call-confidence helpers). |
config.py |
KG runtime configuration dataclasses (GraphClientConfig — formerly the Neo4j-named config class — CacheConfig, SyncConfig, QueryConfig, KnowledgeGraphConfig) — Spec 008. |
constants.py |
KG configuration constants (env-derived, no public classes/functions). |
context_injector.py |
Enriches CXP packets with graph context (TaskType, GraphContext, ContextNode, VolkContext, ContextInjector). |
adr_parser.py |
Pure text-to-dataclass parser for the ADR corpus (parse_adrs, parse_adr_file, ParsedAdr) — ontology phase 2. |
architecture_writer.py |
The converged architecture-ontology writer (ArchitectureWriter; ADR immutability enforced via AdrImmutabilityError) — ontology phase 1. |
context_validator_loop.py |
Validator feedback loop (ValidatorLoop): re-injects wider graph context and retries when the response misses core entities (Spec 008). |
conversation_consumer.py |
Conversation-capture queue consumer (SPEC-021 US-021-007): drains a Redis queue of turns into the dedicated conversation graph. |
ontology_mapping.py |
Pure mapping from live-graph labels to the canonical ontology (SOURCE_LABEL_MAP, REL_MAP, KEY_DERIVATION; Spec 106). |
project_resolver.py |
Project identity resolution (derive_project_id and a resolver) for :Project-scoped reads and writes. |
requirement_resolution.py |
Canonical requirement identity resolution (RequirementChain: Spec, Requirement, RequirementItem). |
runtime_writer.py |
Tier-H runtime signal writer (RuntimeSignalWriter: messages, gateway events, decisions, tool calls; REQ-106-066). |
semantic_bridge.py |
Bridge from the semantic/RAG graph (memgraph database) chunks to operational-graph file roots (search_semantic_roots; Spec 107). |
signal_extraction.py |
Helpers that extract file paths and entity references from runtime payloads (extract_file_paths). |
context_pack/__init__.py |
Deterministic context selector + packer subpackage (SPEC-106 FR-002/003/004). |
context_pack/cache.py |
In-memory render cache for context packs. |
context_pack/relevance.py |
Symbolic (Prolog) relevance refinement of a selected subgraph (SPEC-106 FR-006). |
context_pack/frame.py |
Deterministic request-frame analysis (FR-002): analyze_request, RequestFrame, LinkedEntity. |
context_pack/selector.py |
Per-task-type template selection + graph-signal ranking (FR-003): select, RankedNode, RankedSubgraph. |
context_pack/packer.py |
Budgeted packing + editable pack format (FR-004): pack, render, parse, validate_pack, ContextPack. |
cxp_auditor.py |
Graph audit trail for CXP packet routing (SpikeAuditor). |
dependency_analyzer.py |
Analyzes import statements to build dependency graphs (DependencyAnalyzer). |
exceptions.py |
Exception hierarchy (KnowledgeGraphError and subclasses: connection, query, schema, parse, sync, temporal, ownership). |
file_watcher.py |
Filesystem change detection with debouncing via watchfiles (FileWatcher). |
function_extractor.py |
Function extraction from Python AST — params, return types (FunctionExtractor). |
graph_context_validator.py |
Post-LLM response validator for graph-context compliance (ValidationResult, GraphContextValidator). |
history.py |
Change history for the KG (HistoryManager). |
interfaces.py |
Protocol contracts: SynchronizerProtocol, IKnowledgeGraph, ICodeAnalyzer, ITemporalManager, IQueryEngine. |
kg_context.py |
KG code-context provider (KGCodeContext). |
kg_design.py |
Design store for the spike pipeline (SessionData, RTMSnapshot, ComplianceResult, KGDesignStore). |
graph_client.py |
Graph client (GraphClient, composed from node-creation + file-query mixins); replaces the former Neo4j-named client module. |
graph_node_mixins.py |
Mixin protocols for GraphClient node ops (GraphNodeCreationMixin, GraphFileQueryMixin); replaces the former Neo4j-named mixins module. |
nodes.py |
Node wrappers: dataclass ↔ Cypher property conversion (*_node_to_cypher, cypher_record_to_node). |
pam_integration.py |
PAM++ integration for the KG (PAMIntegration). |
portfolio.py |
Portfolio management (KGPortfolioManager). |
prolog_bridge.py |
Knowledge-specific Prolog bridge (KnowledgePrologBridge). |
query_engine.py |
Query engine over the graph (QueryEngine). |
relationships.py |
Relationship Cypher builders (build_create_rel_cypher, contains_rel, defines_rel, calls_rel, inherits_rel, imports_rel). |
schema.py |
Legacy schema DDL — constraints and indexes (get_all_ddl, get_node_label). |
search.py |
Search engine over the graph (SearchEngine). |
server.py |
KG service entry point over the CXP protocol (main, _serve); port from KG_GRPC_PORT. |
sync.py |
GraphSyncer — syncs serialized AST JSON into the knowledge graph (orchkg). |
_sync_queries.py |
Read-side query mixin for GraphSyncer (QueryMixin). |
synchronizer.py |
File synchronizer (FileSynchronizer). |
temporal.py |
Temporal versioning of graph entities (TemporalManager). |
test_results_store.py |
Stores pytest results in the graph for impact analysis (TestResultRecord, TestRunRecord, TestResultsStore). |
types.py |
Single public import point for KG types (FileAnalysis, ProjectAnalysis, Dependency, DependencyGraph, ChangeEntry, Dashboard, ContextBundle, ResolutionResult). |
types_enums.py |
Enums + UTC helper (NodeType, RelationshipType, ChangeType, SyncStatus, utc_now). |
types_nodes.py |
Node dataclasses (Node, PackageNode, ModuleNode, FileNode, ClassNode, FunctionNode, PredicateNode, RuleNode, ImportNode). |
versioning.py |
Named entity versions, git-tag style (Version, VersioningManager). |
graph_client.py
(Until 2026-07 this module was neo4j_client.py.) GraphClient is the low-level graph access layer that everything else in the package ultimately writes through. It talks Bolt to orchkg using the neo4j driver package, and takes a GraphClientConfig from config.py. It is deliberately thin: rather than one monolithic class, its node-creation and file-query behaviour is factored into the two Protocol mixins in graph_node_mixins.py, and it composes them (GraphClient(GraphNodeCreationMixin, GraphFileQueryMixin)). The Cypher property mapping for each node type comes from nodes.py, relationship Cypher builders live in relationships.py, and schema DDL is applied from schema.py and canonical_schema.py. Higher layers — the query and search engines, temporal management, portfolio views — all sit on top of this client rather than talking to the driver directly. (GraphSyncer is the exception: it uses its own synchronous Bolt repository for bulk loads.)
sync.py and the file-watching loop
GraphSyncer in sync.py is the bulk ingestion engine: it takes the serialized AST JSON produced by the repo's AST serializer and materializes it in orchkg (full_sync(ast_data, project, ...)), creating file/class/function nodes and the DEFINES/CONTAINS/CALLS/IMPORTS edges between them. Its read-only queries are split out into _sync_queries.py's QueryMixin, which the syncer inherits. Keeping the graph fresh after the initial ingest is the job of synchronizer.py's FileSynchronizer together with file_watcher.py's debounced FileWatcher: when source files change on disk, the watcher batches the events and the synchronizer re-parses and re-syncs the affected files, calling on AnomalyDetector to keep the resulting graph consistent.
ast_analyzer.py and the extractors
Where the syncer consumes pre-serialized AST JSON, ASTAnalyzer is the live analysis front door. It orchestrates CodeParser — which understands both Python and Prolog sources — together with ClassExtractor and FunctionExtractor to turn a source file into the typed dataclasses defined in types_nodes.py. DependencyAnalyzer complements this by reading import statements and building module-level dependency graphs. The results of both flow into the graph through the client and syncer, so the two ingestion paths converge on the same schema and the same node identities.
context_injector.py and context_pack/
ContextInjector is where the graph earns its keep in the agent pipeline: before a volk works a task, the injector enriches the CXP packet with graph-derived context so the LLM starts with relevant code knowledge rather than a blank slate. Its inject_for_task path is backed by the deterministic SPEC-106 pipeline in context_pack/. First frame.analyze_request classifies the request and links the entities it mentions against the graph; then selector.select runs per-task-type Cypher templates and ranks the resulting nodes into a RankedSubgraph; finally packer.pack greedily fits ranked nodes into a token budget (using the memory package's token counter), producing an editable, snapshot-hashed ContextPack that can be rendered, parsed back, and validated. After the LLM responds, graph_context_validator.py closes the loop by programmatically checking that the response complies with the injected graph context.
canonical_schema.py
canonical_schema.py is the single DDL source of truth mandated by SPEC-106 FR-001. It defines the deterministic identity function code_entity_id(relpath, qualname), the canonical merge keys for each node label, DDL generation via get_all_ddl, an idempotent apply(driver), and — importantly — a live-database conformance check that reports extra constraints and non-canonical nodes as a ConformanceReport. This gives the rest of the system a way to detect drift between what the database actually contains and what the schema says it should. The older schema.py retains the legacy constraint/index DDL and node-label mapping that GraphClient, nodes.py, and relationships.py still reference.
query_engine.py and search.py
QueryEngine is the general read API over the graph — for example the volk work-context queries the kernel uses — implementing the IQueryEngine Protocol from interfaces.py, while SearchEngine provides search on top of the same GraphClient. Alongside them, kg_context.py's KGCodeContext packages code-level context for consumers outside the package. Together these form the read surface that the orchestrator, kernel, and session subsystems query, keeping the write side (syncer, analyzer) and read side of the graph cleanly separated.
Class map (generated)
Generated from the live source AST by scripts/gen-module-class-diagrams.py — do not hand-edit. Abstract classes have a green border; members listed are those defined on the class itself (inherited members excluded). Solid empty-triangle arrows = in-package inheritance; dashed arrows into dashed boxes = external/stdlib/cross-package bases; filled diamond = composition (constructed in __init__); open diamond = aggregation (annotated/injected reference); diamond edge labels name the owning attribute.