How the SecureDesign Tool System Works: AI-Powered File Manipulation Architecture

The SecureDesign tool system provides a secure, typed bridge between LLM agents and the local file system through specialized tools (read, write, edit, glob, grep, ls, multiedit, theme) that enforce workspace isolation via path validation in tool-utils.ts.

The SecureDesign extension (hbmartin/secure-design) implements a comprehensive tool system that allows AI agents to safely manipulate files within the VS Code workspace. This architecture ensures that all file operations remain sandboxed within the project boundary while providing rich metadata and standardized error handling for LLM consumption. Each tool is built around the ai.tool pattern with Zod schemas for type safety.

Core Architecture of the SecureDesign Tool System

Standardized Response Types

All tools in SecureDesign return a ToolResponse union type defined in src/tools/tool-utils.ts. The system distinguishes between ToolSuccessResponse and ToolErrorResponse, with errors normalized through handleToolError to include an error_type tag and concise messaging that the LLM can interpret.

// src/tools/tool-utils.ts
export interface ToolErrorResponse { … }
export interface ToolSuccessResponse { … }
export type ToolResponse = ToolSuccessResponse | ToolErrorResponse;

Path Security and Workspace Isolation

Every file system tool invokes validateWorkspacePath(filePath, context) before operations. This helper, implemented in src/tools/tool-utils.ts:

  • Rejects paths containing .. to prevent directory traversal attacks
  • Resolves relative paths against context.workingDirectory
  • Verifies the final absolute path starts with the workspace root

Violations return a ToolErrorResponse with error_type: "security", ensuring the AI cannot escape the sandbox.

Execution Context and Logging

Tools receive an ExecutionContext containing the workspace root and a VS Code logger:

export interface ExecutionContext {
    workingDirectory: string;   // workspace root
    logger: Logger;             // injected VS Code logger
}

Each operation logs via context.logger.info, creating an audit trail in the output panel (e.g., [read] Reading text file: src/main.ts (4.2 KB)).

Tool Definition Pattern

All tools follow a factory pattern using ai.tool:

export function createReadTool(context: ExecutionContext) {
    return tool({
        description: 'Read file content with optional line range',
        inputSchema: z.object({ filePath: z.string(), ... }),
        execute: async (args): Promise<ToolResponse> => {
            // 1. Validate path
            // 2. Resolve absolute location
            // 3. Perform operation
            // 4. Return standardized response
        },
    });
}

The Nine Core Tools in SecureDesign

The SecureDesign tool system provides nine specialized instruments for file manipulation and workspace inspection:

Tool Purpose Key File
read Return content (text, image, PDF, binary) with optional line-range src/tools/read-tool.ts
write Write arbitrary content to a file (creates parent dirs) src/tools/write-tool.ts
edit Single find-and-replace in a file src/tools/edit-tool.ts
multiedit Apply a sequence of edits atomically src/tools/multiedit-tool.ts
glob Find files/directories matching a glob pattern src/tools/glob-tool.ts
grep Search file contents with a regexp src/tools/grep-tool.ts
ls List directory entries with filtering src/tools/ls-tool.ts
theme Persist a CSS theme generated by the LLM src/tools/theme-tool.ts

Read Tool

Located in src/tools/read-tool.ts, this tool handles text, image, PDF, and binary files. It enforces a 10 MB size limit and supports line-range extraction via startLine and lineCount parameters. The detectFileType function categorizes content, while processTextFile handles truncation and processMediaFile prepares image/PDF data for the LLM.

Write Tool

Implemented in src/tools/write-tool.ts, this tool creates or overwrites files. The create_dirs parameter automatically generates parent directories using fs.mkdirSync. It validates that the target is not a directory before writing via fs.writeFileSync.

Edit Tool

Found in src/tools/edit-tool.ts, this performs single find-and-replace operations. It counts exact matches of old_string and validates against expected_replacements to prevent unintended changes. The replacement is atomic: read, modify, write back.

Multiedit Tool

Located in src/tools/multiedit-tool.ts, this applies a sequence of edits atomically. The fail_fast parameter controls whether to stop on the first error or continue processing remaining edits. It uses applySingleEdit internally and only writes the file if at least one edit succeeded.

Glob Tool

In src/tools/glob-tool.ts, this converts glob patterns to regex for recursive file discovery. It supports case_sensitive, include_dirs, show_hidden, and max_results filters. The findMatches function walks directories efficiently, sorting results by time when requested.

Grep Tool

Implemented in src/tools/grep-tool.ts, this searches file contents with regex. It skips common directories (like node_modules) via findFilesToSearch, streams files with searchInFile, and respects max_files and max_matches limits to prevent resource exhaustion.

Ls Tool

Found in src/tools/ls-tool.ts, this lists directory contents. It filters hidden files and ignore patterns, supports detailed view with file stats via fs.statSync, and sorts directories before files for logical presentation.

Theme Tool

Located in src/tools/theme-tool.ts, this persists CSS themes generated by the LLM. It validates the CSS file path, creates directories if needed via the create_dirs parameter, and returns theme metadata for the UI to consume.

Practical Usage Examples

The SecureDesign tool system accepts JSON payloads from the LLM and returns structured responses. Below are representative invocations:

Reading Source Code with Line Ranges

