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.toolwith Zod schemas to register type-safe operations with the LLM runtime. - All file system tools enforce workspace isolation through
validateWorkspacePathinsrc/tools/tool-utils.ts, preventing directory traversal attacks. - Tools return standardized
ToolResponseobjects 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →