How the Skill Module Handles CRUD Operations and Fast Retrieval in TencentDB-Agent-Memory

The Skill Module implements atomic CRUD operations through the SkillClient SDK while delivering sub-millisecond retrieval performance via an in-memory fast-path matcher that prioritizes exact name matches before BM25 ranking.

The Skill Module serves as the knowledge-base core within the TencentCloud/TencentDB-Agent-Memory repository, providing persistent storage, versioning, and hybrid search capabilities for agent skills. This architecture separates API handling from storage logic while maintaining a specialized fast-retrieval channel for instant name-based lookups. Understanding how the module orchestrates these layers reveals a system optimized for both data integrity and retrieval speed.

Architecture Overview

The Skill Module operates through three distinct architectural layers that handle requests from HTTP ingress to persistent storage.

The SkillCore class in MemoryCore/src/core/skill/skill-core.ts orchestrates these layers, handling business logic for versioning, permission checks, and result merging between fast-path and standard search channels.

CRUD Operations Implementation

All CRUD operations flow through the SkillClient SDK, which constructs request bodies by merging per-call parameters with client-wide defaults. The server returns specific error codes (40001, 40301, 40302) for missing or invalid IDs rather than throwing client-side exceptions.

Creating and Versioning Skills

The Create operation initializes a skill at version 1 with is_head=true. When invoked via SkillClient.create(), the method builds a request body containing name, content, resources, and metadata:

create(params: SkillCreateRequest): Promise<SkillSummary> {
    const body = stripUndefined({
        ...this.ids(params),
        name: params.name,
        content: params.content,
        resources: params.resources,
        metadata: params.metadata,
    });
    return this.http.post(`${V3}/create`, body);
}

At the storage layer, SqliteSkillStore.appendVersion() in MemoryCore/src/core/skill/skill-store.ts executes three atomic operations within a single transaction: inserting the new row with is_head=1, updating the previous head to is_head=0, and triggering FTS5 synchronization.

Reading and Listing Skills

The Get operation retrieves either the current head row or a specific historical version through SkillClient.get(), executing SQL queries that filter by skill_id and either version or is_head=1.

The List operation (SkillClient.list()) returns paginated head rows for a team using SELECT * FROM skills WHERE is_head=1 AND team_id=?. For full-text retrieval, SkillClient.search() invokes SkillStore.searchSkills() to perform BM25 ranking, optionally combining results with vector similarity searches when embedding dimensions are configured.

Updating and Patching Skills

Two distinct update mechanisms handle different modification patterns:

  • Update (SkillClient.update()): Replaces the entire skill markdown content and bumps the version number, invoking appendVersion() with the complete new content.

  • Patch (SkillClient.patch()): Applies string-replacement edits (such as s/Python/JS/g) to the existing content before creating a new version through the same appendVersion store method.

Both operations maintain immutable history by creating new rows rather than modifying existing records, ensuring full audit trails through the versioning system.

Deletion and Archival

The Delete operation (SkillClient.delete()) performs a soft archive rather than hard deletion. It marks the head row with status='archived' without bumping the version number, preserving the skill's history while removing it from active listings and search results.

The Fast-Path Retrieval Mechanism

The fast-path channel addresses latency requirements for name-explicit skill recall, processing queries in under 5 milliseconds for datasets containing 80,000 skills.

In-Memory Substring Matching

The nameMatchFastPath function in MemoryCore/src/core/skill/skill-fast-path.ts implements a lightweight filter over the in-memory array of skill heads:

export function nameMatchFastPath(
  query: string,
  skills: Skill[],
  minLength: number = DEFAULT_NAME_MATCH_MIN_LENGTH,
): Skill[] {
  const q = (query ?? "").toLowerCase().trim();
  if (q === "") return [];
  return skills.filter(
    (s) => s.name.length >= minLength && q.includes(s.name.toLowerCase()),
  );
}

This function performs no I/O operations, executing entirely within RAM to check if the lowercase query string contains the lowercase skill name.

Parallel Search and Result Merging

When SkillClient.listing() is invoked, SkillCore.handleListing executes two operations concurrently:

  1. Standard Search: Queries the SQLite store using BM25 full-text search via SqliteSkillStore.searchSkills().
  2. Fast-Path Execution: Runs nameMatchFastPath against the cached head rows in memory.

