AIStor Memory
Concepts

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:

  1. Workspace: the files the agent is working on.
  2. Long-term memory: what the agent learned, kept beside the data it came from.
  3. 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:

  1. Read project files and agent memory files (CLAUDE.md, .claude/, AGENTS.md, MEMORY.md, .cursorrules, .cursor/).
  2. Edit those files in place with git, editors, sqlite, and the rest of the toolchain, as on any local disk.
  3. 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_LOCAL environment 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:

  • version is required and must be the quoted string "1.0". An unquoted version: 1.0 is 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.yaml

The 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 as user.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:

claudeCLAUDE.md, .claude/
codexAGENTS.md, .agents/, MEMORY.md
cursor.cursorrules, .cursor/, AGENTS.md
autoAll 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 --content

Flags:

  • -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 as name:line:text instead 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/aimem

The 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, and delete. The aimem client 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 \
  -- claude

To 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 openai

Each 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 varFlagMeaning
—--grant VAR=nameBind 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 varFlagMeaning
AIMEM_ENDPOINT_URL--endpoint-urlMemory-API / S3 endpoint (required)
AIMEM_ACCESS_KEY--access-keyAccess key (required)
AIMEM_SECRET_KEY--secret-keySecret key (required)
AIMEM_REGION--regionSigV4 region (optional, default us-east-1)
AIMEM_SESSION_TOKEN--session-tokenSession token (optional)

Source B: HTTP store (--store-endpoint <url>). Authenticates to your store with a bearer token:

Env varFlagMeaning
AIMEM_SECRET_STORE_ENDPOINT--store-endpointSecret-store base URL
AIMEM_SECRET_STORE_TOKEN--store-tokenBearer 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.