Skip to main content
Glama

remember

Store project-specific conventions, decisions, and failures with reasons to build a persistent codebase memory that guides future development.

Instructions

Routes to the active/current project automatically when known. CALL IMMEDIATELY when user explicitly asks to remember/record something.

USER TRIGGERS:

  • "Remember this: [X]"

  • "Record this: [Y]"

  • "Save this for next time: [Z]"

DO NOT call unless user explicitly requests it.

HOW TO WRITE:

  • ONE convention per memory (if user lists 5 things, call this 5 times)

  • memory: 5-10 words (the specific rule)

  • reason: 1 sentence (why it matters)

  • Skip: one-time features, code examples, essays

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
typeYesType of memory being recorded. Use "failure" for things that were tried and failed - prevents repeating the same mistakes.
categoryYesBroader category for filtering
memoryYesWhat to remember (concise)
reasonYesWhy this matters or what breaks otherwise
scopeNoOptional scope for this memory. Use { kind: "file", file } or { kind: "symbol", file, symbol }.
projectNoOptional project selector for this call. Accepts a project root path, file path, file:// URI, or a relative subproject path under a configured root.
project_directoryNoDeprecated compatibility alias for older clients. Prefer project.

Implementation Reference

  • The main handler function that executes the 'remember' tool logic. It takes user args (type, category, memory, reason, optional scope), creates a SHA-256 content-hash ID, constructs a Memory object, and appends it to the memory file via appendMemoryFile. Returns success, duplicate info, or error.
    export async function handle(
      args: Record<string, unknown>,
      ctx: ToolContext
    ): Promise<ToolResponse> {
      const args_typed = args as {
        type?: MemoryType;
        category: MemoryCategory;
        memory: string;
        reason: string;
        scope?: MemoryScope;
      };
    
      const { type = 'decision', category, memory, reason } = args_typed;
      const scope = normalizeMemoryScope(args_typed.scope);
    
      try {
        const crypto = await import('crypto');
        const memoryPath = ctx.paths.memory;
    
        const hashContent = buildMemoryIdentityParts({ type, category, memory, reason, scope });
        const hash = crypto.createHash('sha256').update(hashContent).digest('hex');
        const id = hash.substring(0, 12);
    
        const newMemory: Memory = {
          id,
          type,
          category,
          memory,
          reason,
          date: new Date().toISOString(),
          ...(scope && { scope })
        };
    
        const result = await appendMemoryFile(memoryPath, newMemory);
    
        if (result.status === 'duplicate') {
          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify(
                  {
                    status: 'info',
                    message: 'This memory was already recorded.',
                    memory: result.memory
                  },
                  null,
                  2
                )
              }
            ]
          };
        }
    
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify(
                {
                  status: 'success',
                  message: 'Memory recorded successfully.',
                  memory: result.memory
                },
                null,
                2
              )
            }
          ]
        };
      } catch (error) {
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify(
                {
                  status: 'error',
                  message: 'Failed to record memory.',
                  error: error instanceof Error ? error.message : String(error)
                },
                null,
                2
              )
            }
          ]
        };
      }
    }
  • Input schema and tool definition for 'remember'. Defines the tool name, description with usage instructions, and inputSchema specifying type (convention/decision/gotcha/failure), category (tooling/architecture/testing/dependencies/conventions), memory (what to remember), reason, and optional scope (global/file/symbol). Required fields: type, category, memory, reason.
    export const definition: Tool = {
      name: 'remember',
      description:
        'CALL IMMEDIATELY when user explicitly asks to remember/record something.\n\n' +
        'USER TRIGGERS:\n' +
        '- "Remember this: [X]"\n' +
        '- "Record this: [Y]"\n' +
        '- "Save this for next time: [Z]"\n\n' +
        'DO NOT call unless user explicitly requests it.\n\n' +
        'HOW TO WRITE:\n' +
        '- ONE convention per memory (if user lists 5 things, call this 5 times)\n' +
        '- memory: 5-10 words (the specific rule)\n' +
        '- reason: 1 sentence (why it matters)\n' +
        '- Skip: one-time features, code examples, essays',
      inputSchema: {
        type: 'object',
        properties: {
          type: {
            type: 'string',
            enum: ['convention', 'decision', 'gotcha', 'failure'],
            description:
              'Type of memory being recorded. Use "failure" for things that were tried and failed - ' +
              'prevents repeating the same mistakes.'
          },
          category: {
            type: 'string',
            description: 'Broader category for filtering',
            enum: ['tooling', 'architecture', 'testing', 'dependencies', 'conventions']
          },
          memory: {
            type: 'string',
            description: 'What to remember (concise)'
          },
          reason: {
            type: 'string',
            description: 'Why this matters or what breaks otherwise'
          },
          scope: {
            type: 'object',
            description:
              'Optional scope for this memory. Use { kind: "file", file } or { kind: "symbol", file, symbol }.',
            properties: {
              kind: {
                type: 'string',
                enum: ['global', 'file', 'symbol']
              },
              file: {
                type: 'string'
              },
              symbol: {
                type: 'string'
              }
            }
          }
        },
        required: ['type', 'category', 'memory', 'reason']
      }
    };
  • Import of the 'remember' tool's definition and handler (as d9/h9) in the tools index.
    import { definition as d9, handle as h9 } from './remember.js';
  • Tool registration: 'remember' definition (d9) is included in the TOOLS array and passed through withProjectSelector to add project routing properties.
    export const TOOLS: Tool[] = [d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11].map(
      withProjectSelector
    );
  • Dispatch routing: case 'remember' maps to h9 (the handler from remember.ts) in the dispatchTool switch statement.
    case 'remember':
      return h9(args, ctx);
  • appendMemoryFile helper: reads existing memories from file, checks for duplicates by ID, appends the new memory if not duplicate, and writes back to disk.
    export async function appendMemoryFile(
      memoryPath: string,
      memory: Memory
    ): Promise<{ status: 'added' | 'duplicate'; memory: Memory }> {
      const existing = await readMemoriesFile(memoryPath);
      const found = existing.find((m) => m.id === memory.id);
      if (found) return { status: 'duplicate', memory: found };
      existing.push(memory);
      await writeMemoriesFile(memoryPath, existing);
      return { status: 'added', memory };
    }
  • buildMemoryIdentityParts helper: constructs a deterministic string from memory fields (type, category, memory, reason, scope) used as input for SHA-256 hashing to generate a content-based ID.
    export function buildMemoryIdentityParts(memory: {
      type: MemoryType;
      category: MemoryCategory;
      memory: string;
      reason: string;
      scope?: MemoryScope;
    }): string {
      const scopePart =
        !memory.scope || memory.scope.kind === 'global'
          ? 'global'
          : memory.scope.kind === 'file'
            ? `file:${normalizePathLike(memory.scope.file)}`
            : `symbol:${normalizePathLike(memory.scope.file)}:${memory.scope.symbol}`;
      return `${memory.type}:${memory.category}:${memory.memory}:${memory.reason}:${scopePart}`;
    }
  • normalizeMemoryScope helper: validates and normalizes the optional scope argument (global, file, or symbol) for the remember tool.
    export function normalizeMemoryScope(raw: unknown): MemoryScope | undefined {
      if (!isRecord(raw)) return undefined;
      const kind = raw.kind;
      if (kind === 'global') {
        return { kind };
      }
      if (kind === 'file' && typeof raw.file === 'string' && raw.file.trim()) {
        return { kind, file: normalizePathLike(raw.file.trim()) };
      }
      if (
        kind === 'symbol' &&
        typeof raw.file === 'string' &&
        raw.file.trim() &&
        typeof raw.symbol === 'string' &&
        raw.symbol.trim()
      ) {
        return {
          kind,
          file: normalizePathLike(raw.file.trim()),
          symbol: raw.symbol.trim()
        };
      }
      return undefined;
    }
  • MemoryCategory type definition: union of 'tooling', 'architecture', 'testing', 'dependencies', 'conventions'.
    export type MemoryCategory =
      | 'tooling' // Build tools, package managers, linting, IDE config
      | 'architecture' // Layers, folder structure, module boundaries
      | 'testing' // Test frameworks, mocking strategies, coverage
      | 'dependencies' // Library choices, wrappers, versioning, package management
      | 'conventions'; // Naming, style, organization not captured in patterns
  • MemoryType type definition: union of 'convention', 'decision', 'gotcha', 'failure'.
    export type MemoryType =
      | 'convention' // Style, naming, component preferences
      | 'decision' // Architecture/tooling choices with rationale
      | 'gotcha' // Things that break and why
      | 'failure'; // Tried X, failed because Y — prevents repeating mistakes
  • Memory interface: defines the shape of a stored memory record (id, type, category, memory, reason, date, source, scope).
    export interface Memory {
      /** Content-based hash ID (first 12 chars of SHA-256) */
      id: string;
      /** Type of knowledge: convention, decision, or gotcha */
      type: MemoryType;
      /** Category for organization and filtering */
      category: MemoryCategory;
      /** Brief description of what to remember */
      memory: string;
      /** Why this decision was made - the rationale/context */
      reason: string;
      /** ISO 8601 date when decision was recorded */
      date: string;
      /** Source of the memory: 'user' (default) or 'git' (auto-extracted from commits) */
      source?: 'user' | 'git';
      /** Optional scope for file-specific or symbol-specific guidance */
      scope?: MemoryScope;
    }
  • MemoryScope type definition: union of {kind:'global'}, {kind:'file', file}, {kind:'symbol', file, symbol}.
    export type MemoryScope =
      | { kind: 'global' }
      | { kind: 'file'; file: string }
      | { kind: 'symbol'; file: string; symbol: string };
