API Reference¶
This page provides a quick reference for the main qortex APIs. For detailed documentation, see the source code docstrings.
QortexClient¶
The consumer-facing protocol. All framework adapters, MCP tools, and REST API endpoints target this interface.
Protocol¶
from qortex.client import QortexClient
class QortexClient(Protocol):
def query(
self,
context: str,
domains: list[str] | None = None,
top_k: int = 10,
min_confidence: float = 0.0,
) -> QueryResult: ...
def explore(self, node_id: str, depth: int = 1) -> ExploreResult | None: ...
def rules(
self,
domains: list[str] | None = None,
concept_ids: list[str] | None = None,
categories: list[str] | None = None,
) -> RulesResult: ...
def feedback(
self,
query_id: str,
outcomes: dict[str, str],
source: str = "unknown",
) -> None: ...
def status(self) -> dict: ...
def domains(self) -> list[dict]: ...
def ingest(self, source_path: str, domain: str) -> dict: ...
Three implementations ship with qortex:
| Implementation | Transport | Use Case |
|---|---|---|
LocalQortexClient |
In-process | Direct embedding, no network |
HttpQortexClient |
HTTP (async) | Remote access via qortex serve |
| MCP server | JSON-RPC (stdio/SSE) | AI assistant tool calls |
LocalQortexClient¶
In-process implementation. Best for single-process deployments and testing.
from qortex.client import LocalQortexClient
from qortex.core.memory import InMemoryBackend
from qortex.vec.index import NumpyVectorIndex
vector_index = NumpyVectorIndex(dimensions=384)
backend = InMemoryBackend(vector_index=vector_index)
backend.connect()
client = LocalQortexClient(
vector_index=vector_index,
backend=backend,
embedding_model=my_embedding,
mode="graph", # or "vec"
)
# Query
result = client.query("OAuth2 authorization", domains=["security"], top_k=5)
# Explore
explore = client.explore(result.items[0].node_id)
# Rules
rules = client.rules(concept_ids=[item.node_id for item in result.items])
# Feedback
client.feedback(result.query_id, {result.items[0].id: "accepted"})
# Add concepts (for adapters)
ids = client.add_concepts(texts=["Zero-trust architecture"], domain="security")
# Get nodes by ID (for adapters)
nodes = client.get_nodes(["sec:oauth", "sec:jwt"])
HttpQortexClient¶
Async HTTP client for remote access. Protocol-compatible with LocalQortexClient.
from qortex.http_client import HttpQortexClient
# Basic usage (no auth)
async with HttpQortexClient("http://localhost:8741") as client:
result = await client.query("OAuth2 authorization", domains=["security"])
await client.feedback(result.query_id, {result.items[0].id: "accepted"})
# With API key authentication
async with HttpQortexClient(
"http://localhost:8741",
api_key="my-secret-key",
) as client:
result = await client.query("error handling patterns")
# With HMAC-SHA256 signing
async with HttpQortexClient(
"http://localhost:8741",
hmac_secret="my-hmac-secret",
) as client:
result = await client.query("error handling patterns")
HttpQortexClient uses httpx under the hood and supports connection pooling, automatic retries, and timeouts. All methods are async.
QortexService¶
The service layer that wires all backends together. Used internally by qortex serve and the MCP server.
from qortex.service import QortexService
# Create from environment variables (async factory)
service = await QortexService.async_from_env()
# The service holds:
# - service.client: LocalQortexClient
# - service.pool: shared asyncpg pool (if QORTEX_STORE=postgres)
# - service.vec_index: PgVectorIndex or SqliteVecIndex
# - service.learning_store: PostgresLearningStore or SqliteLearningStore
# - service.interoception_store: PostgresInteroceptionStore or InMemoryInteroception
async_from_env() reads these environment variables:
| Variable | Effect |
|---|---|
QORTEX_STORE=postgres |
Uses PostgreSQL for vec, learning, and interoception |
DATABASE_URL |
PostgreSQL connection string for the shared pool |
QORTEX_VEC=pgvector |
Uses pgvector for vector index (implied by QORTEX_STORE=postgres) |
QORTEX_GRAPH=memgraph |
Uses Memgraph for graph backend |
Result Types¶
from qortex.client import (
QueryResult, # query() return type
QueryItem, # Individual query result
ExploreResult, # explore() return type
RulesResult, # rules() return type
NodeItem, # Node in explore results
EdgeItem, # Edge in explore results
RuleItem, # Rule in any result
)
QueryResult¶
| Field | Type | Description |
|---|---|---|
query_id |
str |
Unique ID for feedback |
items |
list[QueryItem] |
Ranked results |
rules |
list[RuleItem] |
Auto-surfaced linked rules |
QueryItem¶
| Field | Type | Description |
|---|---|---|
id |
str |
Unique item ID |
content |
str |
"Name: Description" text |
score |
float |
0.0–1.0 relevance |
domain |
str |
Source domain |
node_id |
str |
Graph node ID (use for explore) |
metadata |
dict |
Additional metadata |
ExploreResult¶
| Field | Type | Description |
|---|---|---|
node |
NodeItem |
The explored node |
edges |
list[EdgeItem] |
Typed edges |
neighbors |
list[NodeItem] |
Connected nodes |
rules |
list[RuleItem] |
Linked rules |
RulesResult¶
| Field | Type | Description |
|---|---|---|
rules |
list[RuleItem] |
Matching rules |
domain_count |
int |
Distinct domains |
projection |
str |
Always "rules" |
NodeItem¶
| Field | Type | Description |
|---|---|---|
id |
str |
Node ID |
name |
str |
Human-readable name |
description |
str |
Full description |
domain |
str |
Source domain |
confidence |
float |
Extraction confidence |
properties |
dict |
Additional properties |
EdgeItem¶
| Field | Type | Description |
|---|---|---|
source_id |
str |
Source node ID |
target_id |
str |
Target node ID |
relation_type |
str |
e.g. "REQUIRES", "USES" |
confidence |
float |
Edge confidence |
properties |
dict |
Additional properties |
RuleItem¶
| Field | Type | Description |
|---|---|---|
id |
str |
Rule ID |
text |
str |
Rule text |
domain |
str |
Source domain |
category |
str |
e.g. "security", "architectural" |
confidence |
float |
Rule confidence |
relevance |
float |
Relevance to query/context |
source_concepts |
list[str] |
Linked concept IDs |
metadata |
dict |
Additional metadata |
REST API¶
The REST API is served by qortex serve and exposes all QortexClient operations as HTTP endpoints. Base URL: http://localhost:8741/api/v1.
Authentication¶
Include one of these headers depending on your configuration:
Authorization: Bearer <QORTEX_API_KEY>
Or HMAC-SHA256 signing:
X-Qortex-Timestamp: <unix-epoch-seconds>
X-Qortex-Signature: <HMAC-SHA256(secret, timestamp + method + path + body)>
HMAC signatures are validated within a 60-second replay window.
Endpoints¶
Query¶
POST /api/v1/query
{
"context": "OAuth2 authorization",
"domains": ["security"],
"top_k": 5,
"min_confidence": 0.0
}
Returns: QueryResult JSON.
Feedback¶
POST /api/v1/feedback
{
"query_id": "abc-123",
"outcomes": {"item-1": "accepted", "item-2": "rejected"},
"source": "user"
}
Explore¶
GET /api/v1/explore/{node_id}?depth=2
Returns: ExploreResult JSON.
Rules¶
GET /api/v1/rules?domains=security&categories=architectural&min_confidence=0.5
Returns: RulesResult JSON.
Domains¶
GET /api/v1/domains
Returns: list of DomainInfo objects.
Status¶
GET /api/v1/status
Returns: StatusResult JSON with backend info and health check.
Ingest¶
POST /api/v1/ingest
Content-Type: multipart/form-data
file: <file>
domain: security
source_type: markdown
Ingest Text¶
POST /api/v1/ingest/text
{
"text": "OAuth2 uses bearer tokens...",
"domain": "security",
"format": "markdown"
}
Ingest Structured¶
POST /api/v1/ingest/structured
{
"domain": "security",
"concepts": [{"name": "OAuth2", "description": "Authorization framework"}],
"edges": [{"source": "OAuth2", "target": "JWT", "relation_type": "requires"}],
"rules": [{"text": "Always validate JWT signatures"}]
}
Migrate Vec¶
POST /api/v1/migrate/vec
{
"from": "sqlite",
"to": "pgvector",
"batch_size": 1000
}
Returns: {migrated: int, duration_seconds: float}.
MCP Tools¶
qortex runs as an MCP server exposing 34 tools over JSON-RPC, organized by category.
Core Tools (11)¶
qortex_query¶
Search the knowledge graph for context relevant to the current task.
| Parameter | Type | Required | Default |
|---|---|---|---|
context |
str |
Yes | -- |
domains |
list[str] |
No | all |
top_k |
int |
No | 20 |
min_confidence |
float |
No | 0.0 |
mode |
str |
No | "auto" |
mode controls retrieval strategy: "auto" (graph if available, else vec), "vec" (cosine similarity only), "graph" (structural + vector + rules).
Returns: {query_id, items: [{id, content, score, domain, node_id, metadata}], rules: [{id, text, ...}]}
qortex_feedback¶
Report which knowledge items were useful after answering a question.
| Parameter | Type | Required | Default |
|---|---|---|---|
query_id |
str |
Yes | -- |
outcomes |
dict[str, str] |
Yes | -- |
source |
str |
No | "unknown" |
outcomes maps each item_id to "accepted", "rejected", or "partial". If credit propagation is enabled, feedback cascades through the causal DAG.
Returns: {status: "recorded", query_id, outcome_count, source}
qortex_ingest¶
Add a file to the knowledge graph via LLM extraction.
| Parameter | Type | Required | Default |
|---|---|---|---|
source_path |
str |
Yes | -- |
domain |
str |
Yes | -- |
source_type |
str |
No | auto-detected |
source_type accepts "text", "markdown", or "pdf". Auto-detected from file extension if omitted.
Returns: {domain, source, concepts, edges, rules, warnings}
qortex_ingest_text¶
Ingest raw text or markdown into a domain (no file needed).
| Parameter | Type | Required | Default |
|---|---|---|---|
text |
str |
Yes | -- |
domain |
str |
Yes | -- |
format |
str |
No | "text" |
name |
str |
No | "raw_text" |
format accepts "text" or "markdown", selecting the chunking strategy.
Returns: {domain, source, concepts, edges, rules, warnings}
qortex_ingest_structured¶
Ingest pre-structured data directly (bypasses LLM extraction).
| Parameter | Type | Required | Default |
|---|---|---|---|
concepts |
list[dict] |
Yes | -- |
domain |
str |
Yes | -- |
edges |
list[dict] |
No | [] |
rules |
list[dict] |
No | [] |
Each concept dict requires "name" and optionally "description", "id", "properties", "confidence". Each edge dict: {"source": "name", "target": "name", "relation_type": "requires"}. Each rule dict: {"text": "rule text", "category": "optional"}.
Returns: {domain, source, concepts, edges, rules}
qortex_domains¶
List all knowledge domains and their sizes.
No parameters.
Returns: {domains: [{name, description, concept_count, edge_count, rule_count}]}
qortex_status¶
Check server health and active capabilities.
No parameters.
Returns: {status, backend, vector_index, vector_search, graph_algorithms, domain_count, embedding_model, interoception}
qortex_explore¶
Traverse the knowledge graph from a concept to discover connections.
| Parameter | Type | Required | Default |
|---|---|---|---|
node_id |
str |
Yes | -- |
depth |
int |
No | 1 |
depth is clamped to 1-3.
Returns: {node, edges, neighbors, rules} or {node: null} if not found.
qortex_rules¶
Get domain rules, constraints, and best practices from the knowledge graph.
| Parameter | Type | Required | Default |
|---|---|---|---|
domains |
list[str] |
No | all |
concept_ids |
list[str] |
No | all |
categories |
list[str] |
No | all |
include_derived |
bool |
No | true |
min_confidence |
float |
No | 0.0 |
Returns: {rules: [{id, text, domain, category, confidence, relevance, derivation, source_concepts, metadata}], domain_count, projection: "rules"}
qortex_compare¶
Compare graph-enhanced retrieval against cosine-only retrieval on the same query.
| Parameter | Type | Required | Default |
|---|---|---|---|
context |
str |
Yes | -- |
domains |
list[str] |
No | all |
top_k |
int |
No | 5 |
Returns:
{
"query": "...",
"vec_only": {"method": "Cosine similarity", "items": [...]},
"graph_enhanced": {"method": "Graph-enhanced (structural + vector + rules)", "items": [...], "rules_surfaced": N, "rules": [...]},
"diff": {
"graph_found_that_cosine_missed": [...],
"cosine_found_that_graph_dropped": [...],
"rank_changes": [{"id": "...", "vec_rank": 3, "graph_rank": 1, "delta": 2}],
"overlap": N
},
"summary": "Graph-enhanced retrieval found 2 item(s) that cosine missed, surfaced 1 rule(s)."
}
qortex_stats¶
Knowledge coverage, learning progress, query activity, and persistence info.
No parameters.
Returns:
{
"knowledge": {"domains": N, "concepts": N, "edges": N, "rules": N, "domain_breakdown": {...}},
"learning": {"learners": N, "total_observations": N, "learner_breakdown": {...}},
"activity": {"queries_served": N, "feedback_given": N, "feedback_rate": 0.5, "outcomes": {...}},
"health": {"backend": "InMemoryBackend", "vector_index": "NumpyVectorIndex", "embedding_model": "...", "persistence": {...}}
}
Source Tools (7)¶
Tools for connecting to external databases and ingesting their schemas.
qortex_source_connect¶
Connect to a PostgreSQL database and discover its schema.
| Parameter | Type | Required | Default |
|---|---|---|---|
source_id |
str |
Yes | -- |
connection_string |
str |
Yes | -- |
schemas |
list[str] |
No | ["public"] |
domain_map |
dict[str, str] |
No | {} |
targets |
str |
No | "both" |
targets accepts "vec", "graph", or "both".
Returns: {status, source_id, tables, table_names}
qortex_source_discover¶
Return discovered schemas for a connected source.
| Parameter | Type | Required | Default |
|---|---|---|---|
source_id |
str |
Yes | -- |
Returns: {source_id, tables: [{name, schema, columns, row_count, pk_columns, fk_count}]}
qortex_source_sync¶
Sync a database source's data to the vector layer.
| Parameter | Type | Required | Default |
|---|---|---|---|
source_id |
str |
Yes | -- |
tables |
list[str] |
No | all |
mode |
str |
No | "full" |
mode accepts "full" (re-sync everything) or "incremental" (only changes).
Returns: {source_id, tables_synced, rows_added, vectors_created, duration_seconds, errors}
qortex_source_list¶
List all connected database sources.
No parameters.
Returns: {sources: [{source_id, tables}]}
qortex_source_disconnect¶
Disconnect a source and remove it from the registry.
| Parameter | Type | Required | Default |
|---|---|---|---|
source_id |
str |
Yes | -- |
Returns: {status: "disconnected", source_id}
qortex_source_inspect_schema¶
Inspect a PostgreSQL database schema with full constraint metadata (FK, CHECK, UNIQUE). Read-only, does not modify data.
| Parameter | Type | Required | Default |
|---|---|---|---|
connection_string |
str |
Yes | -- |
source_id |
str |
Yes | -- |
schemas |
list[str] |
No | ["public"] |
domain_map |
dict[str, str] |
No | {} |
Returns: {source_id, tables: [{name, schema, columns, row_count, foreign_keys, check_constraints, unique_constraints, is_catalog, domain, name_column}], edges, rules, table_count, edge_count, rule_count}
qortex_source_ingest_graph¶
Ingest a PostgreSQL database schema into the knowledge graph. Discovers schema, classifies FK relationships, and creates ConceptNodes, ConceptEdges, and ExplicitRules.
| Parameter | Type | Required | Default |
|---|---|---|---|
connection_string |
str |
Yes | -- |
source_id |
str |
Yes | -- |
schemas |
list[str] |
No | ["public"] |
domain_map |
dict[str, str] |
No | {} |
embed_catalog_tables |
bool |
No | true |
extract_rules |
bool |
No | true |
Returns: {source_id, concepts, edges, rules}
Vector Tools (9)¶
Low-level vector index management for MastraVector and other raw-vector consumers. These are separate from the text-level index used by qortex_query.
qortex_vector_create_index¶
Create a named vector index.
| Parameter | Type | Required | Default |
|---|---|---|---|
index_name |
str |
Yes | -- |
dimension |
int |
Yes | -- |
metric |
str |
No | "cosine" |
metric accepts "cosine", "euclidean", or "dotproduct".
Returns: {status: "created", index_name} or {status: "exists", index_name} if already created with the same dimension.
qortex_vector_list_indexes¶
List all named vector indexes.
No parameters.
Returns: {indexes: [...]}
qortex_vector_describe_index¶
Get statistics for a named vector index.
| Parameter | Type | Required | Default |
|---|---|---|---|
index_name |
str |
Yes | -- |
Returns: {dimension, count, metric}
qortex_vector_delete_index¶
Delete a named vector index and all its data.
| Parameter | Type | Required | Default |
|---|---|---|---|
index_name |
str |
Yes | -- |
Returns: {status: "deleted", index_name}
qortex_vector_upsert¶
Upsert vectors into a named index. Replaces existing vectors if IDs match.
| Parameter | Type | Required | Default |
|---|---|---|---|
index_name |
str |
Yes | -- |
vectors |
list[list[float]] |
Yes | -- |
metadata |
list[dict] |
No | [{}] per vector |
ids |
list[str] |
No | auto-generated UUIDs |
documents |
list[str] |
No | None |
Returns: {ids: [...]}
qortex_vector_query¶
Query a named vector index by similarity. Supports MongoDB-like metadata filters.
| Parameter | Type | Required | Default |
|---|---|---|---|
index_name |
str |
Yes | -- |
query_vector |
list[float] |
Yes | -- |
top_k |
int |
No | 10 |
filter |
dict |
No | None |
include_vector |
bool |
No | false |
filter supports operators: $ne, $gt, $gte, $lt, $lte, $in, $nin, $and, $or, $not.
Returns: {results: [{id, score, metadata, document?}]}
qortex_vector_update¶
Update a vector's embedding and/or metadata.
| Parameter | Type | Required | Default |
|---|---|---|---|
index_name |
str |
Yes | -- |
id |
str |
No | -- |
filter |
dict |
No | -- |
vector |
list[float] |
No | -- |
metadata |
dict |
No | -- |
Specify either id or filter (mutually exclusive). At least one of vector or metadata is required.
Returns: {status: "updated", count}
qortex_vector_delete¶
Delete a single vector by ID.
| Parameter | Type | Required | Default |
|---|---|---|---|
index_name |
str |
Yes | -- |
id |
str |
Yes | -- |
Returns: {status: "deleted", id}
qortex_vector_delete_many¶
Delete multiple vectors by IDs or metadata filter.
| Parameter | Type | Required | Default |
|---|---|---|---|
index_name |
str |
Yes | -- |
ids |
list[str] |
No | -- |
filter |
dict |
No | -- |
Specify either ids or filter (mutually exclusive).
Returns: {status: "deleted", count}
Learning Tools (7)¶
Adaptive learning via Thompson Sampling. Learners are auto-created on first use.
qortex_learning_select¶
Select the best candidates from a pool using adaptive learning.
| Parameter | Type | Required | Default |
|---|---|---|---|
learner |
str |
Yes | -- |
candidates |
list[dict] |
Yes | -- |
context |
dict |
No | None |
k |
int |
No | 1 |
token_budget |
int |
No | 0 |
min_pulls |
int |
No | 0 |
Each candidate dict requires "id" (str). Optional: "metadata" (dict), "token_cost" (int). Set token_budget > 0 to cap total token cost of selected arms. Set min_pulls > 0 to force-explore under-observed arms.
Returns: {selected_arms: [...], excluded_arms: [...], is_baseline, scores, token_budget, used_tokens}
qortex_learning_observe¶
Record whether a selected item worked well. Updates posterior distribution.
| Parameter | Type | Required | Default |
|---|---|---|---|
learner |
str |
Yes | -- |
arm_id |
str |
Yes | -- |
outcome |
str |
No | "" |
reward |
float |
No | 0.0 |
context |
dict |
No | None |
outcome accepts "accepted", "rejected", "partial", or custom strings. reward is a direct 0.0-1.0 value that overrides outcome if both are given.
Returns: {arm_id, alpha, beta, mean, pulls}
qortex_learning_posteriors¶
Get current posterior distributions for tracked arms.
| Parameter | Type | Required | Default |
|---|---|---|---|
learner |
str |
Yes | -- |
context |
dict |
No | None |
arm_ids |
list[str] |
No | all |
Returns: {learner, posteriors: {arm_id: {alpha, beta, pulls, mean, ...}}}
qortex_learning_metrics¶
Get aggregate learning metrics for a learner.
| Parameter | Type | Required | Default |
|---|---|---|---|
learner |
str |
Yes | -- |
window |
int |
No | None |
Returns: {learner, total_pulls, total_reward, accuracy, arm_count, explore_ratio}
qortex_learning_session_start¶
Start a named learning session for tracking arm selections.
| Parameter | Type | Required | Default |
|---|---|---|---|
learner |
str |
Yes | -- |
session_name |
str |
Yes | -- |
Returns: {session_id, learner}
qortex_learning_session_end¶
End a learning session and return summary.
| Parameter | Type | Required | Default |
|---|---|---|---|
session_id |
str |
Yes | -- |
Returns: {session_id, learner, selected_arms, outcomes, started_at, ended_at}
qortex_learning_reset¶
Reset learned posteriors for a learner, clearing poisoned or stale data.
| Parameter | Type | Required | Default |
|---|---|---|---|
learner |
str |
Yes | -- |
arm_ids |
list[str] |
No | None |
context |
dict |
No | None |
Scoping:
- arm_ids=None, context=None: Full reset (delete all arm states across all contexts)
- arm_ids=None, context=set: Delete all arms in that context partition
- arm_ids=set, context=None: Delete those arms in the default context
- arm_ids=set, context=set: Delete those arms in that context partition
The learner is evicted from cache after reset, so seed boosts (seed_arms, seed_boost) re-apply on next use.
Returns: {learner, deleted, status}
Learner (Python API)¶
Direct Python API for adaptive learning. Used by framework adapters (buildlog QortexLearner, etc.).
from qortex.learning.learner import Learner
from qortex.learning.types import Arm, ArmOutcome, LearnerConfig
learner = Learner(LearnerConfig(name="my-learner", state_dir="/tmp/state"))
Methods¶
| Method | Description |
|---|---|
select(candidates, context, k) |
Select k arms from candidates using Thompson Sampling |
observe(outcome, context) |
Record a single observation and update posterior |
batch_observe(outcomes, context) |
Record multiple observations in one call |
top_arms(context, k) |
Return top-k arms by posterior mean, descending |
decay_arm(arm_id, decay_factor, context) |
Shrink an arm's learned signal toward the prior |
posteriors(context, arm_ids) |
Get current posteriors for arms |
metrics() |
Compute aggregate learning metrics |
apply_credit_deltas(deltas, context) |
Apply causal credit deltas to posteriors |
reset(arm_ids, context) |
Delete arm states (scoped by arms and/or context) |
session_start(name) |
Start a named learning session |
session_end(session_id) |
End a session and return summary |
Types¶
ArmState¶
| Field | Type | Description |
|---|---|---|
alpha |
float |
Beta distribution alpha (successes + prior) |
beta |
float |
Beta distribution beta (failures + prior) |
pulls |
int |
Total observations |
total_reward |
float |
Cumulative reward |
last_updated |
str |
ISO timestamp |
mean |
float |
Posterior mean: alpha / (alpha + beta) |
ArmOutcome¶
| Field | Type | Description |
|---|---|---|
arm_id |
str |
Which arm was observed |
reward |
float |
0.0 to 1.0 (optional if outcome provided) |
outcome |
str |
"accepted", "rejected", "partial", or custom |
context |
dict |
Context for partitioned state |
LearnerConfig¶
| Field | Type | Default | Description |
|---|---|---|---|
name |
str |
-- | Learner identifier |
baseline_rate |
float |
0.1 |
Probability of uniform random exploration |
seed_boost |
float |
2.0 |
Alpha prior for seed arms |
seed_arms |
list[str] |
[] |
Arms with boosted priors |
state_dir |
str |
"" |
Override for state persistence path |
max_arms |
int |
1000 |
Cap on tracked arms |
min_pulls |
int |
0 |
Force-include arms with fewer than N observations |
Backends¶
GraphBackend Protocol¶
from qortex.core.backend import GraphBackend
class GraphBackend(Protocol):
def connect(self) -> None: ...
def disconnect(self) -> None: ...
def is_connected(self) -> bool: ...
# Domains
def create_domain(self, name: str, description: str | None = None) -> Domain: ...
def get_domain(self, name: str) -> Domain | None: ...
def list_domains(self) -> list[Domain]: ...
def delete_domain(self, name: str) -> None: ...
# Nodes
def add_node(self, node: ConceptNode) -> None: ...
def get_node(self, node_id: str) -> ConceptNode | None: ...
def find_nodes(self, domain: str | None = None, pattern: str | None = None) -> list[ConceptNode]: ...
# Edges
def add_edge(self, edge: ConceptEdge) -> None: ...
def get_edges(self, source_id: str | None = None, target_id: str | None = None) -> list[ConceptEdge]: ...
# Rules
def add_rule(self, rule: ExplicitRule) -> None: ...
def get_rules(self, domain: str | None = None) -> list[ExplicitRule]: ...
# Bulk operations
def ingest_manifest(self, manifest: IngestionManifest) -> None: ...
InMemoryBackend¶
In-memory implementation for testing.
from qortex.core.memory import InMemoryBackend
backend = InMemoryBackend()
backend.connect()
# Use the backend...
backend.create_domain("test", "Test domain")
backend.add_node(node)
backend.add_edge(edge)
# Query
nodes = backend.find_nodes(domain="test")
edges = backend.get_edges(source_id="concept_a")
MemgraphBackend¶
Production backend using Memgraph.
from qortex.core.backend import MemgraphBackend
backend = MemgraphBackend(
host="localhost",
port=7687,
username=None,
password=None,
)
backend.connect()
# Additional Memgraph-specific methods
results = backend.query_cypher("MATCH (n) RETURN n LIMIT 10")
scores = backend.personalized_pagerank(source_ids=["concept_a"])
checkpoint_id = backend.checkpoint()
backend.restore(checkpoint_id)
Projection Pipeline¶
ProjectionSource Protocol¶
from qortex.projectors.base import ProjectionSource
from qortex.core.models import Rule
from qortex.projectors.models import ProjectionFilter
class ProjectionSource(Protocol):
def derive(
self,
domains: list[str] | None = None,
filters: ProjectionFilter | None = None,
) -> list[Rule]: ...
FlatRuleSource¶
Default source that extracts explicit and derived rules.
from qortex.projectors.sources.flat import FlatRuleSource
source = FlatRuleSource(backend=backend)
rules = source.derive(domains=["error_handling"])
Enricher Protocol¶
from qortex.projectors.base import Enricher
from qortex.projectors.models import EnrichedRule
class Enricher(Protocol):
def enrich(self, rules: list[Rule]) -> list[EnrichedRule]: ...
TemplateEnricher¶
Fast, deterministic enrichment.
from qortex.projectors.enrichers.template import TemplateEnricher
enricher = TemplateEnricher(domain="error_handling")
enriched = enricher.enrich(rules)
ProjectionTarget Protocol¶
from qortex.projectors.base import ProjectionTarget
from qortex.projectors.models import EnrichedRule
class ProjectionTarget(Protocol[T]):
def serialize(self, rules: list[EnrichedRule]) -> T: ...
BuildlogSeedTarget¶
Target for the universal schema format.
from qortex.projectors.targets.buildlog_seed import BuildlogSeedTarget
target = BuildlogSeedTarget(
persona_name="my_rules",
version=1,
graph_version="2026-02-05T12:00:00Z", # Optional
)
result = target.serialize(enriched_rules)
# Returns dict in universal schema format
Projection¶
Composes source, enricher, and target.
from qortex.projectors.projection import Projection
projection = Projection(
source=FlatRuleSource(backend=backend),
enricher=TemplateEnricher(domain="error_handling"), # Optional
target=BuildlogSeedTarget(persona_name="rules"),
)
result = projection.project(
domains=["error_handling"], # Optional: all domains if None
filters=ProjectionFilter(...), # Optional
)
Enrichment¶
EnrichmentBackend Protocol¶
from qortex.enrichment.base import EnrichmentBackend
from qortex.projectors.models import RuleEnrichment
class EnrichmentBackend(Protocol):
def enrich_batch(
self,
rules: list[Rule],
domain: str,
) -> list[RuleEnrichment]: ...
AnthropicEnrichmentBackend¶
LLM-powered enrichment using Claude.
from qortex.enrichment.anthropic import AnthropicEnrichmentBackend
backend = AnthropicEnrichmentBackend(
model="claude-sonnet-4-20250514",
max_tokens=1024,
)
enrichments = backend.enrich_batch(rules, domain="error_handling")
EnrichmentPipeline¶
Orchestrates enrichment with fallback.
from qortex.enrichment.pipeline import EnrichmentPipeline
pipeline = EnrichmentPipeline(
backend=AnthropicEnrichmentBackend(), # Optional
# Falls back to TemplateEnrichmentFallback if backend fails
)
enriched = pipeline.enrich(rules, domain="error_handling")
# Check stats
print(pipeline.stats.succeeded)
print(pipeline.stats.failed)
Templates¶
EdgeRuleTemplate¶
Templates for deriving rules from edges.
from qortex.core.templates import EdgeRuleTemplate, get_template, select_template
# Get specific template
template = get_template("requires:imperative")
text = template.render(source_name="A", target_name="B")
# Select template for an edge
from qortex.core.models import ConceptEdge, RelationType
edge = ConceptEdge(
source_id="a",
target_id="b",
relation_type=RelationType.REQUIRES,
)
template = select_template(edge, variant="imperative")
Template Registry¶
from qortex.core.templates import TEMPLATE_REGISTRY, reset_template_registry
# List all templates
for template_id in TEMPLATE_REGISTRY:
print(template_id)
# Reset for test isolation
reset_template_registry()
Interop¶
Configuration¶
from qortex.interop import (
InteropConfig,
SeedsConfig,
SignalsConfig,
get_interop_config,
write_config,
)
# Load config (from ~/.claude/qortex-consumers.yaml or defaults)
config = get_interop_config()
# Custom config
config = InteropConfig(
seeds=SeedsConfig(
pending=Path("~/.qortex/seeds/pending"),
processed=Path("~/.qortex/seeds/processed"),
failed=Path("~/.qortex/seeds/failed"),
),
signals=SignalsConfig(
projections=Path("~/.qortex/signals/projections.jsonl"),
),
)
# Write config
write_config(config)
Seed Operations¶
from qortex.interop import (
write_seed_to_pending,
list_pending_seeds,
list_processed_seeds,
list_failed_seeds,
generate_seed_filename,
)
# Write a seed
path = write_seed_to_pending(
seed_data=result,
persona="my_rules",
domain="error_handling",
emit_signal=True,
)
# List seeds
pending = list_pending_seeds()
processed = list_processed_seeds()
failed = list_failed_seeds() # Returns [(path, error_msg), ...]
Signal Operations¶
from qortex.interop import (
ProjectionEvent,
append_signal,
read_signals,
)
from datetime import datetime, timezone
# Emit event
event = ProjectionEvent(
event="projection_complete",
persona="my_rules",
domain="error_handling",
path="/path/to/seed.yaml",
rule_count=5,
ts=datetime.now(timezone.utc).isoformat(),
)
append_signal(event)
# Read events
events = read_signals(
since=datetime.now(timezone.utc),
event_types=["projection_complete"],
)
Schema Validation¶
from qortex.interop_schemas import (
validate_seed,
validate_event,
export_schemas,
SEED_SCHEMA,
EVENT_SCHEMA,
)
# Validate
errors = validate_seed(seed_dict)
errors = validate_event(event_dict)
# Export
seed_path, event_path = export_schemas("./schemas/")
# Get raw schemas
schema = SEED_SCHEMA.copy()
Serialization¶
serialize_ruleset¶
Low-level serialization to universal schema.
from qortex.projectors.targets._serialize import serialize_ruleset
seed = serialize_ruleset(
enriched_rules=rules,
persona_name="my_rules",
version=1,
graph_version="2026-02-05T12:00:00Z",
source_version="0.1.0",
)
rule_to_dict¶
Convert a single rule to dict.
from qortex.projectors.targets._serialize import rule_to_dict
rule_dict = rule_to_dict(enriched_rule)
Exceptions¶
from qortex.core.exceptions import (
QortexError, # Base exception
DomainNotFoundError, # Domain doesn't exist
NodeNotFoundError, # Node doesn't exist
ConnectionError, # Backend connection failed
)
try:
backend.get_domain("nonexistent")
except DomainNotFoundError:
print("Domain not found")