Skip to content

Changelog

What changed in Contexta

Every release note is a change to the engine itself — an index, a constraint, a retrieval path, or a stage of the ingestion pipeline. v1.5 is current. v1 is the initial public release, kept on the record so the starting point is documented too.

v1.5

latest

The indexing and truth-maintenance release. Point-in-time reads became a real index scan, lexical search became a real GIN predicate, graph traversal became a single capped recursive CTE, and extraction stopped silently falling back to heuristics. Billing and metering code is gone.

Lexical search
550ms → 48ms
Graph traversal
38.5ms → 2.16ms
Extraction success
17% → 87.5%
Public tables
57 → 33

Storage and indexing — Added

  • A durable ingestion outbox with PostgreSQL SKIP LOCKED claiming, so concurrent workers never process the same observation twice and a crashed claim is retried rather than dropped.
  • A composite bitemporal index on (organization_id, valid_to, valid_from), which makes point-in-time as_of reads a real index scan instead of a sequential filter.
  • Entity-name trigram indexes plus a case-insensitive uniqueness constraint on (organization_id, user_id, lower(name)). A migration merged 2,670 pre-existing duplicate entity groups down to zero.
  • A dedicated TruthSupersessionService that invalidates a contradicted memory with valid_to = now() and records lineage through memory_version.superseded_by_id, so stale facts are excluded from active retrieval instead of accumulating as contradictions. Backed by a partial unique index guaranteeing at most one current fact per slot.
  • A closed, validated set of relationship types enforced by a database CHECK constraint, with self-loop rejection at the storage layer.

Retrieval — Added

  • A cascade retrieval mode: lexical and graph evidence are gathered first, and the dense channel is only consulted when that primary evidence is judged insufficient.
  • Precision-aware freshness scoring that honours temporal_precision and temporal_basis, so an explicitly approximate timestamp is not treated as an exact one.

Extraction reliability — Added

  • Bounded retries with escalating temperature, plus robust JSON recovery for fenced code blocks, <think> reasoning traces, and leading preambles.
  • Tolerant coercion of LLM schema drift: unknown memory types, travel mapped to event, list-shaped booleans, and empty titles are normalised instead of discarded. Measured session-level extraction success improved from roughly 17% to 87.5%.

Security and hygiene — Changed

  • Secrets redaction now runs as a fail-closed stage at the head of the ingestion pipeline, so API keys, JWTs, bearer tokens, and passwords are scrubbed before extraction ever runs.
  • Pair-clique edge generation in the knowledge graph was replaced with a bounded approach, removing the O(n²) blow-up as the graph grows.

Indexing — Fixed

  • HNSW retrieval was collapsing on filtered queries and silently returning zero rows. ef_search is now tuned and hnsw.iterative_scan is enabled, so a filtered vector search no longer drops the tenant constraint to get an answer.
  • Sequential lexical search was replaced with a proper GIN tsvector predicate, measured from roughly 550ms to 48ms.
  • 2,745 colliding knowledge-graph edges were deduplicated and re-normalised.

Extraction — Fixed

  • The fine-tuned extractor's context window was raised from 4,096 to 16,384 tokens. Real extraction prompts were 8,281 tokens and were being rejected outright, which silently downgraded sessions to a low-quality heuristic fallback.
  • Structured-output enforcement now works. Ollama's OpenAI-compatible endpoint silently drops the format field, so schema constraints were never actually applied. Contexta detects an Ollama endpoint and uses the native Ollama route, constraining generation to a real JSON Schema.

Isolation — Fixed

  • Tenant scoping on the graph layer was corrected so multi-hop traversal stays inside the requesting organization.

Measured — Performance

  • Lexical retrieval: approximately 550ms to 48ms on the reference corpus.
  • Multi-hop graph traversal: rewritten as a single recursive CTE with hard caps, approximately 38.5ms to 2.16ms — about 16x on the reference graph.
  • Session-level extraction success: roughly 17% to 87.5%.
  • Schema surface: 18 billing tables and 6 dead schemas dropped, taking the public table count from 57 to 33.

Removed — Removed

  • All billing, metering, and credit-consumption code. Contexta Core no longer has a metering path to remove or bypass.

