AIStor Memory — the agent's memory, in three forms
The full feature surface across the three forms of one memory — Workspace, Long-term memory (warmup, annotations, metadata, search, structured memory, skills), and the secrets Vault — with all the operator reference.
AIStor Memory is the memory your agents keep. It is one thing the agent uses: a mount of a MinIO AIStor Memory Bucket (a cortex) that the agent both works in and remembers through. Everything persists to AIStor — your storage, your keys — and AIStor Memory teaches the agent, automatically, how to use it.
Anything an agent needs to keep is memory. AIStor Memory holds it in three forms on one customer-owned cortex — each a distinct purpose and lifecycle, not three separate systems:
- Workspace — active work. The mount the agent works in: it reads project
files and vendor memory and edits them in place with the tools it already
uses —
git, editors,sqlite, build tools all run unchanged — and the resulting state lands back in the cortex when files close. The real files survive sandbox teardown because they live in the durable cortex, not in session residue. - Long-term memory — what the agent learned. Durable knowledge that shapes
future work: the memory files agents already look for (
CLAUDE.md,AGENTS.md,MEMORY.md) warmed on mount; writable per-object annotations; read-only object metadata and tags as provenance; server-side search across the whole cortex; and structured memory as queryable tables (experimental). Theaimemskill teaches the agent to use all of it. - Vault — authority to act. Secrets held in the cortex (encrypted server-side) or provisioned from your own external store, leased into the agent as environment variables at launch — never written to the mount.
The rest of this page is the full feature surface, organized by form, followed by the mount and configuration reference.
The cortex — one mount for all three forms
AIStor Memory mounts only a Memory Bucket — a cortex. On mount it verifies the
target is a cortex over the Memory API and refuses a plain bucket
(not a Memory Bucket (cortex)); there is no opt-out. A cortex is a
first-class AIStor bucket built for agents — compressed, encrypted, KMS-backed,
and version-tracked — created with aimem cortex create or by converting an
existing bucket with aimem cortex convert. See the
CLI reference for the full cortex verb set (create · convert
· list · get · delete · credentials).
The mount gate is strict and refuses to proceed unless, in order: an
endpoint is configured (the endpoint_url: config key or the
--endpoint-url flag), real signing credentials
(AIMEM_ACCESS_KEY / AIMEM_SECRET_KEY, not anonymous or default-chain)
are present, the target is verified as a cortex over the Memory API (not a
plain bucket), and the credentials can reach the Memory API — which is an
Enterprise / paid-tier AIStor capability, so an unlicensed server or a
credential lacking memory:GetCortex fails the check (access denied by the Memory API … or the server is not on a paid tier).
Workspace — active work
The Workspace form is the durable mount the agent works in — the tools it
already uses (git, editors, sqlite, build tools) run unchanged against real
files. It ships exactly the contract an autonomous coding agent (Claude Code,
Cursor, Codex, …) or sandbox VM needs:
- Read project files and any vendor-specific memory (
CLAUDE.md,.claude/,AGENTS.md,MEMORY.md,.cursorrules,.cursor/). - Edit those files in place —
git, editors,sqlite, and the rest of the toolchain work as they would on any local disk. - Have the resulting state land back in the cortex atomically when files close, so it survives sandbox teardown and the next session re-mounts it byte-for-byte.
How it works — mandatory workspace mode
Every file opened for writing is staged on fast local storage (the
staging directory). The staging file is the agent's working copy.
On close() / fsync() the staged contents are uploaded to S3
atomically. Random writes, O_RDWR, and O_TRUNC all work because they
hit the staging file, not the network. mmap and copy_file_range are
not native syscalls here (they return ENOSYS), but the kernel falls
back to read+write over that same staging file, so memory-mapped
tools still function.
The staging directory is required and can be supplied three ways — at least one of them must be present:
- the
local:key in a--config <FILE>YAML file (the canonical, reviewable form — fewest flags), - the
--local <DIR>CLI flag, or - the
AIMEM_LOCALenvironment variable.
If more than one is set, CLI/env win over the config file. If none is present the
mount is refused before it starts (a local staging directory is required; set --local <DIR>, the AIMEM_LOCAL env var, or the `local:` key in --config). There is no auto-detection and no default.
The chosen path is logged at mount; size your staging volume for the agent's expected open-write working set (NVMe is recommended).
Config file (--config <FILE>)
A --config <FILE> YAML file is a serialization of the long-flag surface:
each key is a long flag with dashes rewritten to underscores
(endpoint_url, metadata_ttl, …). Two keys are special: version is
required and must be the quoted string "1.0" (a bare version: 1.0
parses as a float and is rejected), and unknown keys are a hard parse
error. The canonical workspace mount puts the staging dir, endpoint, and
any tunables in the file so the command line carries only the cortex, 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 flags, never the config file.
aimem my-cortex /workspace --config /etc/aimem/mount.yamlPositionals (the cortex/bucket and mount point) and --config itself are
never config-file keys — they always come from the command line.
Long-term memory — what the agent learned
The Long-term memory form is durable knowledge that shapes future work, kept
beside the data that formed it. It is realized today through the memory files
the agent warms on mount, writable per-object annotations (.aimem/annot/…)
for reasoned notes co-located with the bytes they describe, read-only object
metadata and tags (read as xattrs) for provenance the agent reasons over,
server-side search across the whole cortex, and structured
memory as queryable tables (experimental). The aimem skill teaches the agent
to use all of it.
Agent-memory warmup
On every mount, AIStor Memory warms the vendor-specific memory paths into the
--local store, so first-touch reads of CLAUDE.md / .claude/... /
etc. are served from local NVMe via FUSE passthrough instead of S3.
Selected by the agent: key in a --config <FILE> YAML file (or the
--agent flag): claude · codex · cursor · auto:
| claude | CLAUDE.md, .claude/ |
| codex | AGENTS.md, .agents/, MEMORY.md |
| cursor | .cursorrules, .cursor/, AGENTS.md |
| auto | All of the above |
The warmup task runs in the background; the mount becomes operational
immediately — warmup never blocks it — and first-touch reads are served
from local disk via FUSE passthrough as soon as the warmup task
publishes each object into --local. The warmed objects share the one
--local store with write staging; there is no separate in-memory
cache tier.
Custom warmup manifest
To warm additional objects beyond the agent-type defaults, set the
agent_manifest: key in your --config <FILE> YAML file to the path of a
JSONL manifest (the manifest is a config-file setting — there is no
--agent-manifest CLI flag). Each line is a JSON object with key and
size, plus optional etag and priority (0=Low, 1=Medium, 2=High,
3=Critical; defaults to Medium):
{"key": "CLAUDE.md", "size": 4096, "priority": 3}
{"key": "docs/runbook.md", "size": 18234}etag is optional: when omitted, AIStor Memory resolves the real etag (and true
size) with a HEAD at warm time, so the cached blocks match the key the read
path looks up. This costs one HEAD per etag-less entry — negligible for a
handful of files, but for a large manifest populate etag (e.g. from
--generate-workspace-manifest) to keep warmup purely streaming. Warming
never makes a file read-only — warmed paths stay ordinary read-write
workspace files; this only pre-populates the read cache.
The manifest is composed with, not a replacement for, the agent-type defaults — both sets get warmed, and overlapping keys are de-duplicated at the cache layer.
To produce a starter manifest for the current workspace, run
--generate-workspace-manifest <FILE>. AIStor Memory lists the agent-type memory
paths, writes them as JSONL to FILE, and exits without mounting. Edit the
file (trim keys, set priorities) and point the agent_manifest: config key
at it.
Search over data at rest
aimem search <cortex> -e <regex> runs regex search server-side over
the cortex's objects — the server decrypts and decompresses the objects
server-side, matches in place, and streams back matches, so the agent searches
its memory without downloading the workspace:
# Every -e pattern must match (AND semantics); RE2 syntax, line-oriented.
aimem search my-cortex -e 'TODO' -e 'auth' --ext md --ignore-case --contentFlags: -e/--pattern (repeatable, required; all patterns must match),
--prefix to restrict to a key prefix, --ext (repeatable) to limit by
file extension, --ignore-case, and --content to print the matching lines
in grep style (name:line:text) instead of just the object names — plus the
usual cortex connection flags. Patterns are RE2 (linear-time, no
backreferences/lookaround) and matched per line by default; pass
--multiline/-U to let a pattern span line boundaries. Search requires the
memory:Search action on a paid-tier server.
Structured memory (experimental)
Records and events can be kept as queryable Apache Iceberg tables in the same
cortex (aimem bio), so a run's activity becomes durable, queryable memory
alongside the files. Every cortex is warehouse-enabled automatically — whether
created fresh or converted from an existing bucket with aimem cortex convert —
so there is no separate warehouse to stand up. This is experimental and evolving.
SKILLS — the agent's mount manual
The Long-term memory form includes the aimem skill that teaches any LLM agent
to use everything above. AIStor Memory ships a first-class
Agent Skill named aimem that teaches the agent how
to work inside the mount: how to locate its workspace, the POSIX durability
semantics, where to keep long-lived memory, how to read object metadata, how to
leave and inherit per-object annotations, and how to search cortex memory
server-side. A skill is a folder with a
SKILL.md (real YAML frontmatter, name: aimem) plus a references/
directory that the agent loads on demand:
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 cortex memory (aimem search)The skill is generic — it bakes in no bucket, region, or mount point;
it teaches the agent to find its own mount with findmnt -S aimem. That
means the same skill works for any AIStor Memory mount, and it works in
egress-restricted sandboxes because it is bundled into the binary, not
fetched.
An agent discovers the skill through three tiers, widening in scope. The first two are automatic — you do nothing.
Tier 1 — read-time preamble (automatic, in the workspace)
On every mount, AIStor Memory prepends a short orientation preamble to the served
bytes of the agent's instruction files (CLAUDE.md, AGENTS.md,
.cursorrules) as they are read. Any agent that reads its bootstrap file
at startup immediately learns it is in an AIStor Memory workspace and is pointed at
the installed skill (Tier 2) — even if the repo shipped no CLAUDE.md of
its own.
The preamble is injected in memory only; it is never written back to
the bucket. It is disabled automatically when the mount root is a git
repository (so it can't dirty a tracked, committable file), and can be
turned off with AIMEM_PREAMBLE_OVERLAY=0.
Tier 2 — installed skill (automatic, in $HOME)
Also on every mount, AIStor Memory installs the aimem skill into the agent's home
skill directories so it survives the agent leaving 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 coding agents auto-load skills from those paths, so installing there
is the deterministic discovery path. The write is offline (no bucket,
no S3, no network), create-only (an existing SKILL.md is never
overwritten), and crash-safe (staged in a temp dir, published with one
atomic rename).
The install is skipped when $HOME resolves under the mount point — writing
there would push the skill into the bucket through FUSE instead of to local
disk. Turn the whole step off with AIMEM_INSTALL_SKILL=0.
Tier 3 — public skill (host-side, for out-of-sandbox agents)
Some agents run their reasoning outside the sandbox — e.g. the OpenAI Agents SDK or other managed-agent harnesses, where the model lives in the control plane and only issues commands into the compute box. For those, an in-sandbox install (Tiers 1–2) is invisible: the reasoning model never sees files written inside the box.
Those harnesses install the aimem skill host-side from MinIO's public
Agent Skills repository
(minio/skills), alongside their own
skills, before the run starts:
npx skills add minio/skills/aimemminio/skills is MinIO's public home for
all its agent skills. The aimem skill there is the same generic SKILL.md +
references/ that ships in the binary, so a host-side install and an
in-sandbox install are identical.
Vault — secrets an agent needs to act
The Vault form is the authority an approved agent receives: the secrets it needs to act, held in your own store and leased into the agent at launch. The cortex itself is a first-class, writable secret store — the Vault pillar — and an external store (HashiCorp Vault/OpenBao KV, a cloud secret manager) is also supported.
Coding agents need credentials. The OPENAI_API_KEY so the agent can
self-introspect. The GITHUB_TOKEN for pushing to a PR branch. The
NPM_TOKEN for npm publish. The PG connection string for the
deploy step. Every one of those, written into a .env file in the
workspace bucket as plaintext, is a prompt-injection waiting to happen: the
agent reads the file, the agent chats with an untrusted source, the agent
gets convinced to exfiltrate the file.
AIStor Memory's model is the Docker/Kubernetes one: secrets are provisioned and injected, never written into the workspace bucket. A launcher outside the sandbox fetches only the secrets that agent is granted and injects them into the agent process as environment variables. The store credential is held by the launcher, never handed to the agent.
The default secret store is the cortex itself — AIStor Memory's Memory-API
secrets endpoint, where values are persisted encrypted server-side (see
aimem secret put/get/list/delete below), so the Vault lives on the same
AIStor as the rest of the agent's memory. As an optional bridge, if your
secrets already live in a generic external store (HashiCorp Vault/OpenBao KV, a
cloud secret manager), the launcher can lease them from there instead of copying
them into the cortex — useful when that store is your org's mandated
source-of-truth. Either way, one distinction to keep clear: aimem the client
holds no secret bytes on disk or in the workspace bucket (it is a
pass-through), which is not the same as "secrets are never stored anywhere" —
the cortex is a first-class, writable secret store.
provision takes exactly one source. Either resolve from a cortex
over the Memory API:
# Launch the agent with the granted secrets injected as env vars.
# All store/signing credentials stay with the launcher; the agent only
# sees the resolved values.
aimem secret provision \
--cortex my-cortex \
--endpoint-url https://aistor.example.com \
--access-key "$AIMEM_ACCESS_KEY" \
--secret-key "$AIMEM_SECRET_KEY" \
--grant OPENAI_API_KEY=openai \
--grant GITHUB_TOKEN=gh-pat \
-- claude…or from a generic HTTP secret store:
aimem secret provision \
--store-endpoint https://vault.example.com \
--store-token "$VAULT_TOKEN" \
--grant OPENAI_API_KEY=openai \
-- claude
# With no trailing command, emit KEY=VALUE lines for the caller to inject:
eval "$(aimem secret provision --cortex my-cortex \
--endpoint-url https://aistor.example.com \
--grant OPENAI_API_KEY=openai)"provision launches the agent as a child process and exits with its
status. Before launching, it scrubs the full store/connection
credential set from the child's environment —
AIMEM_SECRET_STORE_TOKEN, AIMEM_SECRET_STORE_ENDPOINT,
AIMEM_ACCESS_KEY, AIMEM_SECRET_KEY, AIMEM_SESSION_TOKEN,
AIMEM_ENDPOINT_URL, and AIMEM_REGION — so neither an HTTP-store token
nor the cortex signing credentials ever reach the agent.
Nothing readable is written to the workspace bucket, and a prompt-injected agent cannot enumerate or re-fetch the store — it holds only the values it was leased, never the store or signing credentials.
Managing secrets in the cortex
When the store is the cortex itself, AIStor Memory is not just a fetch client — it
is a first-class, writable secret store. Secret bytes are held encrypted
server-side by the Memory API; aimem never persists them to disk or the
workspace bucket. Four subcommands manage them:
# Store a secret. Prefer piping the value on stdin over --value
# (a --value is visible in the process list and shell history):
printf '%s' "$OPENAI_API_KEY" | aimem secret put my-cortex openai
aimem secret put my-cortex gh-pat --value "$GITHUB_TOKEN"
# Fetch a secret's plaintext value (written to stdout):
aimem secret get my-cortex openai
# Enumerate the secret names in a cortex:
aimem secret list my-cortex
# Delete a secret:
aimem secret delete my-cortex openaiEach subcommand takes the same connection flags / AIMEM_* env as any
other cortex command (endpoint, region, access key, secret key, optional
session token). secret provision --cortex <name> then reads back exactly
these secrets to inject into an agent.
What makes it different
Secrets are held in your own store — the cortex, a writable first-class
store you populate with aimem secret put, or an external store (HashiCorp
Vault/OpenBao, a cloud manager) — never in a vendor's database. The launcher
injects only the leased values as environment variables at agent start; the
agent never holds the store or signing credentials, cannot enumerate or
re-fetch the store, and nothing readable is written to the workspace bucket.
A .env file in the bucket, by contrast, is plaintext — one prompt injection
away from full exfiltration.
Configuration
aimem secret provision requires exactly one secret source — either
--cortex (the AIStor Memory-API endpoint) or --store-endpoint (a
generic HTTP store) — and they are mutually exclusive. A provision
command with neither errors at runtime. The one flag that is always
required is --grant; everything else depends on the chosen source.
--grant VAR=name (repeatable) binds env var VAR to secret name:
| Env var | Flag | Meaning |
|---|---|---|
| — | --grant VAR=name | Bind env var VAR to store secret name |
Source A — cortex (--cortex <name>). Resolves over the Memory API
using the standard cortex connection inputs:
| 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 — generic HTTP store (--store-endpoint <url>). Bearer-auth
against your own store:
| 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 trailing -- <command> the command is launched with the secrets
injected and the full store/signing credential set scrubbed; without one,
KEY=VALUE lines are printed for the caller to consume.
What aimem does not ship
AIStor Memory is memory backed directly by the object store you already run — nothing
extra to operate. The read path is served from the single --local store via
FUSE passthrough: the agent-memory files (CLAUDE.md / .claude/ / AGENTS.md /
.cursor/ / MEMORY.md / .cursorrules) are warmed into it on mount, and everything
else is fetched from S3 on demand through the prefetcher and cached in --local
as it is read. (Writes are separate — staged locally and uploaded atomically on
close().) There is no separate in-memory cache, no multi-disk block caches, no shared
remote cache clusters, and no S3 Express bucket caches — those would be at odds
with the agent-memory contract (one writer, fast iteration on a small hot set,
atomic upload on close). If you need a tunable read-cache tier for a non-agent
workload, reach out — we can talk about the right substrate.