


Build Long-Term Memory for AI Agents with Graph and Vector Search
Use when building memory that lets AI agents keep knowledge between sessions. Turns files, URLs, and text into searchable graph and vector data, keeps each user's data separate with authentication, and lets you swap storage and model providers without changing core code.
To use this AI rule
## Split Agent Memory into Stages, from Taking In Data to Searching It
Define one explicit lifecycle for persistent knowledge: ingest raw files, URLs, or text into datasets; transform the material into entities, relationships, chunks, and summaries; retrieve relevant knowledge through a selected strategy; and enrich the stored graph with additional context or rules.
Keep these stages independently callable but compositionally consistent. Ingestion must create durable dataset and data records before transformation. Transformation classifies and chunks content, extracts structured relationships, summarizes where useful, and writes compatible graph and vector representations. Retrieval must apply authorization before returning results. Enrichment must preserve provenance and version metadata.
## Split the System into Layers So Core Code Never Calls Providers Directly
Separate versioned API or SDK entry points, lifecycle functions, pipeline orchestration, task execution, domain modules, infrastructure adapters, and external services. Dependencies should point downward through these layers so domain behavior does not import provider-specific clients directly.
Keep atomic graph concepts explicit: nodes or data points carry stable identifiers, types, descriptions, versions, and metadata; edges carry source, target, and relationship type; triplets represent subject-predicate-object facts. Use a knowledge-graph container to move coherent node and edge collections between extraction, storage, and retrieval.
## Build Pipelines from Small Tasks and Choose Each Search Strategy Explicitly
Represent processing steps as composable tasks that may run sequentially or in parallel when their data dependencies allow it. A pipeline should make classification, chunk extraction, structured graph extraction, summarization, and storage visible as separate units so failures and retries remain localized.
Route search through an explicit strategy type. Support graph traversal with completion, summary-backed graph context, triplet retrieval, vector and lexical chunk search, document summaries, temporal retrieval, natural-language-to-structured-query conversion, direct graph queries, and automatic strategy selection when justified. Every strategy must share authorization filtering and a stable result contract.
## Put Storage and Model Providers Behind Interfaces So They Can Be Swapped
Define separate interfaces for graph, vector, and relational storage. Select concrete engines through factories so local defaults, remote services, and production databases can change without altering domain tasks. Keep provider-specific connection logic, capability checks, and unsupported-operation errors inside the adapter.
Use the same boundary for language models, embedding engines, structured-output frameworks, file loaders, and object storage. Configuration chooses an implementation; domain code consumes the interface. When a backend lacks a capability such as direct graph queries or a retrieval mode, reject that operation explicitly instead of silently degrading to different semantics.
## Require Authentication Whenever Each User's Data Is Kept Separate
Model access as user to dataset to data, with read, write, delete, and share permissions enforced before graph or vector retrieval. Where supported, isolate storage per user and dataset so filtering mistakes cannot expose another tenant’s knowledge.
Treat backend access control and API authentication as one security posture. Enabling tenant isolation must require authentication; an explicit authentication-off setting must not override active access control. Single-user shared storage is a deliberate separate mode. Return an empty result rather than revealing that inaccessible records exist, while preserving enough internal diagnostics for authorized operators.
## Set Up the Language Model and Embeddings as a Pair, and Review Production Settings Together
Configure the language model and embedding provider as a pair. If only one is set, an implicit default for the other can create missing credentials, incompatible tokenization, or unexpected external calls. Validate both providers, endpoints, models, structured-output mode, and rate limits at startup.
Keep secrets in environment-backed configuration and expose optional integrations through installation extras or feature groups. Local defaults may use file-based relational, vector, and graph stores, but production deployment must review storage paths, remote-request permission, local-file access, raw-query permission, authentication, tenant isolation, and durable object storage together.
## Add New Storage or Search Strategies Through Fixed Registration Points
Add capabilities at the narrowest stable extension point: implement a task and register it in a pipeline, implement a storage interface for a new backend, add provider configuration behind the model gateway, extend document loaders for a new format, register a retrieval strategy, or define a graph model that extends the common data-point contract.
For ontology-grounded extraction, keep resolver, ontology source, and matching strategy configurable. Validate that extracted entity types and relationships conform to the selected semantic framework before storage. New extensions must declare required dependencies, supported capabilities, configuration fields, and failure behavior.
## Test Each Component and the Full Path from Taking In Data to Search
Organize tests by unit behavior, integration boundaries, command-line or API entry points, and task-specific behavior. Every feature needs focused tests, while storage adapters, model gateways, and other integrations need boundary tests against realistic configuration and failure responses.
Maintain at least one full lifecycle integration path from ingestion through transformation to retrieval, including asynchronous execution and authorization filtering. Test each public asynchronous function with direct awaiting or an event-loop runner. Run coverage, lint, formatting, and type checks according to repository policy, and keep tests aligned with the source-layer structure.
## Check Settings First, and Tell Empty Search Results Apart from Failures
Diagnose configuration failures before changing pipeline logic. Verify paired model and embedding settings, structured-output mode, tokenizer compatibility, database URLs and credentials, service availability, and rate-limit settings. Make provider fallback visible so a partial configuration cannot silently select an unintended remote service.
Distinguish an empty authorized result from a transport or parsing failure. Permission-filtered searches should not leak record existence; connection failures should identify the adapter and failed prerequisite; rate-limit failures should expose retry timing; structured-output failures should identify the configured extraction mode. Use structured logs and optional debug instrumentation, but never log credentials or sensitive retrieved content.
