initializdocs
DeveloperForge runtimeCore concepts

Memory System

Session persistence, context management, and long-term memory.

Forge provides two layers of memory management: session persistence for multi-turn conversations and long-term memory for cross-session knowledge.

Session Persistence

Sessions are automatically persisted to disk across requests, enabling multi-turn conversations:

memory:
  persistence: true          # default: true
  sessions_dir: ".forge/sessions"
  • Sessions are saved as JSON files with atomic writes (temp file + fsync + rename)
  • Orphaned tool calls (assistant tool_calls without matching tool results) are stripped on both save and recovery, preventing API rejection errors
  • Automatic cleanup of sessions older than 7 days at startup
  • Session recovery on subsequent requests (disk snapshot supersedes task history)
  • Session max age (default 30 minutes): stale sessions are discarded on recovery to prevent poisoned error context from blocking tool retries. When an LLM accumulates repeated tool failures in a session, it may stop retrying altogether. The max age ensures these poisoned sessions expire, giving the agent a fresh start.

Configure via forge.yaml or environment variable:

memory:
  session_max_age: "30m"   # default; use "1h", "15m", etc.
export FORGE_SESSION_MAX_AGE=1h

Session Store Backends

Session persistence has two backends, selected by memory.session_store:

BackendWhenBehavior
file (default)Single pod / devLocal JSON under sessions_dir (.forge/sessions/*.json). Durable only on that pod's filesystem.
remoteStateless / multi-podSnapshots are pushed to a platform session service over HTTP, so any replica can resume any task with no shared volume — no PVC.

The remote backend keeps agent pods stateless: a task started on one pod resumes on another. It:

  • Pulls before each turn with a conditional GET (If-None-Match) — the service answers 304 (the pod's cached snapshot is current) or 200 (fresh state), so unchanged sessions aren't re-downloaded.
  • Commits with compare-and-swap (If-Match) — a concurrent writer's intervening commit is detected as a 412. On conflict the stale writer yields (the newer state wins) rather than clobbering it; the model is never re-run.
  • Pulls lazily — a cold pod fetches a session only when its task is first touched, not all sessions at once.
memory:
  session_store: remote                       # "file" (default) | "remote"
  session_store_url: "https://sessions.example/api/v1/agent-sessions"

The pod authenticates to the service with its platform token, reusing the same env the admission client reads — FORGE_PLATFORM_TOKEN plus the FORGE_ORG_ID / FORGE_WORKSPACE_ID tenancy stamps. A remote selection missing its URL or token warns and falls back to the file backend, so session memory is never silently dropped.

The remote store attaches independent of memory.persistence (#372/#373). Selecting remote (via session_store: remote or FORGE_SESSION_STORE=remote) engages the backend even when memory.persistence is off / absent — the two are decoupled. This is the load-bearing behavior for the common platform/BYO-CI case, where the platform injects FORGE_SESSION_STORE=remote at deploy time while the developer's committed forge.yaml omits any memory: block: previously the session store was gated behind persistence, so every session was silently dropped despite a configured remote backend. You do not need persistence: true for the remote store to work.

export FORGE_SESSION_STORE=remote
export FORGE_SESSION_STORE_URL=https://sessions.example/api/v1/agent-sessions

Context Window Management

Forge automatically manages context window usage based on model capabilities:

ModelContext WindowCharacter Budget
gpt-4o / gpt-5128K tokens~435K chars
claude-sonnet / claude-opus200K tokens~680K chars
gemini-2.51M tokens~3.4M chars
llama38K tokens~27K chars
llama3.1128K tokens~435K chars

When context grows too large, the Compactor automatically:

  1. Takes the oldest 50% of messages
  2. Flushes tool results and decisions to long-term memory (if enabled)
  3. Summarizes via LLM (with extractive fallback)
  4. Replaces old messages with the summary

Research tool results receive special handling during compaction: they are preserved with a higher extraction limit (5000 vs 2000 characters) and tagged distinctly in long-term memory logs (e.g., [research][tool:tavily_research]) so research insights persist across sessions.

memory:
  char_budget: 200000       # override auto-detection
  trigger_ratio: 0.6        # compact at 60% of budget (default)

Long-Term Memory

Enable cross-session knowledge persistence with hybrid vector + keyword search:

memory:
  long_term: true
  memory_dir: ".forge/memory"
  vector_weight: 0.7
  keyword_weight: 0.3
  decay_half_life_days: 7

Or via environment variable:

export FORGE_MEMORY_LONG_TERM=true

When enabled, Forge:

  • Creates a .forge/memory/ directory with a MEMORY.md template for curated facts
  • Indexes all .md files into a hybrid search index (vector similarity + keyword overlap + temporal decay)
  • Registers memory_search and memory_get tools for the agent to use
  • Automatically flushes compacted conversation context to daily log files (YYYY-MM-DD.md)

Embedding Providers

Embedding providers power the vector search component of long-term memory:

ProviderDefault ModelNotes
openaitext-embedding-3-smallStandard OpenAI embeddings API
geminitext-embedding-3-smallOpenAI-compatible endpoint
ollamanomic-embed-textLocal embeddings

Falls back to keyword-only search if no embedding provider is available (e.g., when using Anthropic as the primary provider without a fallback).

Configuration

Full memory configuration in forge.yaml:

memory:
  persistence: true
  sessions_dir: ".forge/sessions"
  session_max_age: "30m"      # discard sessions idle longer than this
  session_store: "file"       # "file" (default) | "remote"
  session_store_url: ""       # required when session_store: remote
  char_budget: 200000
  trigger_ratio: 0.6
  long_term: false
  memory_dir: ".forge/memory"
  embedding_provider: ""      # Auto-detect from LLM provider
  embedding_model: ""         # Provider default
  vector_weight: 0.7
  keyword_weight: 0.3
  decay_half_life_days: 7

Environment variables:

VariableDescription
FORGE_MEMORY_PERSISTENCESet false to disable session persistence
FORGE_SESSION_MAX_AGESession idle timeout, e.g. 30m, 1h (default: 30m)
FORGE_SESSION_STORESession backend: file (default) or remote
FORGE_SESSION_STORE_URLPlatform session-service URL (required for remote)
FORGE_MEMORY_LONG_TERMSet true to enable long-term memory
FORGE_EMBEDDING_PROVIDEROverride embedding provider

On this page