Skip to main content
Glama

save_rule

Save mandatory rules that apply to every session, bypassing scoring and decay. Use for absolute requirements like 'ALWAYS do Y' or 'NEVER do X'.

Instructions

Save a mandatory rule that will ALWAYS be followed in every session. Rules bypass scoring and decay — they are injected into every conversation, every time. Use for absolute requirements like "NEVER do X" or "ALWAYS do Y".

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
contentYesThe rule to enforce (e.g., "NEVER use -latest model aliases", "ALWAYS apply changes to both class-chat.php AND class-maas.php")
subjectNoShort label for the rule, e.g. "model_aliases", "companions_parity"
scopeNoglobal = applies to all projects, project = only this codebaseproject
categoryNoCategory for organization: frontend, backend, security, general, etc.general
tagsNoOptional tags for grouping rules
project_idNoProject identifier override (auto-detected from CLAUDE_PROJECT_DIR or git remote if omitted)

Implementation Reference

  • The handler function for the save_rule tool. It registers the tool on the MCP server with Zod schema for inputs (content, subject, scope, category, tags, project_id). The handler creates a memory with memory_type='rule' and importance=10, calls storage.saveMemory(), resets debt, and returns the result with merge suggestions.
    server.tool(
      'save_rule',
      'Save a mandatory rule that will ALWAYS be followed in every session. Rules bypass scoring and decay — they are injected into every conversation, every time. Use for absolute requirements like "NEVER do X" or "ALWAYS do Y".',
      {
        content: z
          .string()
          .min(5)
          .max(10000)
          .describe('The rule to enforce (e.g., "NEVER use -latest model aliases", "ALWAYS apply changes to both class-chat.php AND class-maas.php")'),
        subject: z
          .string()
          .max(100)
          .default('')
          .describe('Short label for the rule, e.g. "model_aliases", "companions_parity"'),
        scope: z
          .enum(['global', 'project'])
          .default('project')
          .describe('global = applies to all projects, project = only this codebase'),
        category: z
          .string()
          .max(50)
          .default('general')
          .describe('Category for organization: frontend, backend, security, general, etc.'),
        tags: z
          .array(z.string().max(30))
          .max(5)
          .optional()
          .describe('Optional tags for grouping rules'),
        project_id: z
          .string()
          .max(200)
          .optional()
          .describe('Project identifier override (auto-detected from CLAUDE_PROJECT_DIR or git remote if omitted)'),
      },
      async ({ content, subject, scope, category, tags, project_id }) => {
        try {
          const projectId = project_id || detectProjectId();
          const body: Record<string, unknown> = {
            content,
            memory_type: 'rule',
            category,
            subject,
            importance: 10, // Rules are always max importance
            scope,
            project_id: projectId,
          };
          if (tags && tags.length > 0) body.tags = tags;
          const result = await storage.saveMemory(body);
          resetDebt();
          return wrapResult(annotateMergeSuggestion(result));
        } catch (error) {
          return wrapError(error);
        }
      }
    );
  • Zod input schema for save_rule: content (string, 5-10000 chars), subject (string max 100), scope (enum global/project), category (string max 50), tags (array of strings max 5), project_id (optional string).
    {
      content: z
        .string()
        .min(5)
        .max(10000)
        .describe('The rule to enforce (e.g., "NEVER use -latest model aliases", "ALWAYS apply changes to both class-chat.php AND class-maas.php")'),
      subject: z
        .string()
        .max(100)
        .default('')
        .describe('Short label for the rule, e.g. "model_aliases", "companions_parity"'),
      scope: z
        .enum(['global', 'project'])
        .default('project')
        .describe('global = applies to all projects, project = only this codebase'),
      category: z
        .string()
        .max(50)
        .default('general')
        .describe('Category for organization: frontend, backend, security, general, etc.'),
      tags: z
        .array(z.string().max(30))
        .max(5)
        .optional()
        .describe('Optional tags for grouping rules'),
      project_id: z
        .string()
        .max(200)
        .optional()
        .describe('Project identifier override (auto-detected from CLAUDE_PROJECT_DIR or git remote if omitted)'),
    },
  • src/tools.ts:293-347 (registration)
    The save_rule tool is registered via server.tool('save_rule', ...) in the registerTools function (line 193), which is called from both index.ts (line 109) and http-server.ts (line 176).
    server.tool(
      'save_rule',
      'Save a mandatory rule that will ALWAYS be followed in every session. Rules bypass scoring and decay — they are injected into every conversation, every time. Use for absolute requirements like "NEVER do X" or "ALWAYS do Y".',
      {
        content: z
          .string()
          .min(5)
          .max(10000)
          .describe('The rule to enforce (e.g., "NEVER use -latest model aliases", "ALWAYS apply changes to both class-chat.php AND class-maas.php")'),
        subject: z
          .string()
          .max(100)
          .default('')
          .describe('Short label for the rule, e.g. "model_aliases", "companions_parity"'),
        scope: z
          .enum(['global', 'project'])
          .default('project')
          .describe('global = applies to all projects, project = only this codebase'),
        category: z
          .string()
          .max(50)
          .default('general')
          .describe('Category for organization: frontend, backend, security, general, etc.'),
        tags: z
          .array(z.string().max(30))
          .max(5)
          .optional()
          .describe('Optional tags for grouping rules'),
        project_id: z
          .string()
          .max(200)
          .optional()
          .describe('Project identifier override (auto-detected from CLAUDE_PROJECT_DIR or git remote if omitted)'),
      },
      async ({ content, subject, scope, category, tags, project_id }) => {
        try {
          const projectId = project_id || detectProjectId();
          const body: Record<string, unknown> = {
            content,
            memory_type: 'rule',
            category,
            subject,
            importance: 10, // Rules are always max importance
            scope,
            project_id: projectId,
          };
          if (tags && tags.length > 0) body.tags = tags;
          const result = await storage.saveMemory(body);
          resetDebt();
          return wrapResult(annotateMergeSuggestion(result));
        } catch (error) {
          return wrapError(error);
        }
      }
    );
  • The save_rule handler uses storage.saveMemory() as a helper, setting memory_type='rule' and importance=10 to create mandatory rules. It also calls resetDebt() and annotateMergeSuggestion() helpers.
    // ─── 1b. save_rule ──────────────────────────────────────
    // Rules are mandatory memories that ALWAYS surface in every session.
    // They bypass scoring, decay, and relevance filtering.
    
    server.tool(
      'save_rule',
      'Save a mandatory rule that will ALWAYS be followed in every session. Rules bypass scoring and decay — they are injected into every conversation, every time. Use for absolute requirements like "NEVER do X" or "ALWAYS do Y".',
      {
        content: z
          .string()
          .min(5)
          .max(10000)
          .describe('The rule to enforce (e.g., "NEVER use -latest model aliases", "ALWAYS apply changes to both class-chat.php AND class-maas.php")'),
        subject: z
          .string()
          .max(100)
          .default('')
          .describe('Short label for the rule, e.g. "model_aliases", "companions_parity"'),
        scope: z
          .enum(['global', 'project'])
          .default('project')
          .describe('global = applies to all projects, project = only this codebase'),
        category: z
          .string()
          .max(50)
          .default('general')
          .describe('Category for organization: frontend, backend, security, general, etc.'),
        tags: z
          .array(z.string().max(30))
          .max(5)
          .optional()
          .describe('Optional tags for grouping rules'),
        project_id: z
          .string()
          .max(200)
          .optional()
          .describe('Project identifier override (auto-detected from CLAUDE_PROJECT_DIR or git remote if omitted)'),
      },
      async ({ content, subject, scope, category, tags, project_id }) => {
        try {
          const projectId = project_id || detectProjectId();
          const body: Record<string, unknown> = {
            content,
            memory_type: 'rule',
            category,
            subject,
            importance: 10, // Rules are always max importance
            scope,
            project_id: projectId,
          };
          if (tags && tags.length > 0) body.tags = tags;
          const result = await storage.saveMemory(body);
          resetDebt();
          return wrapResult(annotateMergeSuggestion(result));
        } catch (error) {
          return wrapError(error);
        }
      }
    );
Behavior4/5

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

No annotations are provided, so the description carries the full burden. It clearly explains that rules bypass scoring and decay and are injected every session. However, it does not disclose potential overwrites, limits, or permission requirements.

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 concise three-sentence paragraph with no redundant information. Each sentence adds value: purpose, behavioral specifics, and usage examples. It is front-loaded with the core action.

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

Completeness4/5

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

The description covers the core purpose and behavioral context well, but it does not mention scope, category, or project-specific behavior. Given the schema provides these details, the description is adequate but could be more comprehensive about defaults like project-scoped rules.

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

Parameters3/5

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

Schema description coverage is 100%, so the baseline is 3. The tool description adds no extra parameter-level information beyond what the schema already provides. It focuses on purpose rather than parameter details.

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 saves a mandatory rule that is always followed, with examples of absolute requirements. It distinguishes itself from sibling tools like list_rules and delete_rule by focusing on creation of always-enforced rules.

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

Usage Guidelines4/5

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

The description explicitly advises using the tool for absolute requirements like 'NEVER do X' or 'ALWAYS do Y', providing positive usage guidance. However, it does not mention when not to use it or compare with alternatives like save_memory.

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/hifriendbot/cogmemai-mcp'

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