How Session Summaries Are Generated in ai-memory: A Deep Dive into the Summary.json Lifecycle

Session summaries in ai-memory are generated by the client runtime (Grok, Kiro, Antigravity, etc.) as atomic JSON writes to summary.json, then discovered and parsed by the transcript module at crates/ai-memory-workstream/src/transcript.rs.

The ai-memory project uses a standardized summary.json format to persist metadata about AI chat sessions. When a session terminates, the producing runtime serializes session identifiers, timing data, token usage, and message counts into this file. The core transcript module later reads this file to enable session discovery, indexing, and resumption.

What Contains a Session Summary

A session summary is a JSON file located at the root of a Grok-style session directory. The summary.json format contains a required info object with these fields:

  • info.id — A UUID uniquely identifying the session
  • info.cwd — The working directory the session was attached to
  • info.start / info.end — ISO 8601 timestamps delimiting the session
  • info.tokens — Token usage statistics (tokens in, tokens out)
  • info.messageCount — Total chat messages in the session
  • info.additional — Optional implementation-specific metadata (LLM model, provider, etc.)

Each session producer (Grok, Kiro v2/v3, Antigravity) assembles these fields based on its own runtime observations.

How the Transcript Module Discovers Sessions

The transcript module at crates/ai-memory-workstream/src/transcript.rs handles session discovery by parsing summary.json. The implementation reads the file and extracts the session identifier and checkout path.

From lines 2606–2620 of transcript.rs, the discovery logic:

let Ok(raw) = fs::read_to_string(session_dir.join("summary.json")) else { … };
let Ok(summary) = serde_json::from_str::<Value>(&raw) else { … };

The required fields are extracted from the info object:

let info = summary.get("info").unwrap_or(&Value::Null);
let (Some(id), Some(cwd)) = (
    info.get("id").and_then(Value::as_str),
    info.get("cwd").and_then(Value::as_str),
) else { … };

This parsing validates that summary.json contains the minimum metadata needed to identify and resume a session.

Atomic Write Pattern for Summary Generation

Session producers follow a repository-wide atomic-write convention to prevent data corruption. The pattern—implemented in ai-memory-wiki/src/wiki.rs and reused across crates—ensures summary.json appears atomically at session termination.

The write sequence:

  1. Serialize the session metadata to a JSON object
  2. Write to a temporary file (summary.json.tmp)
  3. Call fsync to flush to disk
  4. rename the temporary file to summary.json

This guarantees that readers never observe partially written summaries.

Complete Code Example: Reading a Session Summary

The transcript module uses this pattern to load session metadata:

use std::fs;
use std::path::{Path, PathBuf};
use serde_json::Value;

/// Returns the (session-id, cwd) pair from a summary.json file.
fn read_summary(session_dir: &Path) -> std::io::Result<(String, PathBuf)> {
    let raw = fs::read_to_string(session_dir.join("summary.json"))?;
    let json: Value = serde_json::from_str(&raw)?;
    let info = json.get("info").unwrap_or(&Value::Null);
    
    let id = info.get("id").and_then(Value::as_str).ok_or_else(|| {
        std::io::Error::new(std::io::ErrorKind::InvalidData, "missing id")
    })?;
    let cwd = info.get("cwd").and_then(Value::as_str).ok_or_else(|| {
        std::io::Error::new(std::io::ErrorKind::InvalidData, "missing cwd")
    })?;
    
    Ok((id.to_string(), PathBuf::from(cwd)))
}

This function returns the session UUID and working directory required to reconstruct the session context.

Complete Code Example: Generating a Session Summary

A session producer implements generation like this simplified illustration:

use std::fs;
use std::io::Write;
use std::path::Path;
use serde_json::json;
use uuid::Uuid;

/// Called when a session ends; writes `summary.json`.
fn write_summary(session_dir: &Path, id: &Uuid, cwd: &Path) -> std::io::Result<()> {
    let summary = json!({
        "info": {
            "id": id.to_string(),
            "cwd": cwd.to_string_lossy(),
            "start": chrono::Utc::now().to_rfc3339(),
            "end": chrono::Utc::now().to_rfc3339(),
            "tokens": 12345,
            "messageCount": 27
        }
    });
    
    // Atomic write: write to a temp file then rename
    let tmp_path = session_dir.join("summary.json.tmp");
    let mut tmp = fs::File::create(&tmp_path)?;
    tmp.write_all(summary.to_string().as_bytes())?;
    tmp.sync_all()?; // fsync
    fs::rename(tmp_path, session_dir.join("summary.json"))?;
    
    Ok(())
}

The sync_all() call ensures durability before the atomic rename makes the file visible to readers.

Key Source Files

File Role
crates/ai-memory-workstream/src/transcript.rs Discovers sessions by reading summary.json (lines 2606–2620)
crates/ai-memory-wiki/src/wiki.rs Contains the generic atomic-write helper for persisting summaries
Session-producer crates (ai-memory-workstream, ai-memory-wiki, etc.) Implement concrete logic for assembling and writing JSON at session termination

Summary

  • Session summaries are JSON files named summary.json living in session directories
  • Generation occurs at session termination by the runtime that produced the session (Grok, Kiro, Antigravity)
  • Atomic writes via temp-file-and-rename prevent corruption and ensure readers see complete data
  • Discovery happens in transcript.rs at lines 2606–2620, where serde_json parses the file and extracts info.id and info.cwd
  • The format standardizes session identity, timing, token usage, and message counts across all ai-memory producers

Frequently Asked Questions

What happens if summary.json is missing or corrupted?

The transcript module skips the directory. The read_to_string and serde_json::from_str calls both return Err variants that the caller handles by logging and continuing to the next session directory. No partial session data is exposed to downstream consumers.

Can session producers extend the summary.json format?

Yes, through the info.additional field. The base format requires only id and cwd; producers may attach implementation-specific metadata such as LLM model names, API providers, or custom telemetry without breaking the core discovery logic.

Why does ai-memory use atomic writes for JSON files?

The atomic temp-file-and-rename pattern prevents readers from observing partially written JSON during crashes or power failures. The fsync before rename guarantees that the data reaches stable storage, and rename is atomic on POSIX systems. This same pattern appears throughout ai-memory's persistence layer, including in ai-memory-wiki/src/wiki.rs.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →