Basic Provider
View SourceThis guide explains the built-in Jido.Memory.Provider.Basic implementation.
Basic is the reference provider for the simple jido_memory path. It keeps
the old ETS/store workflow intact while adapting it to the new provider-first
runtime surface.
What It Is
Jido.Memory.Provider.Basic is:
- built into
jido_memory - synchronous
- store-backed
- provider-contract compliant
- the default provider used by
Jido.Memory.Runtime
It is the simplest way to use the package and the reference implementation for provider behavior in core.
What It Uses Underneath
Basic uses Jido.Memory.Store as its persistence substrate.
That means:
- the default simple path still works
- ETS remains the default practical backend
- store adapters are still useful, but now they sit below the provider layer
Supported Operations
Basic supports:
remembergetretrieveforgetpruneingestexplain_retrievalconsolidatecapabilitiesinfo
This makes it the most complete built-in provider in core.
Configuration
Primary provider options:
namespacestorestore_opts
Example:
provider_opts = [
namespace: "agent:agent-1",
store: {Jido.Memory.Store.ETS, [table: :my_memory]}
]The default store is ETS:
{Jido.Memory.Store.ETS, [table: :jido_memory]}Redis is also supported as a storage backend for Basic:
provider_opts = [
namespace: "agent:agent-1",
store:
{Jido.Memory.Store.Redis,
[
command_fn: &MyApp.MemoryRedis.command/1,
prefix: "my_app:memory"
]}
]jido_memory still does not take a hard Redis dependency. Your application
provides the command bridge, typically through a client such as Redix.
Postgres is also available as an optional durable store for Basic. Your
application owns the Ecto repo and must include :ecto_sql and :postgrex.
provider_opts = [
namespace: "agent:my-agent",
store: {Jido.Memory.Store.Postgres, repo: MyApp.Repo}
]The adapter is migration-first by default. Use a regular application migration:
def change do
create table(:jido_memory_records, primary_key: false) do
add :namespace, :text, null: false, primary_key: true
add :id, :text, null: false, primary_key: true
add :class, :text, null: false
add :kind, :text, null: false
add :text, :text
add :source, :text
add :observed_at, :bigint, null: false
add :expires_at, :bigint
add :record, :binary, null: false
end
create index(:jido_memory_records, [:namespace, :observed_at, :id])
create index(:jido_memory_records, [:namespace, :class, :observed_at, :id])
create index(:jido_memory_records, [:namespace, :kind, :observed_at, :id])
create index(:jido_memory_records, [:expires_at], where: "expires_at IS NOT NULL")
endFor development or integration tests, ensure_ready/1 can create the table and
indexes when ensure_table?: true is set:
store:
{Jido.Memory.Store.Postgres,
[
repo: MyApp.Repo,
table: "jido_memory_records",
ensure_table?: true
]}The Postgres store is basic durable storage for canonical records. It is not a vector search adapter, pgvector integration, or analytics-oriented schema.
If you want Redis to be the explicit provider identity in core, use provider: :redis instead of :basic with a Redis store override:
opts = [
provider: :redis,
provider_opts: [
namespace: "agent:agent-1",
command_fn: &MyApp.MemoryRedis.command/1,
prefix: "my_app:memory"
]
]Direct Runtime Usage
alias Jido.Memory.Runtime
alias Jido.Memory.Store.ETS
:ok = ETS.ensure_ready(table: :basic_memory)
opts = [
provider: :basic,
provider_opts: [
namespace: "agent:agent-1",
store: {ETS, [table: :basic_memory]}
]
]
{:ok, record} =
Runtime.remember(%{id: "agent-1"}, %{
class: :semantic,
kind: :fact,
text: "Basic provider stores canonical records through Jido.Memory.Store."
}, opts)Plugin Usage
Jido.Memory.BasicPlugin is the Jido integration layer for Basic.
use Jido.Agent,
name: "memory_agent",
default_plugins: %{
__memory__:
{Jido.Memory.BasicPlugin,
%{
store: {Jido.Memory.Store.ETS, [table: :my_agent_memory]},
namespace_mode: :per_agent
}}
}The plugin replaces Jido's built-in :__memory__ default plugin and keeps only
namespace and store state. Runtime resolves those into basic provider options
when action and agent calls are dispatched.
Retrieval Behavior
Basic retrieval is structured and deterministic.
It uses canonical Query fields such as:
namespaceclasseskindstags_anytags_alltext_containssinceuntillimitorder
It does not do semantic/vector ranking.
That makes it useful for:
- deterministic tests
- simple agent memory
- local development
- baseline provider behavior
Ingest, Explain, and Consolidate
Ingest
Basic supports canonical ingest requests and stores each record through the
underlying store adapter.
It is useful for:
- batch inserts
- migration utilities
- importing already-normalized records
Explain Retrieval
Basic can produce a simple canonical explanation describing:
- returned hit count
- match metadata
- rank and score values when present
This is not a semantic explanation system. It is a deterministic explanation of the basic provider’s retrieval result.
Consolidate
Basic consolidation maps to lifecycle cleanup of expired records.
Today this is intentionally simple:
- prune expired records
- return a canonical
ConsolidationResult
Option Resolution
The Basic provider resolves namespace and store from several places:
- explicit runtime opts
- attrs or query values
- plugin state
- provider opts
- target-derived fallback namespace
That behavior is important because it lets the same provider work:
- directly through runtime calls
- through plugin-backed agent calls
- through action execution contexts
When To Use Basic
Use Basic when you want:
- the simplest supported memory path
- deterministic behavior
- provider-contract reference behavior
- store-backed memory without backend-native complexity
Reach for external providers when you need:
- semantic/vector retrieval
- backend-native memory systems
- richer domain-specific data models
Limitations
Basic is intentionally not a full advanced memory system.
It does not try to provide:
- semantic embeddings
- taxonomy layers
- knowledge graphs
- long-term orchestration
- backend-native advanced retrieval semantics
Its job is to be simple, stable, and reliable.