How Dexter Deduplicates Skills and Enforces Tool-Call Limits Before Execution

Dexter prevents duplicate skill execution and monitors tool usage through in-memory checks in AgentToolExecutor and Scratchpad before any external API calls are made.

In the virattt/dexter repository, the agent loop applies two critical safety mechanisms to ensure efficient execution: skill deduplication and tool-call limit checking. These checks occur in AgentToolExecutor before any external tool is invoked, preventing redundant workflow runs and alerting the LLM when approaching usage thresholds.

Skill Deduplication Mechanism

Detection in AgentToolExecutor

The deduplication logic begins in src/agent/tool-executor.ts within the executeAll method. When iterating over the LLM's tool_calls, the executor specifically checks for the skill tool:

// src/agent/tool-executor.ts
if (toolName === 'skill') {
  const skillName = toolArgs.skill as string;
  if (ctx.scratchpad.hasExecutedSkill(skillName)) continue; // ← skip duplicate
}

Tracking in Scratchpad

The Scratchpad class in src/agent/scratchpad.ts maintains an in-memory JSON-L log of all executions. The hasExecutedSkill method searches for existing tool_result entries with type skill:

// src/agent/scratchpad.ts
hasExecutedSkill(skillName: string): boolean {
  return this.readEntries().some(
    e => e.type === 'tool_result' && e.toolName === 'skill' && e.args?.skill === skillName
  );
}

When a skill completes, addToolResult records the execution, ensuring subsequent calls are detected as duplicates and skipped before any external API request occurs.

Tool-Call Limit Enforcement

Query Extraction and Limit Checking

Before executing any tool, AgentToolExecutor.executeSingle extracts a representative query string from the tool arguments and consults the scratchpad:

const toolQuery = this.extractQueryFromArgs(toolArgs);
const limitCheck = ctx.scratchpad.canCallTool(toolName, toolQuery);

The canCallTool method in src/agent/scratchpad.ts evaluates three conditions against the configured maxCallsPerTool limit and similarityThreshold:

  1. Call count vs. maximum – warns if the count already reached the ceiling
  2. Query similarity – uses Jaccard similarity to detect near-duplicate queries (similarity ≥ threshold triggers warning)
  3. Approaching limit – warns when only one call remains

Advisory Warnings and Event Emission

Unlike hard limits, Dexter's restrictions are advisory. The canCallTool method always returns { allowed: true, warning?: string }, never blocking execution. When a warning exists, the executor emits a tool_limit event before the actual tool_start:

if (limitCheck.warning) {
  yield {
    type: 'tool_limit',
    tool: toolName,
    warning: limitCheck.warning,
    blocked: false,
  };
}

This event allows the LLM to adapt its strategy—such as switching tools or rephrasing queries—while the system continues to track usage via recordToolCall after successful execution.

Summary

  • Skill deduplication occurs in AgentToolExecutor.executeAll using Scratchpad.hasExecutedSkill to ensure each SKILL.md workflow runs only once per user query.
  • Tool-call limits are checked in AgentToolExecutor.executeSingle via Scratchpad.canCallTool, which tracks counts and query similarity using Jaccard comparison.
  • Both mechanisms operate before external API calls, using in-memory JSON-L logs stored in the scratchpad for fast, deterministic checks.
  • Limits are advisory only—execution proceeds but emits tool_limit events to inform the LLM of potential inefficiencies or near-duplicates.

Frequently Asked Questions

Does Dexter block execution when tool limits are reached?

No. Dexter treats tool limits as advisory rather than hard constraints. When Scratchpad.canCallTool detects that maxCallsPerTool has been reached or that a query is too similar to previous calls, it returns a warning but sets allowed: true. The executor emits a tool_limit event to notify the LLM, allowing it to adjust strategy while permitting the call to proceed.

How does Dexter detect duplicate skill invocations?

Dexter checks for duplicate skills using the hasExecutedSkill method in src/agent/scratchpad.ts. This method scans the in-memory JSON-L log for existing tool_result entries where toolName equals "skill" and the skill argument matches the requested workflow. If found, AgentToolExecutor.executeAll skips the duplicate call via a continue statement before any external execution occurs.

What similarity metric does Dexter use for query deduplication?

Dexter uses Jaccard similarity to compare the current tool query against previous queries for the same tool. The canCallTool method tokenizes the query strings and calculates the intersection over union ratio. If the similarity meets or exceeds the configured similarityThreshold, the method returns a warning indicating a near-duplicate query, helping prevent redundant API calls to search or data providers.

Where are skill and tool execution records stored?

All execution records are stored in the Scratchpad class within src/agent/scratchpad.ts. The scratchpad maintains an in-memory JSON-L (JSON Lines) log where each entry represents an event such as tool_result or tool_limit. This design ensures fast, deterministic lookups for deduplication and limit checking without requiring external database queries or persistent storage during the agent loop.

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 →