{
  "tool": "read",
  "arguments": {
    "filePath": "src/services/customAgentService.ts",
    "startLine": 10,
    "lineCount": 20,
    "encoding": "utf-8"
  }
}

Response:

{
  "success": true,
  "content": "[Content truncated: showing lines 10-29 of 250 total lines]\n\nimport …",
  "filePath": "src/services/customAgentService.ts",
  "fileType": "text",
  "mimeType": "text/typescript",
  "size": 8423,
  "lineCount": 250,
  "isTruncated": true,
  "linesShown": [10, 29]
}

Writing Configuration Files

{
  "tool": "write",
  "arguments": {
    "file_path": ".superdesign/config/theme.json",
    "content": "{ \"name\": \"dark\", \"primary\": \"#1e1e1e\" }",
    "create_dirs": true
  }
}

Response:

{
  "success": true,
  "file_path": ".superdesign/config/theme.json",
  "absolute_path": "/repo/.superdesign/config/theme.json",
  "is_new_file": true,
  "lines_written": 1,
  "bytes_written": 44
}

Batch Editing with Multiedit

{
  "tool": "multiedit",
  "arguments": {
    "file_path": "src/webview/components/CanvasView.tsx",
    "edits": [
      {
        "old_string": "const foo = 1;",
        "new_string": "const foo = 42;",
        "expected_replacements": 1
      },
      {
        "old_string": "background: white;",
        "new_string": "background: #111;",
        "expected_replacements": 1
      }
    ],
    "fail_fast": false
  }
}

Response:

{
  "success": true,
  "file_path": "src/webview/components/CanvasView.tsx",
  "edits_total": 2,
  "edits_successful": 2,
  "total_replacements": 2,
  "lines_total": 312,
  "bytes_total": 8456,
  "content_changed": true,
  "edit_results": [
    { "edit": {  }, "success": true, "occurrences": 1 },
    { "edit": {  }, "success": true, "occurrences": 1 }
  ]
}

Searching with Grep

{
  "tool": "grep",
  "arguments": {
    "pattern": "createTool\\(",
    "path": "src/tools",
    "include": "*.ts",
    "case_sensitive": false,
    "max_files": 200,
    "max_matches": 10
  }
}

Response:

{
  "success": true,
  "pattern": "createTool\\(",
  "search_path": "src/tools",
  "files_searched": 8,
  "files_with_matches": 3,
  "matches": [
    {
      "filePath": "read-tool.ts",
      "lineNumber": 17,
      "line": "export function createReadTool(context: ExecutionContext) {",
      "matchStart": 22,
      "matchEnd": 33
    }
  ],
  "total_matches": 6,
  "summary": "Found 6 match(es) for \"createTool\\(\" in 3 file(s) (searched 8/8 files)"
}

Key Source Files

File Role
src/tools/tool-utils.ts Shared validation, path resolution, and response helpers
src/tools/read-tool.ts Implements file reading with truncation and media handling
src/tools/write-tool.ts Writes content, creates directories, returns write metadata
src/tools/edit-tool.ts Single find-and-replace with occurrence validation
src/tools/multiedit-tool.ts Sequential batch edits with optional fail-fast
src/tools/glob-tool.ts Fast glob-to-regex conversion and recursive discovery
src/tools/grep-tool.ts Regex search across text files with resource limits
src/tools/ls-tool.ts Directory listing with hidden file filtering
src/tools/theme-tool.ts Persists CSS themes generated by the LLM
src/services/customAgentService.ts Registers all tools with the AI runtime and injects execution context

Summary

  • The SecureDesign tool system uses ai.tool with Zod schemas to register type-safe operations with the LLM runtime.
  • All file system tools enforce workspace isolation through validateWorkspacePath in src/tools/tool-utils.ts, preventing directory traversal attacks.
  • Tools return standardized ToolResponse objects containing rich metadata (file sizes, line counts, MIME types) for LLM consumption.
  • The nine core tools (read, write, edit, multiedit, glob, grep, ls, theme, and bash) cover the full spectrum of file manipulation, search, and UI theming needs.
  • Execution context provides workspace root resolution and audit logging, creating a transparent record of all AI file operations.

Frequently Asked Questions

How does SecureDesign prevent the AI from accessing files outside the workspace?

The validateWorkspacePath function in src/tools/tool-utils.ts rejects any path containing .. sequences and resolves all paths against the workspace root. It verifies that the final absolute path starts with context.workingDirectory, returning a security error type if the check fails, effectively sandboxing all file operations.

What is the difference between the edit and multiedit tools?

The edit tool performs a single find-and-replace operation with exact match counting and validation against expected_replacements. The multiedit tool accepts an array of edits and applies them sequentially to the same file, with the fail_fast parameter controlling whether to stop on first error or continue processing remaining edits.

How does the read tool handle different file types?

The read tool in src/tools/read-tool.ts uses detectFileType to categorize files as text, image, PDF, or binary. Text files support line-range extraction via processTextFile, images and PDFs are processed through processMediaFile for appropriate MIME type handling, and binary files return a placeholder response. All files are subject to a 10 MB size limit.

Where are the tools registered with the AI runtime?

The customAgentService.ts file in src/services/ instantiates all tool factories (like createReadTool, createWriteTool) with the ExecutionContext, then registers them with the LLM runtime using the ai.tool pattern. This service injects the workspace root and logger into each tool, ensuring consistent context across all file operations.

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 →