AIStor Memory

CLI reference

Every aimem command — mount, Memory Bucket, secret, search, and the agent biography (bio).

The aimem binary is how an agent reaches its memory. Every command works against one customer-owned MinIO AIStor Memory Bucket. Each subcommand touches a different form of that memory: the workspace the agent works in, the long-term memory it remembers through, and the Vault of secrets it needs to act. Five surfaces, one Memory Bucket:

  • mount — aimem <bucket> <mountpoint> mounts a Memory Bucket as the agent's workspace: the filesystem it both works in and remembers through. This is the default form, with no subcommand. A --config YAML file is the canonical way to configure the mount — see Mounting a Memory Bucket below. Mount a sub-prefix with the bucket/prefix/ positional. Mounting only works against a Memory Bucket: it needs an explicit endpoint and real signing credentials, and the target bucket must already be a Memory Bucket on a paid-tier AIStor deployment.
  • aimem bucket — create and manage the Memory Buckets that hold every form of memory.
  • aimem secret — the Vault: deployment-side secret provisioning for launchers.
  • aimem search — long-term-memory search: regex over a Memory Bucket's data at rest.
  • aimem bio — the biography: an OpenTelemetry collector that records what an agent did into queryable tables in the same Memory Bucket.

The management verbs share one set of connection flags. bucket, search, and bucket-backed secret operations use the AIStor Memory API. bio also uses the Iceberg REST catalog. secret provision can instead target a generic HTTP secret store (--store-endpoint).

--config applies only to the mount command. The management verbs take their settings as flags, or as the connection env vars below, never from a config file.

Mounting a Memory Bucket

aimem <bucket> <mountpoint> mounts a Memory Bucket as a workspace. The canonical way to configure a mount is a --config YAML file: point --config at it, supply credentials in the environment, and pass the Memory Bucket and mountpoint as positionals.

export AIMEM_ACCESS_KEY=... AIMEM_SECRET_KEY=...
aimem my-memory-bucket /workspace --config /etc/aimem/mount.yaml

The --config YAML must declare version: "1.0". It carries every mount setting — the advanced tunables that have no CLI flag, and the mandatory staging directory (via the local: key here, or the --local flag / AIMEM_LOCAL env var — at least one is required). See Configuration for the full key reference.

Credentials are environment-only: AIMEM_ACCESS_KEY, AIMEM_SECRET_KEY, and the optional AIMEM_SESSION_TOKEN. They are never mount flags and never --config YAML keys, so the signing secret stays out of config files and process arguments.

Mount flags

The everyday mount settings are also available as CLI flags. Each flag is equivalent to the --config YAML key of the same name (dashes become underscores), and --config is the preferred way to set them — the flags exist for quick, one-off mounts. An explicit flag always overrides the YAML value.

FlagConfig keyDescription
--local <DIR>localMandatory local staging + read-cache directory. Also AIMEM_LOCAL; one of the three is required.
--endpoint-url <URL>endpoint_urlAIStor endpoint; repeatable, or a {1...N} brace range, for failover.
--region <REGION>regionSigV4 signing region (default us-east-1).
--request-timeout <SECONDS>request_timeoutPer-request deadline; retries the next endpoint. Only valid with two or more endpoints.
--health-path <PATH>health_pathHTTP path polled per endpoint for liveness; unhealthy endpoints leave the round-robin pool.
--tls-ca-file <FILE>tls_ca_fileExtra PEM CA bundle for endpoint TLS. Also AIMEM_TLS_CA_FILE.
--tls-server-name <NAME>tls_server_nameName to verify the endpoint's certificate against, when --endpoint-url is an IP. Also AIMEM_TLS_SERVER_NAME.
--read-onlyread_onlyMount the filesystem read-only.
--agent <TYPE>agentWarm vendor memory files on mount (claude, codex, cursor, auto).
--metadata-ttl <TTL>metadata_ttlKernel metadata cache TTL: indefinite, minimal, or seconds.
-f, --foregroundforegroundRun in the foreground instead of daemonizing.
-l, --log-directory <DIR>log_directoryWrite logs to files under this directory instead of syslog.
-d, --debugdebugEnable debug logging.
--no-logno_logDisable logging entirely.

Of these, only --local (AIMEM_LOCAL), --tls-ca-file (AIMEM_TLS_CA_FILE), --tls-server-name (AIMEM_TLS_SERVER_NAME), and --region (AIMEM_REGION) also read an environment variable. The rest are flag-or---config only, and credentials remain environment-only (above).