Behavior3/5

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

No annotations are provided, so the description must cover behavioral traits. It mentions 'Routes to the active/current project automatically' but does not disclose side effects (e.g., whether memories overwrite, persistence, permissions, or rate limits). The instructions on writing style give some behavioral expectations but leave significant gaps.

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

Conciseness4/5

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

The description is structured with headings (USER TRIGGERS, DO NOT, HOW TO WRITE) and front-loads the key action. While it is somewhat lengthy, every section serves a purpose. Minor redundancy in listing all triggers could be trimmed, but overall it is well-organized.

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

Completeness3/5

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

With 7 parameters (4 required) and no output schema, the description provides good guidance on when and how to call, but omits post-call behavior (e.g., success confirmation, error handling). The agent must infer that memories are stored since get_memory exists. Context is adequate but not fully complete.

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?

Schema coverage is 100%, so baseline is 3. The description adds value by providing guidance on how to write 'memory' (5-10 words) and 'reason' (1 sentence), and explains when to use 'failure' type. This enriches the schema descriptions and helps the agent use parameters effectively.

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

Purpose5/5

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

The description clearly states the tool's purpose: to remember/record something when the user explicitly asks. It lists specific user triggers ('Remember this', 'Record this', 'Save this for next time') and provides instructions for when to call it. This differentiates it from siblings like get_memory, which retrieves memories.

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

Usage Guidelines5/5

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

The description provides explicit guidelines: 'CALL IMMEDIATELY when user explicitly asks to remember/record something' and 'DO NOT call unless user explicitly requests it.' It also gives writing conventions ('ONE convention per memory', 'memory: 5-10 words', 'Skip: one-time features, code examples, essays'), making the usage clear.

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/PatrickSys/codebase-context'

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