Upgrade notes

  1. 01Run the v1.5 migrations against a snapshot. The entity uniqueness constraint is created case-insensitively on lower(name) and will refuse to apply while case-variant duplicates exist; the shipped migration merges them first, which is the step that cleared 2,670 duplicate groups.
  2. 02The new relationship-type CHECK constraint is closed. If you have written custom relationship types directly against the graph tables, map them onto the validated set before upgrading.
  3. 03The 18 billing tables and 6 dead schemas are dropped. Any dashboard query, report, or export that referenced them needs to be removed in the same change.
  4. 04The offline embedding profile is unchanged at 1024 dimensions, so no vector migration is required. If you had switched the column to the 1536-d online profile, switch it back before re-indexing.
  5. 05Ollama endpoints are now detected and routed natively for structured output. A custom OpenAI-compatible base URL that is not recognisably Ollama will no longer receive a schema constraint — point the endpoint at Ollama directly.
  6. 06The outbox uses SKIP LOCKED claiming. Scaling ingestion workers is now safe, but any worker that previously assumed single-writer ordering should tolerate interleaved claims.

v1

The first public release. Contexta shipped as a self-hosted memory engine: a Python extraction and retrieval core driven by Celery, a Go gateway on :8443 that verifies API keys and rate limits in Redis, Python and TypeScript SDKs, a Next.js operator dashboard, and a compose stack that comes up without a paid model key.

Engine
Python · FastAPI + Celery
Gateway
Go · :8443
SDKs
Python · TypeScript
Embedding keys
none required

Memory engine — Added

  • A Python memory engine on FastAPI with Celery workers over Redis, routed across three task queues: extraction, embedding, and maintenance for decay, reflection, and dream cycles. task_acks_late and task_reject_on_worker_lost mean a killed worker requeues its job instead of dropping the observation.
  • The core stages shipped as separate modules under contexta/core/: a sensitive filter for redaction, an extraction worker, near-duplicate merging, importance and confidence scoring, entity resolution, contradiction maintenance, a hybrid retrieval engine, read-age decay, and dream-cycle reflection — orchestrated by contexta/core/pipeline.py.
  • Multi-tenancy through a single base class. TenantScopedRepository in contexta/repositories/base.py appends WHERE organization_id = :tenant_id to every statement it builds, so isolation is inherited by every repository rather than remembered per call.

Edge and SDKs — Added

  • A Go gateway terminating TLS on :8443 and reverse-proxying to the Python API, with SHA-256-hashed API key verification in internal/auth/verifier.go and a Redis-backed token-bucket rate limiter with per-tier RPS and burst limits in internal/ratelimit/bucket.go. It holds no persistent state.
  • A Python client (contexta_client) with sync and async clients exposing observe(), observe_batch(), and context(), and a TypeScript client with the same surface. Adapters shipped for OpenAI, Anthropic, LangChain, and LlamaIndex in Python, and OpenAI, Anthropic, LangChain, and Vercel AI in TypeScript.
  • A CLI covering init, login, keys, memory, observations, policy, projects, schema, context, test, and usage.

Operator surface — Added

  • A Next.js operator dashboard with a memory inspector, per-memory lineage rows, an entity graph viewer, API key issuance and revocation, and a settings surface.

Running the stack — Added

  • docker compose up --build brings up PostgreSQL with pgvector, Redis, the FastAPI backend, the Go services, the Celery workers, and the dashboard behind a single entrypoint.sh, with a GitHub Actions CI workflow on the repository.
  • A deterministic local embedding provider, selected with CONTEXTA_EMBEDDING_PROVIDER=deterministic, so the default install needs no OpenAI or DeepSeek key. It is hash-derived rather than semantic, which makes it a bring-up default and not a retrieval-quality baseline.

Getting started

  1. 01This is the first public release, so there is nothing to migrate from. Clone the repository and run docker compose up --build; the dashboard is served on :3000 and the gateway terminates TLS on :8443.
  2. 02The default embedding provider is deterministic. Use it to bring the stack up and exercise the pipeline, but do not use it to judge retrieval quality — the vectors are hash-derived, not semantic.
  3. 03Model-backed extraction is configured through CONTEXTA_LLM_MODEL and CONTEXTA_LLM_API_KEY. The stack boots without them; set them when you want an LLM extraction provider rather than the offline path.
  4. 04Python 3.11 or newer, PostgreSQL with the pgvector extension, and Redis are the only hard prerequisites.