Every other mount setting — the FUSE, transfer, memory, observability, and health-check tunables — is --config-only and listed in the Configuration key reference.

Connection flags

Every management verb reaches the Memory API with the same endpoint and credentials. Pass them as flags or — preferably — as environment variables.

FlagEnvironment variableDescription
--endpoint-url <URL>AIMEM_ENDPOINT_URLAIStor / Memory API endpoint (e.g. https://aistor.example.com:9000)
--access-key <KEY>AIMEM_ACCESS_KEYAccess key
--secret-key <KEY>AIMEM_SECRET_KEYSecret key
--region <REGION>AIMEM_REGIONSigV4 region (default us-east-1)
--session-token <TOK>AIMEM_SESSION_TOKENOptional STS session token
export AIMEM_ENDPOINT_URL=https://aistor.example.com:9000
export AIMEM_ACCESS_KEY=your-access-key
export AIMEM_SECRET_KEY=your-secret-key

The Memory API is a paid-tier AIStor feature. Creating and mounting a Memory Bucket requires a licensed AIStor deployment.

aimem bucket — manage Memory Buckets

A Memory Bucket is a first-class AIStor bucket built for agents: compressed, encrypted, KMS-backed, version-tracked, and stamped with memory metadata. AIStor Memory mounts only a Memory Bucket, so this is where every workspace begins.

bucket create <name>

Create a Memory Bucket.

FlagDescription
--kms-key-id <ID>Pin a specific KMS key for encryption (defaults to the server key).
--upgrade-existingConvert an existing regular bucket instead of failing if it exists.
aimem bucket create my-project

bucket convert <name>

Convert an existing regular bucket into a Memory Bucket in place. Idempotent — converting an existing Memory Bucket is a no-op. Objects written before the conversion are not retro-actively compressed, encrypted, or metadata-stamped; only writes after it honor the Memory Bucket contract. Warehouse buckets cannot be converted.

Any bucket you convert becomes a full Memory Bucket: besides the workspace and the Memory API, the resulting Memory Bucket also serves as an Iceberg warehouse, so structured memory (aimem bio tables, below) works on the same bucket immediately — no separate warehouse to stand up.

FlagDescription
--note <NOTE>Record a free-form migration note (stored as upgrade-note).
--kms-key-id <ID>Pin a KMS key, applied only when the bucket has no encryption of its own.
aimem bucket convert legacy-bucket --note "migrated 2026-07"

bucket list

List Memory Buckets.

FlagDescription
--search <SUBSTR>Filter Memory Buckets whose name contains this substring.
--jsonEmit JSON instead of a table.

bucket get <name>

Show a single Memory Bucket — bucket, uuid, created timestamp, encryption, compression, KMS key (when pinned), memory format, and the upgraded flag. Add --json for the full detail object (which also includes any operator metadata).

aimem bucket get my-project --json

bucket delete <name>

Delete a Memory Bucket and all its data.

FlagDescription
--forceDelete even when the Memory Bucket is non-empty.

bucket credentials <name>

Mint STS credentials scoped to a single Memory Bucket (AssumeRole with an inline session policy). The temporary credentials can mount the bucket and use the Memory API on it — and nothing else. This is how a launcher hands a sandbox least-privilege access to exactly one workspace.

FlagDescription
--duration <SECS>Requested credential lifetime.
--jsonEmit JSON instead of shell export lines.
# inject scoped, time-boxed credentials into a sandbox
eval "$(aimem bucket credentials my-project --duration 3600)"

aimem secret — deployment-side secret provisioning

aimem secret is a launcher / deployment helper, not a skill and not a command the agent runs. The process that launches the agent — a sandbox controller, a CI job, an orchestrator — runs it outside the sandbox. Secrets never touch the mount, and the agent inside the workspace has no reason to call aimem secret at all.

secret provision --grant VAR=name [-- cmd …]

Fetch the granted secrets and inject them as environment variables. With a trailing -- <command>, the agent inherits the ambient environment with the store and connection credentials scrubbed and the leased secrets injected on top. Scrubbing removes the AIMEM_SECRET_STORE_* variables and AIMEM_ACCESS_KEY / AIMEM_SECRET_KEY / AIMEM_SESSION_TOKEN / AIMEM_ENDPOINT_URL / AIMEM_REGION. The agent therefore keeps PATH/HOME and receives its API keys as ordinary environment variables, but can neither read the store credential nor re-fetch.

provision launches the command as a child process, waits for it, and exits with the child's status; it does not exec. With no command, it prints KEY=VALUE lines for the caller to consume.

FlagDescription
--grant VAR=nameBind an environment variable to a secret name. Repeatable.
--bucket <BUCKET>Resolve secrets from a Memory Bucket over the Memory API.
--store-endpoint <URL>Resolve from a generic HTTP store (HashiCorp Vault/OpenBao, a cloud manager). Mutually exclusive with --bucket. Also AIMEM_SECRET_STORE_ENDPOINT.
--store-token <TOK>Bearer token for the HTTP store; held launcher-side, never injected. Also AIMEM_SECRET_STORE_TOKEN.

The --bucket path additionally requires the Memory-API connection credentials, given either as flags or environment variables:

FlagDescription
--endpoint-url <URL>Memory-API endpoint URL. Required with --bucket. Also AIMEM_ENDPOINT_URL.
--access-key <KEY>Access key. Required with --bucket. Also AIMEM_ACCESS_KEY.
--secret-key <KEY>Secret key. Required with --bucket. Also AIMEM_SECRET_KEY.
--region <REGION>Region for SigV4 signing. Optional (defaults to us-east-1). Also AIMEM_REGION.
--session-token <TOK>Session token for temporary credentials. Optional. Also AIMEM_SESSION_TOKEN.

provision errors if the endpoint, access key, or secret key is unset when --bucket is used.

# launch the agent with OPENAI_API_KEY leased in, store creds scrubbed
aimem secret provision --bucket my-project \
    --grant OPENAI_API_KEY=openai -- claude

secret put / get / list / delete

Manage secrets stored in a Memory Bucket over the Memory API. These, too, are launcher/operator-side administration — not something the sandboxed agent invokes.

CommandDescription
secret put <bucket> <name>Store a secret. Prefer piping the value on stdin over --value, which is visible in the process list and shell history.
secret get <bucket> <name>Print a secret's plaintext value.
secret list <bucket>List secret names in a Memory Bucket.
secret delete <bucket> <name>Delete a secret.
printf '%s' "$OPENAI_KEY" | aimem secret put my-project openai
aimem secret list my-project

aimem search — regex over data at rest

aimem search runs a server-side regex search over a Memory Bucket's objects, which stay compressed and encrypted at rest. It returns the names of matching objects, or with --content, the matching lines in grep style (name:line:text).

aimem search my-project --pattern 'TODO|FIXME' --ext md --ext rs --ignore-case
FlagDescription
-e, --pattern <REGEX>RE2 pattern to match; repeatable, 1–16 patterns, all must match (AND).
--prefix <PREFIX>Restrict the search to keys under a prefix.
--ext <EXT>Restrict to these extensions, with or without the dot (md or .md); repeatable.
--ignore-caseCase-insensitive matching.
-U, --multilineLet a pattern span line boundaries (ripgrep -U); off by default.
--contentPrint matching lines (name:line:text), not just object names.

aimem bio — the agent's biography

An agent's memory also has a structured form: what it did, kept as queryable tables in the same Memory Bucket that holds its files. aimem bio runs an OpenTelemetry collector beside the agent, writes what the agent's harness emits into that Memory Bucket, and reads it back — so a run's activity becomes durable memory alongside the files it produced.

The collector speaks standard OTLP/HTTP, so nothing has to be written against a proprietary API. Any harness or SDK that can export OpenTelemetry — a coding agent's telemetry plugin, an application's own instrumentation — points at it and its traces, logs and metrics land in the Memory Bucket.

bio ships as a sibling aimem-bio binary that aimem bio dispatches to (resolved next to aimem first, then on PATH). It is included in the deb and rpm packages and the standalone archive, so aimem bio … works from a normal install; aimem bio --help lists its own options.

bio serve <bucket> --agent <ID> --endpoint-file <FILE> [--session-key <ATTRIBUTE>]

Run the collector. It binds a loopback port, writes the base URL it chose to --endpoint-file, and accepts OTLP/HTTP on the standard /v1/traces, /v1/logs and /v1/metrics paths — JSON or protobuf, gzipped or not.

aimem bio serve my-project --agent checkout-bot \
  --session-key session.id \
  --endpoint-file /run/agent/otlp-endpoint

Run one per agent. Every payload the collector accepts is stored under the agent named by --agent. A payload's own aimem.agent.id attribute is kept like any other field but does not route the write. There is no provisioning step: before it publishes its endpoint, the collector creates the agent's namespace and tables if they do not exist yet.

--session-key names the attribute that carries the agent's session id, as the agent record's capture_descriptors declare it. Pass it when the collector runs under the agent's own credential, which is not granted the agent record. Without it the collector reads the key from the record. See Scoping a collector to one agent for the credential.

Point the agent's exporter at the published endpoint:

export OTEL_EXPORTER_OTLP_ENDPOINT="$(cat /run/agent/otlp-endpoint)"

If the collector cannot write what it has taken in — a wrong Memory Bucket name, a credential without the table permissions it needs — it says so on every attempt and then stops with a non-zero exit rather than going on accepting data it cannot store. Run it under a supervisor that restarts it and surfaces that exit.

Each agent's telemetry is written to six tables — otel_spans, otel_span_events, otel_span_links, otel_logs, otel_metric_points and otel_metric_exemplars — plus the otel_quarantine table. bio serve creates any that are missing before it publishes its endpoint, and bio ingest creates them on its first write to an agent.

In otel_metric_points, a histogram point also fills count, sum, min, max, bucket_counts and explicit_bounds, so SQL can aggregate token usage and durations without parsing JSON. Other point types leave these columns empty. value_json still holds every point in full.

Spans, span events and logs also carry the structured GenAI attributes as JSON: gen_ai_input_messages, gen_ai_output_messages, gen_ai_system_instructions and gen_ai_tool_definitions. A key-value list becomes a JSON object, with its keys sorted, and an array becomes an array. A string attribute that holds a JSON object or array is stored as that JSON. Any other value is stored as its JSON scalar, so a plain string keeps its quotes ("gpt-5"). JSON has no NaN or infinity, so a non-finite double reads as null, and as a column value on its own it leaves the column empty. The attribute map is unchanged.

A table created before any of these columns existed gains them in place the next time the collector starts. Its earlier rows read them as null. If the credential may not change the table's schema, the collector says so and keeps writing the table as it is.

bio query <bucket> --agent <ID> [--table <TABLE>] [--where <EXPR>] [--limit N]

Read an agent's telemetry back, as JSON lines. --table defaults to otel_spans and --limit to 100. --where takes one filter, session_id = <value>, which narrows the read to a single agent session. The session is whatever identifier the harness itself emits — nothing to configure — so a harness that names it something the reader does not recognise leaves the column empty and the filter matches nothing.

aimem bio query my-project --agent checkout-bot --limit 20
aimem bio query my-project --agent checkout-bot --table otel_logs \
  --where "session_id = 2f9c1b04"

bio ls <bucket>[.<agent>]

List a Memory Bucket's namespaces — one per agent that has telemetry, plus any you made yourself with bio create — or the tables in one of them.

aimem bio ls my-project              # namespaces
aimem bio ls my-project.checkout-bot # that agent's tables

bio export <bucket> --agent <ID> --output <FILE> [--table <TABLE>] [--where <EXPR>]

Write every row of an agent's table to a Parquet file, for engines that cannot read the tables directly, such as DuckDB and Spark. Unlike bio query it has no row limit. Each timestamp is written in microseconds, the unit those engines map, and the exact value is kept beside it as an integer <column>_unix_nano. --table defaults to otel_spans, and --where takes the same session_id = <value> filter as bio query.

aimem bio export my-project --agent checkout-bot --output spans.parquet

bio ingest <bucket> <path> [--session-key <ATTRIBUTE>]

Load OTLP/JSON from a file or directory — for backfilling telemetry captured before the collector was running, or for replaying a capture. Routed the same way as live telemetry, and idempotent per payload: re-ingesting a file adds no duplicate rows while its record is still held, which covers replaying a capture or re-running a backfill. The record is bounded, so a replay is not deduplicated indefinitely against a table that has been written many times since.

--session-key names the attribute that carries the session id, as the agents' records declare it. It defaults to session.id.

aimem bio ingest my-project ./otel-traces.json

bio create <bucket>.<namespace>.<table> --schema <FILE>

Create a table of your own in the Memory Bucket, alongside the telemetry ones. --schema accepts a raw Iceberg struct schema or a friendly ordered field list ([{"name":"id","type":"string"}, …]); --schema - reads from stdin. Idempotent — an existing table with a matching schema is a no-op, and a create against an incompatible existing schema (a missing field, or a type/requiredness mismatch) is rejected.

aimem bio create my-project.app.events --schema schema.json

What's next