Enable and configure memory
This is the admin quickstart: the minimal, ordered steps to take inference memory from "installed" to "an organization is using it." Three steps — point memory at an embedding model, provision your organization, and turn on the MCP server so agents can reach the memory tools. Everything here is copy-pasteable.
Before you start, decide how your organization is sourced from identity — that is the one enterprise-specific choice. Memory works with no auth configuration (every caller falls into the default organization), but a real multi-tenant deployment sources the organization from the caller's token. See Enterprise authentication for memory. The concepts behind the boundary are in Memory tenancy and isolation.
Table of contents
Step 1 — Point memory at your embedder
Recall quality is entirely a function of the embedding model. Out of the box memory uses a local, zero-dependency hashing embedder at dimension 384 — good for a smoke test, but not semantic. For real recall, point memory at a model. The full provider matrix (self-hosted HTTP, Bedrock, Vertex, Azure, multimodal image models), credential wiring, and dimension locking are documented in Inference memory embeddings; this step shows the two most common enterprise starting points.
The embedding settings live under plugins.memory.embedding.* and are dynamic — set them with PUT _cluster/settings and the provider hot-swaps with no restart. Secrets (API keys, cloud credentials) are keystore-only and read at node startup.
plugins.memory.embedding.dimension is locked into the memory index when it is first created — set it to match your model before the first remember (or before you provision an organization). Changing the width later requires a re-index. Default is 384.
Keyless AWS Bedrock (recommended on EKS)
On EKS, use IAM Roles for Service Accounts (IRSA) — no static keys live in the cluster. Grant the pod's IAM role bedrock:InvokeModel on your embedding model, then:
PUT _cluster/settings
{
"persistent": {
"plugins.memory.embedding.provider": "bedrock",
"plugins.memory.embedding.region": "us-east-1",
"plugins.memory.embedding.model": "amazon.titan-embed-text-v2:0",
"plugins.memory.embedding.dimension": 1024
}
}
Credentials resolve through the AWS SDK default chain (which finds the IRSA web-identity role), so no keystore entries are needed. Titan Embed Text v2 supports 256, 512, or 1024 dimensions — set dimension to match. See Inference memory embeddings for the off-EKS static-key fallback and PrivateLink endpoints.
Self-hosted / vLLM (sovereign, in-network)
For a model you host yourself — vLLM, a private model server, or any endpoint that speaks the OpenAI /embeddings shape — use the http provider. Nothing leaves your network.
bin/lucenia-keystore add plugins.memory.embedding.api_key # only if your endpoint requires auth
Restart the node if you added the keystore secret, then:
PUT _cluster/settings
{
"persistent": {
"plugins.memory.embedding.provider": "http",
"plugins.memory.embedding.endpoint": "https://vllm.internal.example:8000/v1/embeddings",
"plugins.memory.embedding.model": "intfloat/e5-large-v2",
"plugins.memory.embedding.dimension": 1024
}
}
Set dimension to the model's output width.
Confirm the active embedder
GET /_plugins/_memory/stats
The embedding block reports the live mode (model id), dimension, and whether it is semantic and multimodal. Confirm semantic is true before you rely on recall.
Step 2 — Provision your organization
Each organization's long-term memory lives in its own physical index (see Memory tenancy and isolation). An administrator provisions that index once, per organization, with:
PUT /_plugins/_memory/org/acme
With no body, the organization adopts the deployment's configured embedding model and dimension (from Step 1) and its physical indices are created. The response echoes the stored policy (any non-secret provider fields you set — provider, endpoint, region, and so on — are echoed too):
{
"org": "acme",
"model": "amazon.titan-embed-text-v2:0",
"dimension": 1024,
"created_at": 1751500000000
}
The organization name in the path must match [a-z0-9][a-z0-9-]{0,62} (lowercase alphanumerics and hyphens).
This endpoint is admin-gated. It is granted by the memory_full_access role via the cluster permissions cluster:admin/lucenia/memory/org/put, cluster:admin/lucenia/memory/org/get, and cluster:admin/lucenia/memory/org/reembed. The end-user roles memory_read (the read verbs — recall, history, audit, stats, usage, model/get — plus conversation and message reads) and memory_read_write (all reads plus the write verbs, model/put, and conversation/message writes) do not include organization provisioning or re-embed. Grant memory_full_access only to operators.
Inspect provisioned organizations
GET /_plugins/_memory/org # list every provisioned organization
GET /_plugins/_memory/org/acme # one organization's policy
Both return an orgs array; each entry reports the organization's org, its embedding configuration (model, dimension, provider, and any provider-specific fields), and created_at:
{
"orgs": [
{ "org": "acme", "model": "amazon.titan-embed-text-v2:0", "dimension": 1024, "created_at": 1751500000000 }
]
}
The declared allowed_models set (below) is not echoed here — a user reads the models available to them through GET /_plugins/_memory/model (see Using memory in your organization).
Per-organization embedding models
Each organization can pin its own embedding model at provisioning time — for example, one tenant on a 1024-dim Bedrock Titan model and another on a 768-dim self-hosted model — each embedded and recalled in its own physically isolated index. That is why the long-term index name embeds a model slug (.plugins-memory-longterm-<org>__<model-slug>): different organizations, different models, different backing indices, one alias each.
Pass the organization's embedding configuration in the provisioning body. Any field you omit defaults to the deployment's plugins.memory.embedding.* value, so a bare request (just the org name) provisions the organization on the deployment embedder:
PUT /_plugins/_memory/org/acme
{
"provider": "bedrock",
"model": "amazon.titan-embed-text-v2:0",
"dimension": 1024,
"region": "us-east-2"
}
All embedding fields are optional:
| Field | Purpose |
|---|---|
provider | hashing / http / bedrock / vertex / azure / azure_vision |
model | the embedding model id |
dimension | the vector dimension the organization's index is created at |
endpoint | endpoint URL (for http) or a provider endpoint override |
region | AWS region (for bedrock) |
gcp_project / gcp_location | GCP project + region (for vertex) |
azure_api_version / azure_vision_model_version | Azure REST / model versions |
allowed_models | Array of embedding specs a user in this org may self-select (see Let users choose their model) |
Credentials are never part of this request. The API key and AWS/GCP/Azure secrets stay in the node keystore (shared, keystore-only settings); only the non-secret shape of the model — provider, model, dimension, endpoint, region — travels in the request and is stored in the (readable) organization policy. A per-organization model that resolves through keyless cloud identity (IRSA / Workload Identity / Managed Identity) or a shared keystore key therefore needs no per-organization secret.
Changing an organization's model re-provisions but does not migrate existing memories automatically. Re-provisioning an organization with a different model creates the new (org, model) index and atomically re-points the organization's alias to it; the organization's existing memories stay in the previous index (now detached from the alias) and are not recalled until you run a re-embed backfill against them (see Migrate memories to a new model). When the embedding space changes, the response carries a note field saying so. Re-provisioning with the same embedding configuration is idempotent.
Let users choose their model
An organization can offer its users a menu of embedding models rather than a single default. The admin declares that menu as allowed_models — an array of embedding specs — on the organization policy:
PUT /_plugins/_memory/org/acme
{
"provider": "bedrock",
"model": "amazon.titan-embed-text-v2:0",
"dimension": 1024,
"region": "us-east-2",
"allowed_models": [
{ "provider": "bedrock", "model": "amazon.titan-embed-text-v2:0", "dimension": 1024, "region": "us-east-2" },
{ "provider": "http", "model": "intfloat/e5-large-v2", "dimension": 1024, "endpoint": "https://vllm.internal.example:8000/v1/embeddings" }
]
}
Each entry is a full embedding spec (the same non-secret fields as the organization body above, so each allowed model carries its own dimension and provider wiring). A user then self-selects one by model id with PUT /_plugins/_memory/model — see Using memory in your organization. A user's pinned model gets its own (org, model) long-term index; the organization default stays behind the alias for users who never select. Credentials for an allowed model still come only from the keystore or keyless cloud identity — never from this request.
allowed_models is optional. Omit it and the organization has a single default model and per-user selection is refused with 400. The set is not returned by GET /_plugins/_memory/org; a user reads their own menu and effective model through GET /_plugins/_memory/model.
Migrate memories to a new model (re-embed)
When you change an organization's default model, its existing memories stay behind in the old model's index and stop being recalled. A re-embed backfill migrates them: it reads the memories still held in the previous model's index, re-embeds each with the organization's current default model, writes them into the current model's index, and (by default) drops the old index once every memory has moved.
POST /_plugins/_memory/org/acme/reembed
{
"from_model": "amazon.titan-embed-text-v1",
"drop_source": true
}
| Field | Default | Purpose |
|---|---|---|
from_model | (required) | The previous model id whose index is the migration source. |
drop_source | true | Delete the source index after a complete migration; set false to retain it for audit. |
The response reports what moved:
{
"org": "acme",
"from_model": "amazon.titan-embed-text-v1",
"to_model": "amazon.titan-embed-text-v2:0",
"migrated": 1840,
"source_dropped": true,
"truncated": false
}
- Bounded and repeatable. A single pass migrates up to a fixed cap of memories; if more remain,
truncatedistrue— call the endpoint again until it returnsfalse. Because memory ids are content-addressed, re-embedding is idempotent, so repeating a pass never duplicates a memory.source_droppedis onlytrueon a complete, non-truncated migration. - Refuses a no-op. Re-embedding from the organization's current default model is rejected with
400— there is nothing to migrate. - Admin-only. Granted by
memory_full_accessviacluster:admin/lucenia/memory/org/reembed.
Step 3 — Enable the MCP server
Agents (for example, a coding assistant) reach the memory tools over Lucenia's Model Context Protocol (MCP) server. It is off by default. Turn it on with the dynamic cluster setting:
PUT _cluster/settings
{
"persistent": {
"plugins.ml_commons.mcp_server_enabled": true
}
}
The MCP server then serves at:
POST /_plugins/_ml/mcp
(The same path answers GET with 405 Method Not Allowed — MCP is a POST protocol.) When the setting flips on, the memory tools are registered automatically — there is no manual tool-registration step. Reaching the MCP server is gated by the cluster permission cluster:admin/lucenia/ml/mcp/server, which is included in the memory_full_access role.
Connecting an MCP-capable client (a coding assistant or IDE agent) to this endpoint with a user's token — and, if your organization offers a menu of models, letting the user select one — is covered in Using memory in your organization.
Settings reference
Tenancy — how the caller's organization is sourced (details and per-provider recipes in Enterprise authentication for memory):
| Setting | Default | Purpose |
|---|---|---|
plugins.memory.tenancy.org_attribute | attr.jwt.org | Identity attribute the organization is read from. |
plugins.memory.tenancy.org_backend_role_prefix | (empty — disabled) | Prefix that selects a backend role as the organization source. |
plugins.memory.tenancy.require_org | false | When true, an identity with no resolvable organization is refused (403) instead of falling to default. |
All three are node-scoped and dynamic (settable with PUT _cluster/settings).
Embedding — see Inference memory embeddings for the complete matrix. The load-bearing two:
| Setting | Default | Purpose |
|---|---|---|
plugins.memory.embedding.provider | (empty — memory disabled) | http, bedrock, vertex, azure, azure_vision, or hashing (dev/CI). Memory is disabled until this (or endpoint) is set. |
plugins.memory.embedding.dimension | 384 | Vector width. Locked at index creation. |
LLM (optional — distillation and abstractive rollup) — off by default; see Inference memory embeddings for the full family:
| Setting | Default | Purpose |
|---|---|---|
plugins.memory.llm.provider | (empty — inference off) | Set to bedrock to enable infer/distillation and abstractive rollup. |
plugins.memory.llm.model | amazon.nova-lite-v1:0 | Chat model (Bedrock Converse). |
plugins.memory.llm.region / .endpoint / .max_tokens | — / — / 512 | AWS region, optional endpoint override, max tokens per call. |
Audit (optional — operation history) — off by default; see Security, privacy, and data sovereignty:
| Setting | Default | Purpose |
|---|---|---|
plugins.memory.audit.enabled | false | Master switch for the per-org audit trail (POST /_plugins/_memory/audit). |
plugins.memory.audit.record_reads | false | Also record read operations (high-volume). |
plugins.memory.audit.retention_days | 365 | Retention window; <= 0 retains indefinitely. |
plugins.memory.audit.redact_profile | fedramp | Compliance profile applied to audit notes (none/pii_basic/gdpr/ccpa/hipaa/pci_dss/soc2/fedramp/iso_27001/nist_800_53). |
Conversation store (redaction) — the compliance redaction applied to the org-tenant-scoped conversation store (/_plugins/_memory/conversations); see Conversation management:
| Setting | Default | Purpose |
|---|---|---|
plugins.memory.conversation.redact_profile | none | Compliance profile applied to conversation/message content on write (never stored in the clear) and read. none disables redaction. Same profile values as audit.redact_profile. |
plugins.memory.conversation.redact_exempt_roles | (empty) | Roles that see stored conversation content in the clear at read time. |
plugins.memory.conversation.redact_exempt_backend_roles | (empty) | Backend roles exempt from read-time conversation redaction. |
plugins.memory.conversation.redact_exempt_when_no_identity | false | Fail-closed: a caller with no verified identity is redacted unless true. |
All four are node-scoped and dynamic. Note the defaults differ by design: the audit note redaction defaults to fedramp (audit records are compliance evidence, so they redact out of the box), while the conversation store redaction defaults to none (opt-in) — a governance blueprint sets it per regime. Write-time redaction is never bypassed by an exemption; exemptions only reveal stored content at read time.
MCP:
| Setting | Default | Purpose |
|---|---|---|
plugins.ml_commons.mcp_server_enabled | false | Enables the MCP server at POST /_plugins/_ml/mcp. |
Related pages
- Memory tenancy and isolation — the organization/user boundary and per-organization indices.
- Enterprise authentication for memory — source the organization from your identity provider.
- Inference memory embeddings — the full embedding-provider matrix.
- Inference memory — the verbs.
- Monitoring memory usage and data residency — per-org storage, tokens, and trust-boundary egress (
GET /_plugins/_memory/usage/_allfor every org).