Skip to main content
Glama

agent_memory

Store and recall persistent memory across agents, sessions, and tools. Enable context retention and data sharing between different AI agents for consistent interactions.

Instructions

Cross-agent persistent memory — store and recall across sessions and tools

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The main execute function for the agent_memory tool. Handles four actions: store, recall, recall_by_tags, and get_recent. Includes size limits (10KB per entry, 1000 per agent) and SQLite-backed persistence.
    export function executeAgentMemory(
      db: FourDADatabase,
      params: AgentMemoryParams,
    ): object {
      const rawDb = db.getRawDb();
    
      switch (params.action) {
        // ========================================================================
        // STORE
        // ========================================================================
        case "store": {
          if (!params.subject || !params.content) {
            return { error: "subject and content are required for store action" };
          }
    
          // --- Size limit: max 10KB per entry ---
          const contentBytes = new TextEncoder().encode(params.content).length;
          if (contentBytes > MAX_CONTENT_BYTES) {
            return {
              error: `Content too large: ${contentBytes} bytes exceeds ${MAX_CONTENT_BYTES} byte limit (10KB)`,
            };
          }
    
          // --- Storage quota: max 1000 entries per agent ---
          const agentType = params.agent_type || "unknown";
          try {
            const countRow = rawDb
              .prepare(
                `SELECT COUNT(*) as cnt FROM agent_memory WHERE agent_type = ?`,
              )
              .get(agentType) as { cnt: number } | undefined;
            const currentCount = countRow?.cnt ?? 0;
            if (currentCount >= MAX_ENTRIES_PER_AGENT) {
              return {
                error: `Storage quota exceeded: agent "${agentType}" has ${currentCount} entries (max ${MAX_ENTRIES_PER_AGENT}). Delete old entries before storing new ones.`,
              };
            }
          } catch (quotaErr) {
            return {
              error: `Failed to check storage quota: ${quotaErr instanceof Error ? quotaErr.message : String(quotaErr)}`,
            };
          }
    
          try {
            const stmt = rawDb.prepare(
              `INSERT INTO agent_memory
                 (session_id, agent_type, memory_type, subject, content, context_tags, expires_at)
               VALUES (?, ?, ?, ?, ?, ?, ?)`,
            );
    
            const result = stmt.run(
              params.session_id || "unknown",
              params.agent_type || "unknown",
              params.memory_type || "context",
              params.subject,
              params.content,
              JSON.stringify(params.context_tags || []),
              params.expires_at || null,
            );
    
            return {
              success: true,
              id: result.lastInsertRowid,
              message: `Memory stored: ${params.subject}`,
            };
          } catch (error) {
            return {
              error: `Failed to store memory: ${error instanceof Error ? error.message : String(error)}`,
            };
          }
        }
    
        // ========================================================================
        // RECALL
        // ========================================================================
        case "recall": {
          if (!params.query) {
            return { error: "query is required for recall action" };
          }
    
          try {
            const pattern = `%${params.query.toLowerCase()}%`;
            let sql = `SELECT id, session_id, agent_type, memory_type, subject, content,
                              context_tags, created_at, expires_at, promoted_to_decision_id
                       FROM agent_memory
                       WHERE (LOWER(subject) LIKE ? OR LOWER(context_tags) LIKE ?)
                       AND (expires_at IS NULL OR expires_at > datetime('now'))`;
            const sqlParams: (string | number)[] = [pattern, pattern];
    
            if (params.filter_agent) {
              sql += ` AND agent_type = ?`;
              sqlParams.push(params.filter_agent);
            }
    
            sql += ` ORDER BY created_at DESC LIMIT ?`;
            sqlParams.push(params.limit || 20);
    
            const rows = rawDb.prepare(sql).all(...sqlParams) as AgentMemoryRow[];
    
            return {
              memories: rows.map(parseMemoryRow),
              count: rows.length,
            };
          } catch (error) {
            return {
              memories: [],
              count: 0,
              error: `Failed to recall memories: ${error instanceof Error ? error.message : String(error)}`,
            };
          }
        }
    
        // ========================================================================
        // RECALL BY TAGS
        // ========================================================================
        case "recall_by_tags": {
          if (!params.tags || params.tags.length === 0) {
            return { error: "tags array is required for recall_by_tags action" };
          }
    
          try {
            // Build OR conditions for each tag
            const conditions = params.tags.map(
              () => `LOWER(context_tags) LIKE ?`,
            );
            const tagParams = params.tags.map((t) => `%${t.toLowerCase()}%`);
    
            const sql = `SELECT id, session_id, agent_type, memory_type, subject, content,
                                context_tags, created_at, expires_at, promoted_to_decision_id
                         FROM agent_memory
                         WHERE (${conditions.join(" OR ")})
                         AND (expires_at IS NULL OR expires_at > datetime('now'))
                         ORDER BY created_at DESC LIMIT ?`;
    
            const rows = rawDb
              .prepare(sql)
              .all(...tagParams, params.limit || 20) as AgentMemoryRow[];
    
            return {
              memories: rows.map(parseMemoryRow),
              count: rows.length,
            };
          } catch (error) {
            return {
              memories: [],
              count: 0,
              error: `Failed to recall by tags: ${error instanceof Error ? error.message : String(error)}`,
            };
          }
        }
    
        // ========================================================================
        // GET RECENT
        // ========================================================================
        case "get_recent": {
          const since =
            params.since ||
            new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
    
          try {
            let sql = `SELECT id, session_id, agent_type, memory_type, subject, content,
                              context_tags, created_at, expires_at, promoted_to_decision_id
                       FROM agent_memory
                       WHERE created_at > ?`;
            const sqlParams: (string | number)[] = [since];
    
            if (params.filter_agent) {
              sql += ` AND agent_type = ?`;
              sqlParams.push(params.filter_agent);
            }
    
            sql += ` ORDER BY created_at DESC LIMIT ?`;
            sqlParams.push(params.limit || 50);
    
            const rows = rawDb.prepare(sql).all(...sqlParams) as AgentMemoryRow[];
    
            return {
              memories: rows.map(parseMemoryRow),
              count: rows.length,
              since,
            };
          } catch (error) {
            return {
              memories: [],
              count: 0,
              since,
              error: `Failed to get recent memories: ${error instanceof Error ? error.message : String(error)}`,
            };
          }
        }
    
        default:
          return { error: `Unknown action: ${params.action}` };
      }
    }
  • The tool definition with name 'agent_memory' and full inputSchema describing all parameters (action enum, session_id, agent_type, memory_type, subject, content, context_tags, expires_at, query, filter_agent, limit, tags, since).
    export const agentMemoryTool = {
      name: "agent_memory",
      description:
        "Cross-agent persistent memory. Actions: store (save a memory), recall (search by subject), recall_by_tags (search by tags), get_recent (memories since timestamp). What one agent learns, all agents can access.",
      inputSchema: {
        type: "object" as const,
        properties: {
          action: {
            type: "string",
            enum: ["store", "recall", "recall_by_tags", "get_recent"],
            description: "Action to perform",
          },
          session_id: {
            type: "string",
            description: "Session identifier (for store)",
          },
          agent_type: {
            type: "string",
            description:
              "Agent identifier, e.g. claude_code, cursor, windsurf (for store)",
          },
          memory_type: {
            type: "string",
            enum: ["discovery", "decision", "context", "warning", "preference"],
            description: "Type of memory (for store). Default: context",
          },
          subject: {
            type: "string",
            description: "Short subject line for the memory (for store)",
          },
          content: {
            type: "string",
            description: "Full memory content (for store)",
          },
          context_tags: {
            type: "array",
            items: { type: "string" },
            description: "Tags for categorization (for store)",
          },
          expires_at: {
            type: "string",
            description: "ISO datetime when this memory expires (for store, optional)",
          },
          query: {
            type: "string",
            description: "Search term to match against subject and tags (for recall)",
          },
          filter_agent: {
            type: "string",
            description: "Filter results to a specific agent type (for recall, get_recent)",
          },
          limit: {
            type: "number",
            description: "Max results to return (default 20)",
          },
          tags: {
            type: "array",
            items: { type: "string" },
            description: "Tags to search for (for recall_by_tags)",
          },
          since: {
            type: "string",
            description: "ISO datetime to get memories after (for get_recent)",
          },
        },
        required: ["action"],
      },
  • Registration of 'agent_memory' in the dispatch map, mapping the tool name to the executeAgentMemory handler.
      // Agent
      agent_memory: executeAgentMemory,
    
      // Identity
      developer_dna: executeDeveloperDna,
    };
  • Schema registry entry for agent_memory, categorized under 'agent' with tags and reference to agent-memory.json schema file.
    // --- Agent (standalone) ---
    agent_memory: {
      summary: "Cross-agent persistent memory — store and recall across sessions and tools",
      schemaFile: "agent-memory.json",
      category: "agent",
      tags: ["agent", "memory", "persistent", "cross-session"],
      standalone: true,
    },
  • Helper function parseMemoryRow that converts a raw AgentMemoryRow (with JSON-stringified context_tags) into a structured object.
    function parseMemoryRow(row: AgentMemoryRow) {
      return {
        id: row.id,
        session_id: row.session_id,
        agent_type: row.agent_type,
        memory_type: row.memory_type,
        subject: row.subject,
        content: row.content,
        context_tags: JSON.parse(row.context_tags || "[]") as string[],
        created_at: row.created_at,
        expires_at: row.expires_at,
        promoted_to_decision_id: row.promoted_to_decision_id,
      };
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description bears full responsibility for behavioral disclosure. It mentions persistence and cross-session storage but omits critical traits like whether data is retrievable by any agent, storage limits, or potential side effects. The minimal description leaves the agent uninformed about safety and mutability.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, concise sentence that conveys the core purpose without unnecessary words. It is front-loaded and efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the lack of parameters and output schema, the description should explain how the tool is used (e.g., does it return data? Is it implicitly invoked?). The brief description does not provide enough context for an agent to confidently use the tool, leaving behavioral and invocation details ambiguous.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has no parameters, so the baseline is 4. The description adds no parameter-level detail, but since there are none, it does not need to compensate. The description's mention of 'store and recall' provides minimal functional context beyond the empty schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool is for cross-agent persistent memory with store and recall capabilities, effectively identifying the resource and actions. However, it does not explicitly differentiate from sibling tools like decision_memory, which may have overlapping functions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use this tool versus alternatives, nor are there any usage restrictions or prerequisites. The description only states what it does without contextual cues for invocation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/runyourempire/4DA'

If you have feedback or need assistance with the MCP directory API, please join our Discord server