The results merge with fast-path hits positioned at the front of the result set, followed by deduplicated BM25 and embedding-based results. This merged list renders into an <available_skills> block suitable for downstream LLM prompt injection, ensuring immediate recall for exact name matches while preserving semantic search capabilities for broader queries.

Working with the Skill Module SDK

Complete CRUD Workflow

The following TypeScript example demonstrates the full lifecycle using the SDK:

import { SkillClient } from "tencentdb-agent-memory";

const skills = new SkillClient({
  endpoint: "https://memory.tencentyun.com",
  apiKey: "sk-REPLACE_WITH_KEY",
  serviceId: "mem-abc",
  teamId: "team-1",
  agentId: "agent-coder",
  userId: "user-42",
});

// Create
const created = await skills.create({
  name: "py-tips",
  content: "---\nname: py-tips\nsummary: Python best-practices\n---\n",
});

// Update (full replacement)
const updated = await skills.update({
  skill_id: created.skill_id,
  name: "py-tips",
  content: "---\nname: py-tips\nsummary: Updated Python tricks\n---\n",
});

// Patch (string replacement)
await skills.patch({
  skill_id: created.skill_id,
  patch: "s/Python/JS/g",
});

// Delete (soft archive)
await skills.delete({ skill_id: created.skill_id });

Fast Retrieval Integration

To leverage the fast-path optimization when fetching skills for prompt context:

const listing = await skills.listing({
  pagination: { limit: 20 },
});

console.log(listing.listing_block); // Pre-formatted <available_skills> block

Direct Store Access

For advanced use cases requiring direct database interaction:

import { SqliteSkillStore } from "./MemoryCore/src/core/skill/skill-store";
import { openSync } from "sqlite3";

const db = openSync(":memory:");
const store = new SqliteSkillStore({ db, dimensions: 0 });
store.init(); // Creates tables and FTS5 index

await store.appendVersion({
  skill_id: "skill-123",
  name: "demo-skill",
  content: "Hello world",
  user_id: "u1",
  owner_agent_id: "a1",
  team_id: "t1",
  task_id: "",
});

Summary

  • Atomic Versioning: All write operations (create, update, patch) invoke SqliteSkillStore.appendVersion() to create immutable historical records with automatic head-row management.

  • Soft Deletion: The delete operation sets status='archived' without removing data or incrementing versions, preserving complete audit trails.

  • Dual-Channel Search: The system combines BM25 full-text search with an in-memory fast-path matcher to prioritize exact name matches while maintaining semantic search capabilities.

  • Sub-Millisecond Fast-Path: The nameMatchFastPath function executes entirely in RAM, filtering 80,000 skills in under 5 milliseconds by performing substring matches against skill names.

  • Schema Isolation: The SkillClient automatically injects teamId, agentId, userId, and taskId into all requests, enforcing multi-tenant data isolation at the API layer.

Frequently Asked Questions

What is the difference between Update and Patch operations in the Skill Module?

Update replaces the entire skill markdown content and metadata with new values, while Patch applies a string-replacement transformation (such as regex substitution) to the existing content before saving. Both operations create new version rows through SqliteSkillStore.appendVersion(), but Patch allows surgical edits without resubmitting the full document.

How does the fast-path retrieval achieve sub-millisecond performance?

The fast-path operates entirely in memory through the nameMatchFastPath function in MemoryCore/src/core/skill/skill-fast-path.ts, performing simple lowercase substring checks against cached skill names without database I/O. Because it avoids SQLite queries and runs as a pure JavaScript filter operation, it processes tens of thousands of skills in under 5 milliseconds.

Does deleting a skill permanently remove it from the database?

No. The SkillClient.delete() method performs a soft deletion by updating the head row's status field to 'archived' in MemoryCore/src/core/skill/skill-store.ts. The historical versions remain intact, and the version number does not increment, allowing for potential unarchival while immediately excluding the skill from search and listing results.

How are search results ranked when both fast-path and BM25 results exist?

SkillCore.handleListing merges the two result sets by placing fast-path matches at the beginning of the response array, followed by BM25 and embedding-based results. The system deduplicates entries to prevent double-listing, ensuring that name-explicit matches receive top priority in the final <available_skills> block while preserving the semantic relevance ordering of traditional search results.

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 →