Reliable memory and context infrastructure for AI coding agents.
Infinity Context helps AI coding agents keep project knowledge across sessions without turning random chat history into permanent truth. It captures decisions, documents, tasks, source references, agent events and reviewable suggestions, then serves compact, cited context back through HTTP, SDK, MCP and a local UI.
The difference is trust. Every durable memory has a canonical lifecycle in Postgres: source evidence, versions, scopes, deletes, idempotency and review state. Vector and graph engines make recall better, but they never become hidden truth. If Qdrant, Graphiti or an LLM returns something stale, Infinity Context revalidates it before it reaches the agent prompt.
This is not a demo memory store. The repo already includes the reusable core, FastAPI server, Postgres lifecycle, optional Qdrant and Graphiti adapters, SDK, MCP adapter, CLI, local memory browser, service-token auth, workers, diagnostics, smoke flows and prompt-impacting quality evals.
- Cited agent memory for architecture decisions, docs, tasks, captures and transcripts.
- Scoped recall across spaces, memory scopes and threads, so one project does not leak into another.
- Review-gated learning where agents can suggest memories and relations, but humans control what becomes canonical.
- Current-state filtering for updates, deletes, restricted data and stale derived indexes.
- Self-hosted runtime with local Docker profiles, service tokens, CLI, browser UI, SDK and MCP adapter.
- Replaceable retrieval with Postgres as the source of truth and Qdrant, Graphiti, Cognee or provider adapters behind ports.
- Safer than plain vector memory. A vector hit is only a candidate until it is hydrated through canonical facts, source refs and visibility rules.
- More controllable than automatic chat memory. Prompt memory is evidence, not instruction, and suggested memory can be reviewed before it affects future agents.
- Better fit for coding work. The model is built around projects, documents, decisions, source evidence, thread cleanup, digest reports and agent tooling.
- Stable enough for real workflows. Additive migrations, transactional outbox, token hashing, circuit diagnostics, import-boundary tests, API tests, worker tests and golden evals are part of the shipped system.
Use Mem0-style tools when you mostly need quick personalization memory. Use Zep when you want a managed enterprise context graph. Use LangGraph memory primitives when your memory should stay inside one agent framework.
Use Infinity Context when the hard problem is trustworthy project memory for coding agents: source-backed facts, scoped recall, current-state filtering, review workflows, self-hosted data and portable adapters.
Infinity Context is a working standalone service and library stack. It supports local developer setups, self-hosted team deployments and client integrations through HTTP, SDK or MCP.
Runtime architecture:
Infinity Context = Postgres canonical truth + Qdrant RAG + optional Graphiti graph + SDK/MCP/UI
Trust model:
- Clean Architecture;
- SOLID;
- simple DDD;
- port/adapter boundaries;
- Postgres as canonical truth;
- Qdrant and Graphiti as derived indexes;
- prompt memory is evidence, never instruction.
- Core runtime implementation plan
- Local install and Memory Digest plan
- Global architecture plan
- Client compatibility notes
- Client integration run notes
packages/
infinity_context_core/
infinity_context_server/
infinity_context_adapters/
infinity_context_sdk/
infinity_context_mcp/
infinity_context_cli/
tests/
unit/
integration/
e2e/
fixtures/
Client applications should consume this project through HTTP or SDK, not by importing provider-specific adapters.
Infinity Context ships as a reusable service and library stack:
infinity_context_coreowns domain entities, application use cases and ports only;infinity_context_serverowns FastAPI routes, composition root, auth, config, admin CLI, worker CLI and eval CLI;infinity_context_serveralso serves the optional local memory browser at/ui/;infinity_context_adaptersowns Postgres, optional Qdrant/OpenAI/Graphiti adapters and disabled noop adapters;infinity_context_sdkowns HTTP client calls and typed error handling for other apps;infinity_context_mcpowns the agent-facing MCP adapter over the HTTP API;infinity_context_cliowns local install/runtime UX and calls the HTTP API instead of importing server internals;- Postgres is canonical truth for spaces, memory_scopes, facts, source refs, fact versions, episodes, documents, chunks, suggestions, outbox and idempotency;
- Qdrant vectors and Graphiti graph memory are derived projections behind ports;
- Qdrant adapter creates its collection on first upsert/search when enabled;
- Graphiti adapter is optional and requires Neo4j credentials when enabled;
- context/search hydrate graph/vector candidates through Postgres before rendering;
- prompt memory is rendered as evidence, never as instructions.
- prompt context is grouped by memory_scope id and caps chunk evidence per source so one long document cannot consume the whole memory block;
- document/chunk classification is enforced in the prompt path:
restrictedmemory is stored canonically but excluded from context by default, andunknowndocuments are not embedded until reclassified.
Implemented API surface:
/v1/health,/v1/capabilities;/v1/spaces,/v1/memory-scopes;/v1/factsremember/list/get/versions/update/forget;/v1/documentsingest/get/chunks/process/delete;/v1/episodestranscript/event ingest for app or agent sessions;/v1/search,/v1/contextwith citedtop_evidenceandanswer_supportdiagnostics for source-grounded chat answers;/v1/digestfor source-bound Memory Digest reports;/v1/thread-memory/status,/v1/thread-memorydelete for thread-scoped cleanup;/v1/suggestionscreate/list/approve/reject/expire for review-gated memory;/v1/link-suggestions,/v1/context-link-suggestions,/v1/context-link-suggestions/review-batch,/v1/context-linksfor reviewable memory relations and status-filtered review history;/v1/diagnostics/adapters,/outbox,/memory-scope/{memory_scope_id}with production-safe metadata only;- optional client-compatible
/api/v1/interview-memory/ingest,/context, session status and delete routes whenMEMORY_LEGACY_CLIENT_ENABLED=true.
Local browser UI:
- open
http://127.0.0.1:7788/ui/after the server starts; - enter the service token from local config, for example
~/.infinity-context/.env; - browse graph nodes for facts, suggestions, sources, kinds, tags and statuses;
- review pending suggestions and relation suggestions with approve/reject/edit actions;
- build source-bound digest and recall results through the existing
/v1API; - disable with
MEMORY_UI_ENABLED=false.
Operational pieces:
- transactional outbox for derived graph/vector side effects;
- outbox worker that re-reads canonical rows and handles disabled adapters safely;
- idempotency keys are scoped by operation and memory_scope/thread boundary, so client-provided retry keys cannot collide across memory scopes;
- admin commands for doctor, invariant check, projection repair dry-run and dead-job replay;
- admin service-token create/list/revoke stores token hashes only; raw token is printed once on creation;
- database service tokens support expiry and last-used tracking without storing raw tokens;
infinity_context_server.db upgrade,admin seed-defaultsand guardedadmin reset-local;- schema upgrade is additive for local databases and repairs missing fact/document/chunk classification columns without dropping canonical data;
- document delete hides chunks immediately and also deletes active facts whose current evidence only points to the deleted document or its chunks;
- redacted memory_scope export removes fact/chunk text and source quote previews;
- small golden eval for prompt-impacting context behavior;
- quality golden eval for recall, precision, stale/delete filtering, memory_scope/thread isolation, restricted-memory hiding, prompt-injection evidence handling and token budget safety;
- import-boundary, API, worker, SDK and review-gated suggestion tests.
One-command local install:
curl -fsSL https://raw.githubusercontent.com/777genius/infinity-context/main/scripts/install.sh | bashSafer inspectable install:
curl -fsSL https://raw.githubusercontent.com/777genius/infinity-context/main/scripts/install.sh -o install.sh
bash install.sh --no-startAfter install:
export PATH="$HOME/.infinity-context/bin:$PATH"
infinity-context quickstart --agent codex --open-uiManual local controls remain available:
infinity-context up --lite
infinity-context status
infinity-context doctor
infinity-context mcp-config --agent codex
infinity-context digest "current architecture decisions" --space default --memory_scope defaultinfinity-context quickstart initializes local config, starts the lite Docker
runtime, waits for readiness and writes an MCP config under
~/.infinity-context/generated/. quickstart and mcp-config keep the local
service token out of generated agent config by default and point the MCP adapter
at the private ~/.infinity-context/.env token file instead. Use
--include-token only when intentionally writing a private local config file.
infinity-context ui prints the local memory browser URL,
infinity-context ui --open opens it in your browser, and
quickstart --open-ui opens the visual memory browser immediately after setup.
infinity-context doctor also verifies the generated MCP config and /ui/
browser entrypoint. The browser starts with a quick Capture panel for text notes
and file evidence, including a first-memory rail for the current memory scope,
capture count, file count, pending reviews and graph nodes. Direct local browser
links are available as /ui/#capture and /ui/#review, then the browser shows
overview, graph, review, operations and timeline.
Both quickstart --json and doctor --json include a local_experience
summary with status, ui_url, visual_memory_ready, mcp_ready,
ready_agents, a first-use readiness score, the first Capture surface and a
one_minute_path checklist with human labels, short descriptions,
blocked_by or degraded_reason diagnostics, and Capture/Review deep links.
When the runtime is available, the Capture summary is derived from
/v1/capabilities, so it only advertises active modalities: for example, local
audio/video metadata is shown separately from API-backed transcription. A fresh
local setup should reach status=ready;
configured_not_started means the MCP config was generated but the local runtime
still needs infinity-context up --lite. If Docker is running on a different
published port than the configured API URL, status --json and doctor --json
include docker_published_api_urls and suggested_api_url diagnostics instead
of silently failing with only ConnectError.
The fastest local proof for the first-memory flow is:
make infinity-context-local-visual-smokeIt starts the lite stack if needed, writes a Codex MCP config without embedding
the raw token, checks MCP memory_status, saves a sandbox Capture, waits for
consolidation, and verifies that pending review plus the Capture are visible in
the local memory browser.
Agent-assisted local setup is also available through MCP, but it is off by default so agents do not create files or start background services unexpectedly:
export MEMORY_MCP_LOCAL_RUNTIME_ENABLED=true
export MEMORY_MCP_LOCAL_RUNTIME_HOME="$HOME/.infinity-context"
export MEMORY_MCP_LOCAL_RUNTIME_REPO_DIR="$(pwd)"Then an agent can call memory_obsidian_prepare for the safe first-use flow:
dry-run local config, vault folders and plugin install, then apply after user
approval. It never starts Docker or runs mutating sync. Lower-level
memory_local_runtime_status, memory_local_runtime_init,
memory_local_runtime_doctor and dry-run memory_local_runtime_start remain
available for diagnostics. A real Docker start still requires a separate
explicit gate:
export MEMORY_MCP_LOCAL_RUNTIME_START_ENABLED=trueObsidian connector verification:
make infinity-context-obsidian-test
make infinity-context-obsidian-ui-e2einfinity-context-obsidian-test covers the Python connector, live HTTP sync smoke,
MCP stdio setup/sync smoke, and plugin typecheck/build without opening Obsidian.
infinity-context-obsidian-ui-e2e opens the real desktop Obsidian app and runs the
full WDIO plugin suite. Vaults with a custom Obsidian config folder are supported
through --obsidian-config-dir or MEMORY_MCP_OBSIDIAN_CONFIG_DIR.
Install once:
python3 -m venv .venv
.venv/bin/python -m pip install -e '.[dev,qdrant,openai,graphiti,mcp]'The Docker compose file has two practical profiles:
lite Postgres + Infinity Context Server, provider adapters disabled.
full Postgres + Qdrant + Neo4j + Infinity Context Server + workers, with OpenAI embeddings and Graphiti enabled.
Both profiles run separate projection and extraction workers. The extraction
worker only claims workload_class=extraction jobs, so file parsing can be
scaled independently from vector, graph and auto-memory projection work.
MEMORY_EXTRACTION_WORKER_LIMIT controls how many outbox jobs are claimed per
poll. MEMORY_EXTRACTION_WORKER_CONCURRENCY controls how many claimed
extraction jobs run at once in one process, and defaults to 1 for conservative
parser/provider resource isolation.
Recommended local proof:
make infinity-context-up-lite
make infinity-context-smoke
make infinity-context-mcp-smoke
make infinity-context-local-visual-smokeinfinity-context-smoke covers the SDK lifecycle path plus MemoryScope snapshot thread transfer.
Full provider mode needs OpenAI for embeddings and Graphiti. Do not paste the key into commands that will be saved in shell history. Read it silently or use an ignored local env file:
read -s OPENAI_API_KEY
export OPENAI_API_KEY
export MEMORY_OPENAI_API_KEY="$OPENAI_API_KEY"
make infinity-context-up-full
make infinity-context-smoke-fullSmall-team self-hosting uses a production-oriented Compose file with a built image, server deploy profile, explicit migrations and persistent volumes:
cp .env.selfhost.example .env.selfhost
docker compose --env-file .env.selfhost -f docker-compose.selfhost.yml up -d --build
make infinity-context-selfhost-smokeSee docs/self-hosted-team-deployment.md for the runbook, full provider mode
and backup notes.
MEMORY_OPENAI_API_KEY is used by the Infinity Context embeddings adapter.
OPENAI_API_KEY is also required because Graphiti reads the standard OpenAI
environment variable internally.
For a fully isolated paid canary, use a fresh Compose project and temporary Docker volumes. The script starts isolated Postgres, Qdrant and Neo4j, runs migrations, seeds defaults, starts the server, verifies Graphiti/Qdrant/OpenAI behavior, then tears everything down:
make infinity-context-clean-full-smokeIf the key is not already exported in the current shell, use the interactive wrapper. It reads the key with terminal echo disabled and passes it only through the canary process environment:
make infinity-context-full-provider-canary-interactiveFor local defaults, copy .env.example to .env and adjust non-secret provider
flags. Secrets should stay in your shell, .env.local, .env.full, or another
ignored file. Cognee is available as an optional adapter boundary, while the
default RAG path is Qdrant directly and the default temporal fact path is
Graphiti directly.
Common local targets are available in Makefile, for example make infinity-context-lint,
make infinity-context-test-unit, make infinity-context-eval, make infinity-context-db-upgrade,
make infinity-context-seed-defaults, make infinity-context-doctor, make infinity-context-up,
make infinity-context-server, make infinity-context-up-lite, make infinity-context-up-full,
make infinity-context-clean-full-smoke, make infinity-context-auto-memory-eval,
make infinity-context-auto-memory-quality and make infinity-context-mcp-smoke.
Memory Digest can be called through API, SDK, MCP or CLI. It is derived evidence,
not canonical memory, and pending suggestions are clearly marked as non-canonical.
For exact lookups or write/update/forget flows, agents should still call
memory_search or memory_get_fact.
GitHub Actions runs the same prompt-impacting gate on push and pull requests:
make PYTHON=python RUFF=ruff infinity-context-test-quality. Keep quality changes green
there before relying on memory in an agent prompt path.
Policy modes:
MEMORY_POLICY_MODE=disabled # no server writes or retrieval
MEMORY_POLICY_MODE=manual_only # explicit API writes, retrieval for reviewed/manual memory
MEMORY_POLICY_MODE=suggestions # review-gated memory mode
MEMORY_POLICY_MODE=active_context # active prompt-context mode
Auto-memory capture defaults are conservative:
MEMORY_CAPTURE_MODE=retrieve_only # no automatic capture writes
MEMORY_CAPTURE_MODE=capture_only # store captures, no suggestions
MEMORY_CAPTURE_MODE=suggest # captures can become pending suggestions
MEMORY_AUTO_APPLY_SAFE_ENABLED=false # separate switch for direct safe apply
MEMORY_CAPTURE_EXTRACTOR_PROVIDER=rule_based # rule_based, noop, or openai
MEMORY_CAPTURE_EXTERNAL_AI_ENABLED=false # external extractor egress kill switch
MEMORY_CAPTURE_EXTRACTOR_MODEL=gpt-4.1-mini # used only by the OpenAI extractor
MEMORY_MAX_PENDING_CAPTURES_PER_MEMORY_SCOPE=5000 # hook-loop ingress guard
MEMORY_MAX_PENDING_SUGGESTIONS_PER_MEMORY_SCOPE=500 # review queue ingress guard
MEMORY_AUTO_MEMORY_MODE is accepted as a compatibility alias for
MEMORY_CAPTURE_MODE on both Infinity Context Server and plugin hooks. When both are set,
MEMORY_AUTO_MEMORY_MODE wins.
Media extraction has product-plan usage guards in addition to parser limits:
MEMORY_PRODUCT_PLAN_TIER=free
MEMORY_PLAN_MEDIA_ANALYSIS_SECONDS_PER_MONTH=36000 # 10 hours
Audio/video uploads can pass estimated_media_seconds so Infinity Context can reserve
monthly media-analysis quota before enqueueing extraction. Clients can poll
/v1/asset-extractions/{job_id} for progress and /v1/usage?space_slug=...
for the current plan meter.
Long extraction jobs refresh their lease while parsing and honor cancellation
requests through MEMORY_EXTRACTION_CANCELLATION_POLL_SECONDS plus
MEMORY_EXTRACTION_HEARTBEAT_SECONDS; these values are also exposed by
/v1/capabilities.
rule_based keeps consolidation local and deterministic. openai is available
behind MemoryExtractorPort, but it requires both
MEMORY_CAPTURE_EXTERNAL_AI_ENABLED=true and MEMORY_OPENAI_API_KEY; otherwise
startup or consolidation fails closed without sending capture text to a provider.
Auto-memory quality is checked by make infinity-context-auto-memory-quality, which
includes deterministic golden capture metrics for review gating, redaction,
duplicate suppression, replay idempotency and auto_apply_safe safety.
The Python SDK exposes create_capture, get_capture, list_captures,
consolidate_capture, purge_capture and capture_diagnostics, so clients
should not hand-roll capture payloads.
Data classification:
public # embeddable and renderable evidence
internal # embeddable and renderable evidence
unknown # canonical storage and keyword recall, no embeddings by default
restricted # canonical storage only, excluded from context by default
Worker and operational commands:
MEMORY_SERVICE_TOKEN=local-dev-token .venv/bin/python -m infinity_context_server.worker --once
MEMORY_SERVICE_TOKEN=local-dev-token .venv/bin/python -m infinity_context_server.doctor
MEMORY_SERVICE_TOKEN=local-dev-token .venv/bin/python -m infinity_context_server.admin repair-projections --space project-alpha --memory_scope default --dry-run
MEMORY_SERVICE_TOKEN=local-dev-token .venv/bin/python -m infinity_context_server.admin import-memory_scope --space project-alpha --memory_scope default --file memory_scope-export.json --dry-run
MEMORY_SERVICE_TOKEN=local-dev-token .venv/bin/python -m infinity_context_server.eval run --suite small-golden
MEMORY_SERVICE_TOKEN=local-dev-token .venv/bin/python -m infinity_context_server.eval run --suite quality-goldenService tokens:
MEMORY_SERVICE_TOKEN=root-token .venv/bin/python -m infinity_context_server.admin token create --description app
MEMORY_SERVICE_TOKEN=root-token .venv/bin/python -m infinity_context_server.admin token create --space space_project_alpha --description project-alpha --expires-at 2026-12-31T23:59:59+00:00
MEMORY_SERVICE_TOKEN=root-token .venv/bin/python -m infinity_context_server.admin token create --space space_project_alpha --memory_scope memory_scope_default --description project-alpha-default
MEMORY_SERVICE_TOKEN=root-token .venv/bin/python -m infinity_context_server.admin token list
MEMORY_SERVICE_TOKEN=root-token .venv/bin/python -m infinity_context_server.admin token revoke --token-id tok_...The static MEMORY_SERVICE_TOKEN is a root token. Database service tokens are
stored as hashes only. A token created with --space is scoped to that space
id or slug and cannot access another space or unscoped diagnostics/list routes.
Add repeatable --memory_scope values to restrict a token to specific memory_scope ids
or external refs inside the allowed space.
Expired or revoked database tokens are rejected immediately. Token list output
contains ids, descriptions, scope, timestamps and status, never raw token values.
Graphiti local enablement requires Graphiti runtime dependencies plus Neo4j:
MEMORY_GRAPHITI_ENABLED=true \
MEMORY_GRAPHITI_NEO4J_URI=bolt://127.0.0.1:7687 \
MEMORY_GRAPHITI_NEO4J_USER=neo4j \
MEMORY_GRAPHITI_NEO4J_PASSWORD=<password> \
MEMORY_GRAPHITI_BUILD_INDICES=true \
MEMORY_SERVICE_TOKEN=local-dev-token \
.venv/bin/python -m infinity_context_server.mainThe client compatibility gateway is opt-in for older client integrations that
still call /api/v1/interview-memory/*. New integrations should prefer the
canonical /v1/* API or infinity_context_sdk.
MEMORY_DEFAULT_SPACE_SLUG=client-app \
MEMORY_LEGACY_CLIENT_ENABLED=true \
make infinity-context-up-liteSmoke the client compatibility gateway directly:
curl -X POST http://127.0.0.1:7788/api/v1/interview-memory/context \
-H "Authorization: Bearer local-dev-token" \
-H "Content-Type: application/json" \
-d '{
"session_id": "session-123",
"current_request": {
"id": "req-1",
"label": "request",
"text": "What memory is available for this session?"
}
}'Other apps can use canonical ids or external scope refs. External refs are the
recommended integration shape for app sessions because the server resolves them
to canonical space_id/memory_scope_id/thread_id behind the API boundary:
curl -X POST http://127.0.0.1:7788/v1/episodes \
-H "Authorization: Bearer local-dev-token" \
-H "Content-Type: application/json" \
-d '{
"space_slug": "project-alpha",
"memory_scope_external_ref": "default",
"thread_external_ref": "session-123",
"source_type": "system_audio",
"source_external_id": "event-123",
"text": "Candidate prefers FIFO queue for event processing.",
"idempotency_key": "event-123"
}'
curl -X POST http://127.0.0.1:7788/v1/context \
-H "Authorization: Bearer local-dev-token" \
-H "Content-Type: application/json" \
-d '{
"space_slug": "project-alpha",
"memory_scope_external_ref": "default",
"thread_external_ref": "session-123",
"query": "What did the candidate prefer for event processing?",
"token_budget": 512
}'SDK example:
from infinity_context_sdk import InfinityContextClient
client = InfinityContextClient(token="local-dev-token")
client.remember_fact(
space_id="space_project_alpha",
memory_scope_id="memory_scope_default",
text="Postgres is canonical truth.",
kind="architecture_decision",
source_refs=[{"source_type": "manual", "source_id": "note-1"}],
)
client.ingest_episode(
space_slug="project-alpha",
memory_scope_external_ref="default",
thread_external_ref="session-123",
source_type="system_audio",
source_external_id="event-123",
text="Candidate prefers FIFO queue for event processing.",
idempotency_key="event-123",
)
context = client.build_context(
space_slug="project-alpha",
memory_scope_external_ref="default",
thread_external_ref="session-123",
query="event processing preference",
token_budget=512,
)
typed_context = client.build_typed_context(
space_slug="project-alpha",
memory_scope_external_ref="default",
thread_external_ref="session-123",
query="event processing preference",
token_budget=512,
)
assert typed_context.answer_support.status in {"strong", "partial", "missing"}
suggestion = client.create_suggestion(
space_id="space_project_alpha",
memory_scope_id="memory_scope_default",
candidate_text="Qdrant is a derived index.",
kind="architecture_decision",
safe_reason="review_required",
source_refs=[{"source_type": "manual", "source_id": "note-2"}],
)
client.approve_suggestion(suggestion["data"]["id"], reason="reviewed")python -m venv .venv
.venv/bin/python -m pip install -e '.[dev]'
.venv/bin/ruff check .
.venv/bin/python -m pytest
.venv/bin/python -m infinity_context_server.eval run --suite small-golden
.venv/bin/python -m infinity_context_server.eval run --suite quality-golden