Let agents carry knowledge across turns and sessions with native memory, or take over generation and consumption yourself.
Memory lets an agent keep the knowledge it gains in one session and reuse it later. A project's build command, test layout, and code conventions no longer have to be rediscovered on every run.
Qoder Agent SDK memory has two halves — generation and consumption — which can be configured independently:
In native mode the only configurable parts are the two scope switches and the result callbacks. Everything else — the storage location, the generation prompt, the loading budget — stays owned by the runtime and improves with each release.
Native memory has two scopes. Both are enabled by default.
Disable either one per query:
Native mode requires at least one enabled scope. Disabling both throws:
An empty object is the explicit "off" switch, equivalent to omitting
Each root is a directory the memory agent may use:
Generation normally starts on every completed turn.
The callback receives the completed turn's
Passing explicit
Files are injected in array order, and
Memory runs in the background, so surface its outcome rather than assuming success. Two paths are available.
Register callbacks, which work in both
Or read the same payloads off the message stream, as
Generation reports one of five outcomes:
Consumption reports
Two methods on the query handle the timing problems that background generation creates.
Memory options are negotiated with the runtime, so read back what actually took effect instead of trusting the request:
When
| Half | What it does | When it runs |
|---|---|---|
| Generation | Writes what the agent learned into memory files | After a turn completes, in a background memory agent |
| Consumption | Loads memory files into the agent's context | At session initialization, and on explicit refresh |
Enable native memory
mode: 'native' delegates all behavior to Qoder CLI defaults. This is the recommended starting point: the runtime decides what is worth remembering, where to store it, and when to load it.
Choose memory scopes
Native memory has two scopes. Both are enabled by default.
| Scope | Root id | Holds |
|---|---|---|
| User | user | Knowledge that follows the operator across every project |
| Project | project | Knowledge specific to the current working directory |
Disable memory
An empty object is the explicit "off" switch, equivalent to omitting memory entirely. No memory configuration is sent to the runtime.
Override generation and consumption
mode: 'custom' applies your overrides and inherits everything you omit from the runtime defaults. Use it when the application owns where memory lives or what counts as worth remembering.
Control what gets written
| Field | Type | Default | Description |
|---|---|---|---|
id | string | — | Stable identifier used in prompts, initialization, and results |
path | string | — | Directory on the machine running Qoder CLI |
access | 'read' | 'read-write' | 'read-write' | Whether the memory agent may write to this root |
indexFile | string | — | Relative index path inside the root. Omit when every file is content |
Decide per turn whether to write
Generation normally starts on every completed turn. shouldGenerate lets the application veto an attempt — useful to skip trivial turns, respect a per-tenant budget, or avoid writing during a read-only review.
prompt and response, plus sessionId, cwd, and a one-based turnIndex. Returning run: false emits a skipped result instead of starting the background agent.
| Field | Type | Default | Description |
|---|---|---|---|
enabled | boolean | true | Whether turn-complete generation runs at all |
shouldGenerate | callback | — | Product-side gate. Omit to use runtime guards only |
timeoutMs | number | 10000 | Maximum time allowed for the gate |
onGateError | 'skip' | 'report_failed' | 'skip' | How a callback error or timeout is reported |
Control what gets loaded
Passing explicit files replaces native auto-memory for this query. Static instructions still load.
id becomes the injected section name.
| Field | Type | Default | Description |
|---|---|---|---|
enabled | boolean | true | Whether memory is loaded at all |
files | MemoryConsumptionFile[] | — | Explicit files. Replaces native auto-memory |
maxTokens | number | — | Shared budget across all explicit files |
overflow | 'truncate' | 'fail_query' | 'truncate' | Behavior when content exceeds maxTokens |
failureMode | 'best_effort' | 'fail_query' | 'best_effort' | Read-failure behavior. Only required files can fail the query |
Observe what memory did
Memory runs in the background, so surface its outcome rather than assuming success. Two paths are available.
Register callbacks, which work in both native and custom mode:
system messages with subtype memory_generation and memory_consumption:
| Status | Meaning |
|---|---|
saved | Every written file succeeded |
partial | At least one file succeeded and one failed — inspect failedFiles |
no_change | The attempt ran and found nothing new to record |
skipped | The attempt did not run, for example because a gate returned run: false |
failed | The attempt ran and produced no successful write |
success, partial, or failed, with a per-file status of loaded, missing, failed, or truncated. A missing file is not an error on its own — memory files may legitimately not exist yet on a first run.
Control memory at runtime
Two methods on the query handle the timing problems that background generation creates.
flushMemory() matters most in CI and in tests: without it, a process that exits right after the final result message can terminate a generation attempt mid-write.
Verify the effective configuration
Memory options are negotiated with the runtime, so read back what actually took effect instead of trusting the request:
memory is omitted or set to {}, init.memory is undefined.
Next steps
- Session Control — resume and fork sessions that carry memory
- External Session Storage — persist transcripts so another host can resume
- Track cost and usage — generation attempts report their own
usageandcredits