Skip to main content
Glama

knowledge_sync_rules

Automatically syncs high-importance insights into IDE rules files, converting dynamic agent learnings into persistent project rules.

Instructions

Auto-sync graduated insights (importance >= 7) into your project's IDE rules file (.cursorrules or .clauderules). This bridges behavioral memory with static IDE context — turning dynamic agent learnings into always-on rules.

How it works:

  1. Fetches graduated insights from the ledger

  2. Formats them as markdown rules inside sentinel markers

  3. Idempotently writes them into the target file at the project's configured repo_path

Requirements: The project must have a repo_path configured in the dashboard.

Idempotency: Uses <!-- PRISM:AUTO-RULES:START --> / <!-- PRISM:AUTO-RULES:END --> sentinel markers. Running this tool multiple times produces the same file. User-maintained content outside the sentinels is never touched.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectYesProject identifier. Must have a repo_path configured in the dashboard.
target_fileNoTarget rules filename (default: '.cursorrules'). Common values: '.cursorrules', '.clauderules'.
dry_runNoIf true, returns a preview of the rules block without writing to disk. Default: false.

Implementation Reference

  • Implementation of the knowledge_sync_rules tool handler, which syncs graduated insights into IDE rules files (e.g., .cursorrules) using sentinel markers for idempotency.
    export async function knowledgeSyncRulesHandler(args: unknown) {
      if (!isKnowledgeSyncRulesArgs(args)) {
        throw new Error("Invalid arguments for knowledge_sync_rules");
      }
    
      const { project, target_file = ".cursorrules", dry_run = false } = args;
      const storage = await getStorage();
    
      // 1. Resolve repo path
      const repoPath = await getSetting(`repo_path:${project}`, "");
      if (!repoPath || !repoPath.trim()) {
        return {
          content: [{
            type: "text",
            text: `❌ No repo_path configured for project "${project}".\n` +
              `Set it in the Mind Palace dashboard (Settings → Project Repo Paths) before syncing rules.`,
          }],
          isError: true,
        };
      }
    
      const normalizedRepoPath = repoPath.trim().replace(/\/+$/, "");
    
      // 2. Fetch graduated insights
      const insights = await storage.getGraduatedInsights(project, PRISM_USER_ID, 7);
    
      if (insights.length === 0) {
        return {
          content: [{
            type: "text",
            text: `ℹ️ No graduated insights found for project "${project}".\n` +
              `Insights graduate when their importance score reaches 7 or higher.\n` +
              `Use \`knowledge_upvote\` to increase importance of valuable entries.`,
          }],
          isError: false,
        };
      }
    
      // 3. Format rules block
      const rulesBlock = formatRulesBlock(
        insights.map(i => ({ ...i, importance: i.importance ?? 0 })),
        project
      );
    
      // 4. Dry-run: return preview without writing
      if (dry_run) {
        return {
          content: [{
            type: "text",
            text: `🔍 **Dry Run Preview** — ${insights.length} graduated insight(s) for "${project}":\n\n` +
              `Target: ${normalizedRepoPath}/${target_file}\n\n` +
              `\`\`\`markdown\n${rulesBlock}\n\`\`\`\n\n` +
              `Run again without \`dry_run\` to write this to disk.`,
          }],
          isError: false,
        };
      }
    
      // 5. Idempotent file write — with path traversal protection
      // Reject absolute paths (e.g. "/etc/hosts")
      if (isAbsolute(target_file)) {
        return {
          content: [{
            type: "text",
            text: `❌ Security Error: target_file cannot be an absolute path. Got: "${target_file}"`,
          }],
          isError: true,
        };
      }
    
      // Resolve both paths to their canonical forms, then assert containment
      const resolvedRepo = resolve(normalizedRepoPath);
      const targetPath = resolve(resolvedRepo, target_file);
    
      // Ensure the resolved target is strictly inside the repo root
      // (handles "../../../etc/hosts" style traversal)
      if (!targetPath.startsWith(resolvedRepo + sep)) {
        return {
          content: [{
            type: "text",
            text: `❌ Security Error: Path traversal blocked.\n` +
              `"${target_file}" resolves outside the repo root "${resolvedRepo}".`,
          }],
          isError: true,
        };
      }
    
      // Ensure directory exists (handles nested target_file like ".config/rules.md")
      const targetDir = dirname(targetPath);
      if (!existsSync(targetDir)) {
        await mkdir(targetDir, { recursive: true });
      }
    
      let existingContent = "";
      try {
        existingContent = await readFile(targetPath, "utf-8");
      } catch {
        // File doesn't exist yet — will be created
        debugLog(`[knowledge_sync_rules] File ${targetPath} doesn't exist, creating new`);
      }
    
      const newContent = applySentinelBlock(existingContent, rulesBlock);
      await writeFile(targetPath, newContent, "utf-8");
    
      debugLog(`[knowledge_sync_rules] Synced ${insights.length} insights to ${targetPath}`);
    
      return {
        content: [{
          type: "text",
          text: `✅ Synced ${insights.length} graduated insight(s) to \`${targetPath}\`\n\n` +
            `Top insights synced:\n` +
            insights.slice(0, 5).map(i =>
              `  • [${i.importance}] ${i.summary.substring(0, 80)}${i.summary.length > 80 ? "..." : ""}`
            ).join("\n") +
            (insights.length > 5 ? `\n  ... and ${insights.length - 5} more` : ""),
        }],
        isError: false,
      };
    }
  • MCP tool schema definition for knowledge_sync_rules.
    export const KNOWLEDGE_SYNC_RULES_TOOL: Tool = {
      name: "knowledge_sync_rules",
      description:
        "Auto-sync graduated insights (importance >= 7) into your project's IDE rules file " +
        "(.cursorrules or .clauderules). This bridges behavioral memory with static IDE context — " +
        "turning dynamic agent learnings into always-on rules.\n\n" +
        "**How it works:**\n" +
        "1. Fetches graduated insights from the ledger\n" +
        "2. Formats them as markdown rules inside sentinel markers\n" +
        "3. Idempotently writes them into the target file at the project's configured repo_path\n\n" +
        "**Requirements:** The project must have a repo_path configured in the dashboard.\n\n" +
        "**Idempotency:** Uses `<!-- PRISM:AUTO-RULES:START -->` / `<!-- PRISM:AUTO-RULES:END -->` " +
        "sentinel markers. Running this tool multiple times produces the same file. " +
        "User-maintained content outside the sentinels is never touched.",
      inputSchema: {
        type: "object",
        properties: {
          project: {
            type: "string",
            description: "Project identifier. Must have a repo_path configured in the dashboard.",
          },
          target_file: {
            type: "string",
            description:
              "Target rules filename (default: '.cursorrules'). " +
              "Common values: '.cursorrules', '.clauderules'.",
          },
          dry_run: {
            type: "boolean",
            description: "If true, returns a preview of the rules block without writing to disk. Default: false.",
          },
        },
        required: ["project"],
      },
    };
  • src/server.ts:163-165 (registration)
    Registration of the knowledge_sync_rules tool and its handler in the main server file.
    // v4.2: Knowledge Sync Rules
    KNOWLEDGE_SYNC_RULES_TOOL,
    knowledgeSyncRulesHandler,

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/dcostenco/BCBA'

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