How memory works
Reference for the three forms of memory (Workspace, Long-term memory, and the secrets Vault) and the skill that teaches an agent to use them, with the mount and configuration details.
AIStor Memory is the memory your agents keep. The agent uses one mount of a MinIO AIStor Memory Bucket. It works in that mount and remembers through it. Everything is stored in your AIStor, under your keys, and AIStor Memory teaches the agent how to use it.
AIStor Memory keeps memory in three forms on one Memory Bucket. Each form has its own purpose and lifecycle:
- Workspace: the files the agent is working on.
- Long-term memory: what the agent learned, kept beside the data it came from.
- Vault: the secrets the agent needs to act.
The skill teaches the agent to use all three.
The Memory Bucket — one mount for all three forms
AIStor Memory mounts only a Memory Bucket. A Memory Bucket is an AIStor
bucket built for agents: compressed, version-tracked, and encrypted
when AIStor has a KMS, with its own Memory API. Create one with aimem create, or convert an
existing bucket with aimem convert. See the CLI reference for
all the bucket commands (create, convert, list, get, delete,
credentials).
At mount, AIStor Memory checks the target over the Memory API. It refuses a
plain bucket (not a Memory Bucket), and this check cannot be turned off. The
mount also needs an endpoint, real signing credentials, and a licensed AIStor
server; see Prerequisites for the full list.
Workspace — active work
The Workspace is the mount the agent works in. It gives a coding agent (Claude Code, Cursor, Codex, …) or a sandbox VM what it needs:
- Read project files and agent memory files (
CLAUDE.md,.claude/,AGENTS.md,MEMORY.md,.cursorrules,.cursor/). - Edit those files in place with
git, editors,sqlite, and the rest of the toolchain, as on any local disk. - Save the result to the Memory Bucket, atomically, when each file is closed. The next session mounts the same files byte for byte.
How it works — mandatory workspace mode
Every file opened for writing is staged in a local directory, the staging
directory. The staged file is the agent's working copy. On close() or
fsync(), AIStor Memory uploads it to S3 atomically. Random writes, O_RDWR,
and O_TRUNC all work, because they change the staged file, not the remote
object. mmap and copy_file_range return ENOSYS, and the kernel falls
back to read and write on the staged file, so tools that use memory-mapped
I/O still work. Hard links are not supported (link() returns EPERM).
The staging directory is required. Set it in one of three ways:
- the
local:key in the--config <FILE>YAML file (recommended), - the
--local <DIR>CLI flag, or - the
AIMEM_LOCALenvironment variable.
If you set more than one, the CLI flag or environment variable wins over the
config file. There is no default. If none is set, the mount stops before it
starts with this error:
a local staging directory is required; set --local <DIR>, the AIMEM_LOCAL env var, or the `local:` key in --config.
AIStor Memory logs the staging path at mount. Size the staging volume for the files the agent has open for writing at one time; NVMe is recommended.
Config file (--config <FILE>)
Each key in the --config <FILE> YAML file is a long CLI flag with dashes
changed to underscores (endpoint_url, metadata_ttl, …). Two more rules
apply:
versionis required and must be the quoted string"1.0". An unquotedversion: 1.0is read as a number and rejected.- An unknown key is an error.
Put the staging directory, the endpoint, and any other settings in the file. The command line then carries only the Memory Bucket, the mount point, and the config path:
# /etc/aimem/mount.yaml
version: "1.0"
local: /var/cache/aimem
endpoint_url: https://aistor.example.com
agent: claude# Signing credentials come from AIMEM_ACCESS_KEY / AIMEM_SECRET_KEY in the
# environment, never from flags or the config file.
aimem my-memory-bucket /workspace --config /etc/aimem/mount.yamlThe Memory Bucket name, the mount point, and --config itself always come
from the command line. They are never config-file keys.
Long-term memory — what the agent learned
Long-term memory is knowledge that shapes future work, kept beside the data that produced it. It takes five forms:
- memory files, loaded onto local disk at mount;
- per-object annotations under
.aimem/annot/…, notes stored next to the data they describe; - object metadata and tags, readable as extended attributes (xattrs):
S3 user metadata as
user.s3.meta.*and tags asuser.s3.tags.*; - server-side search across the whole Memory Bucket;
- the agent's biography, a record of what it did, as queryable tables.
Annotations are a tech preview. They can be enabled for an AIStor deployment under guidance from MinIO support. Avoid using them with production data until annotations are generally available (GA).
The aimem skill teaches the agent to use all of them.
Agent-memory warmup
On every mount, AIStor Memory copies the agent's memory files into the
--local directory. The first read of CLAUDE.md, .claude/…, and the
others then comes from local disk instead of S3.
The agent: config key (or the --agent flag) picks which files to load:
| claude | CLAUDE.md, .claude/ |
| codex | AGENTS.md, .agents/, MEMORY.md |
| cursor | .cursorrules, .cursor/, AGENTS.md |
| auto | All of the above |
Warmup runs in the background and does not delay the mount, which you can use
at once. Each file is read from local disk as soon as warmup has copied it.
Warmed files share the --local directory with staged writes; there is no
separate memory cache.
Custom warmup manifest
To load more files than the defaults for the agent type, set the
agent_manifest: key in the config file to the path of a JSONL manifest. There
is no --agent-manifest CLI flag. Each line is a JSON object with key and
size, and optionally etag and priority (0=Low, 1=Medium, 2=High,
3=Critical; the default is Medium):
{"key": "CLAUDE.md", "size": 4096, "priority": 3}
{"key": "docs/runbook.md", "size": 18234}If you leave out etag, AIStor Memory sends one HEAD request per entry at
warmup to look up the etag and size. For a few files this costs little. For a
large manifest, fill in etag (for example, with
--generate-workspace-manifest) to avoid the extra requests. Warmed files stay
ordinary read-write files; warmup only fills the read cache.
AIStor Memory loads the manifest in addition to the agent-type defaults. Keys in both are loaded once.
To create a starting manifest, add --generate-workspace-manifest <FILE> to
the mount command
(aimem <bucket> <mountpoint> --generate-workspace-manifest <FILE>).
AIStor Memory writes the agent's memory paths to FILE as JSONL and exits
without mounting. Edit the file (remove keys, set priorities), then point the
agent_manifest: key at it.
Search over data at rest
aimem search <bucket> -e <regex> searches the Memory Bucket's objects on
the server. The server decrypts and decompresses each object, matches it,
and returns the results, so the agent does not download the workspace:
# Every -e pattern must match (AND); RE2 syntax, one line at a time.
aimem search my-memory-bucket -e 'TODO' -e 'auth' --ext md --ignore-case --contentFlags:
-e/--pattern: required and repeatable; every pattern must match.--prefix: search only keys under this prefix.--ext: repeatable; search only files with this extension.--ignore-case: match without regard to case.--content: print matching lines asname:line:textinstead of only the object names.--multiline/-U: let a pattern match across line breaks.
Search also takes the usual Memory Bucket connection flags. Patterns use RE2
syntax (no backreferences or lookaround). Search needs the memory:Search
action on a paid-tier server.
To limit a credential to part of a Memory Bucket, add a memory:prefix
condition to its memory:Search grant, the same way s3:prefix limits
s3:ListBucket. Without the condition, the grant covers the whole Memory
Bucket. A credential with the condition is denied a search that gives no
--prefix, or a prefix outside its scope.
The biography — what the agent did
aimem bio serve runs an OpenTelemetry collector beside the agent. The
traces, logs, and metrics the agent's harness already sends over standard
OTLP are stored as Apache Iceberg tables in the same Memory Bucket. What a run
did is then kept beside what it produced. Every Memory Bucket supports these
tables, whether you created it or converted it with aimem convert, so
there is no separate warehouse to set up.
SKILLS — the agent's mount manual
The skill teaches an AI agent to use everything above. AIStor Memory includes
an Agent Skill named aimem that explains how to
find the mount, how saving files works, where to keep long-lived memory, how
to read object metadata, how to leave and read annotations, and how to search
the Memory Bucket. The skill is a folder with a SKILL.md file (YAML
frontmatter, name: aimem) and a references/ directory that the agent reads
when it needs to:
aimem/
├── SKILL.md
└── references/
├── navigation.md # locate your mount point (findmnt) + how the root maps to objects
├── workspace.md # POSIX semantics: staging, close-to-commit, rename
├── memory.md # where CLAUDE.md / AGENTS.md / MEMORY.md live
├── metadata.md # read S3 user-metadata + tags as xattrs
├── annotations.md # durable per-object notes via .aimem/annot/
└── search.md # server-side regex over Memory Bucket memory (aimem search)The skill names no bucket, region, or mount point. It teaches the agent to
find its mount with findmnt -S aimem, so the same skill works on any AIStor
Memory mount. It is built into the binary, so it also works in sandboxes with
no internet access.
The agent finds the skill in one of three ways. The first two happen automatically on every mount.
Tier 1 — read-time preamble (automatic, in the workspace)
When the agent reads an instruction file from the mount (CLAUDE.md,
AGENTS.md, .cursorrules), AIStor Memory adds a short preamble to the start
of what the agent reads. The preamble tells the agent it is in an AIStor Memory
workspace and points it to the installed skill (Tier 2). This works even if
the repository has no CLAUDE.md of its own.
The preamble is added in memory only and is never written to the bucket.
AIStor Memory turns it off when the mount root is a git repository, so a
tracked file never shows a change. To turn it off yourself, set
AIMEM_PREAMBLE_OVERLAY=0.
Tier 2 — installed skill (automatic, in $HOME)
On every mount, AIStor Memory also installs the aimem skill in the agent's
home directory, so the agent can still find it outside the workspace:
~/.agents/skills/aimem/ # read by Codex CLI, Cursor, Gemini CLI, Copilot
~/.claude/skills/aimem/ # read by Claude Code (honors CLAUDE_CONFIG_DIR)These agents load skills from these paths on their own. The install needs no
network. It never overwrites an existing SKILL.md, and it writes the folder
in one atomic step, so a crash cannot leave a partial skill.
The install is skipped when $HOME is under the mount point, because the
skill would then be written into the bucket instead of local disk. To turn the
install off, set AIMEM_INSTALL_SKILL=0.
Tier 3 — public skill (host-side, for out-of-sandbox agents)
Some agents reason outside the sandbox: the model runs in a control plane and only sends commands into the sandbox, as with the OpenAI Agents SDK. Such an agent never sees files installed inside the sandbox, so Tiers 1 and 2 do not reach it.
For these agents, install the aimem skill on the host from MinIO's public
skills repository, minio/skills, before
the run starts:
npx skills add minio/skills/aimemThe skill in minio/skills is the same SKILL.md and references/ that are
built into the binary.
Vault — secrets an agent needs to act
The Vault holds the secrets an agent needs to act, such as an OPENAI_API_KEY,
a GITHUB_TOKEN to push a branch, an NPM_TOKEN to publish, or a database
connection string.
Do not put these in a .env file in the workspace. The agent can read that
file, and an untrusted prompt can then persuade the agent to send it
elsewhere (prompt injection).
AIStor Memory follows the Docker and Kubernetes model instead. A launcher outside the sandbox fetches only the secrets the agent is granted and passes them to the agent process as environment variables. The launcher keeps the credential for the secret store; the agent never receives it. Nothing readable is written to the workspace.
Secrets can come from two places:
- The Memory Bucket (the default). The Memory API stores secret values
encrypted on the server. You manage them with
aimem secret put,get,list, anddelete. Theaimemclient only passes values through; it never writes them to disk or to the workspace. - An external store you already use, such as HashiCorp Vault/OpenBao KV or a cloud secret manager. Use this when your organization requires that store as the single source of secrets.
aimem secret provision takes exactly one source. To use the Memory Bucket:
# AIMEM_ACCESS_KEY and AIMEM_SECRET_KEY are set in the launcher's environment.
# The agent sees only the granted secret values.
aimem secret provision \
--bucket my-memory-bucket \
--endpoint-url https://aistor.example.com \
--grant OPENAI_API_KEY=openai \
--grant GITHUB_TOKEN=gh-pat \
-- claudeTo use an HTTP secret store:
aimem secret provision \
--store-endpoint https://vault.example.com \
--store-token "$VAULT_TOKEN" \
--grant OPENAI_API_KEY=openai \
-- claude
# With no command after --, print KEY=VALUE lines for the caller to use:
eval "$(aimem secret provision --bucket my-memory-bucket \
--endpoint-url https://aistor.example.com \
--grant OPENAI_API_KEY=openai)"provision runs the agent as a child process and exits with its status.
Before it starts the agent, it removes these variables from the agent's
environment: AIMEM_SECRET_STORE_TOKEN, AIMEM_SECRET_STORE_ENDPOINT,
AIMEM_ACCESS_KEY, AIMEM_SECRET_KEY, AIMEM_SESSION_TOKEN,
AIMEM_CREDENTIALS_FILE, AIMEM_ENDPOINT_URL, and AIMEM_REGION. The agent
holds only the secret values it was granted. It cannot list or fetch anything
else from the store.
Managing secrets in the Memory Bucket
Four commands manage the secrets stored in a Memory Bucket:
# Store a secret. Pipe the value on stdin rather than using --value
# (a --value is visible in the process list and shell history):
printf '%s' "$OPENAI_API_KEY" | aimem secret put my-memory-bucket openai
aimem secret put my-memory-bucket gh-pat --value "$GITHUB_TOKEN"
# Print a secret's value to stdout:
aimem secret get my-memory-bucket openai
# List the secret names in a Memory Bucket:
aimem secret list my-memory-bucket
# Delete a secret:
aimem secret delete my-memory-bucket openaiEach command takes the same connection flags and AIMEM_* environment
variables as the other Memory Bucket commands (endpoint, region, access key,
secret key, and optional session token). aimem secret provision --bucket <name>
reads these secrets back to give to an agent.
What makes it different
Secrets stay in your own store: the Memory Bucket or your external store,
never a vendor's database. The agent receives only the values it was granted,
as environment variables at launch. It never holds the store or signing
credentials and cannot list or fetch more. A .env file in the bucket, by
contrast, is plaintext that one prompt injection can expose.
Configuration
aimem secret provision needs exactly one secret source: --bucket (the
AIStor Memory API) or --store-endpoint (an HTTP store). With neither, it
fails. --grant is always required; the other flags depend on the source.
--grant VAR=name (repeatable) sets environment variable VAR to secret
name:
| Env var | Flag | Meaning |
|---|---|---|
| — | --grant VAR=name | Bind env var VAR to store secret name |
Source A: Memory Bucket (--bucket <name>). Uses the Memory API with the
standard Memory Bucket connection settings:
| Env var | Flag | Meaning |
|---|---|---|
AIMEM_ENDPOINT_URL | --endpoint-url | Memory-API / S3 endpoint (required) |
AIMEM_ACCESS_KEY | --access-key | Access key (required) |
AIMEM_SECRET_KEY | --secret-key | Secret key (required) |
AIMEM_REGION | --region | SigV4 region (optional, default us-east-1) |
AIMEM_SESSION_TOKEN | --session-token | Session token (optional) |
Source B: HTTP store (--store-endpoint <url>). Authenticates to your
store with a bearer token:
| Env var | Flag | Meaning |
|---|---|---|
AIMEM_SECRET_STORE_ENDPOINT | --store-endpoint | Secret-store base URL |
AIMEM_SECRET_STORE_TOKEN | --store-token | Bearer token (optional; only valid with --store-endpoint; held launcher-side) |
With a command after --, provision launches it with the secrets set and
the store and signing credentials removed. Without one, it prints KEY=VALUE
lines for the caller to use.
What aimem does not ship
AIStor Memory needs nothing beside the object store you already run. Reads are
served from the one --local directory: memory files are loaded there at
mount, and other files are fetched from S3 when first read and kept there.
There is no separate memory cache, multi-disk block cache, shared remote cache
cluster, or S3 Express bucket cache.
Quick start
Install AIStor Memory, create a Memory Bucket on MinIO AIStor, and mount it for an agent in about five minutes.
Architecture
How AIStor Memory presents an agent's memory as files, how reads and writes reach the Memory Bucket, what the local cache holds, and how the agent skill is installed.