Tools Architecture & Reference
Everything the agent loop can do is a tool. Smoke Monkey provides 24 production built-ins and allows you to write custom backend tools that stream real-time events and interactive cards directly into @smoke-monkey/ui.
How to Create Custom Tools (Backend & UI)
Custom tools require four simple steps: defining the ToolDefinition, handling execution & validation, registering it with the AgentLoop, and rendering the streaming card in @smoke-monkey/ui.
Define the Custom Tool (`ToolDefinition`)
Specify schema, execution handler, annotations for safety pauses, and UI presentation metadata.
import { ToolDefinition, createAgent } from '@smoke-monkey/harness';// 1. Define your custom backend toolexport const deployStagingTool: ToolDefinition = {name: 'deploy_staging', // Unique snake_case identifierdescription:'Deploys the compiled application to the staging environment. ' +'Call this only after tests have passed in the verify phase. ' +'Requires target git branch and environment confirmation.',inputSchema: {type: 'object',properties: {branch: { type: 'string', description: 'Git branch to deploy (e.g. main, staging)' },dryRun: { type: 'boolean', description: 'Simulate deployment without updating remote' },},required: ['branch'],},// Annotations drive loop behavior:annotations: {destructiveHint: true, // Triggers Pause 1 (Permission Gate) before execution},// Presentation defines how the tool renders in @smoke-monkey/ui:presentation: {icon: '🚀',label: 'Deploy Staging',family: 'run',tone: 'primary',},async execute(input, ctx) {// 1. Validate arguments (model input is coerced, not schema-enforced)const branch = typeof input.branch === 'string' ? input.branch.trim() : '';if (!branch) {return {output: 'Error: branch parameter is required, e.g. branch="staging".',isError: true, // Recoverable failure: loop demotes and retries};}if (ctx.abortSignal.aborted) {return { output: 'Deployment cancelled by user.', isError: true };}// 2. Stream real-time progress events to the UIctx.eventEmitter?.emit('tool.progress', {toolCallId: ctx.toolCallId,message: `Validating staging build for branch: ${branch}...`,});// 3. Execute external operationconst deployResult = await triggerStagingDeploy({ branch, dryRun: !!input.dryRun });// 4. Return results: output for the LLM, data for the React UIreturn {success: true,output: `Successfully deployed ${branch} to staging (URL: ${deployResult.url})`,summary: `Deployed ${branch} to ${deployResult.url}`,data: {url: deployResult.url,deploymentId: deployResult.id,durationMs: deployResult.durationMs,}, // Rides SSE events to @smoke-monkey/ui (never consumed by LLM)};},};
output (For the LLM)
The string returned in output is what the model reads to determine its next action. Keep it compact and informative. Never return empty strings or the model receives (no output).
data (For the React UI)
The object returned in data is streamed over SSE to @smoke-monkey/ui. It is never seen by the LLM, making it perfect for rich tables, preview URLs, charts, and interactive controls.
Register Custom Tools in the Backend Harness
Mix built-in tool groups (filesystem, terminal, git) with your custom tool definitions.
import { createAgent } from '@smoke-monkey/harness';import { deployStagingTool } from './tools/deploy-staging';import { queryDatabaseTool } from './tools/query-db';// Register built-in tool groups alongside your custom toolsconst agent = createAgent({workspacePath: process.cwd(),provider: 'nvidia',model: 'nvidia/nemotron-3-super-120b-a12b',// Mix built-in groups ('filesystem', 'terminal', 'git', 'search') with custom tools:tools: ['filesystem','terminal','git',deployStagingTool,queryDatabaseTool,],// Human-in-the-Loop permission policypermission: async (req) => {// Non-destructive tools auto-pass; destructiveHint triggers this checkif (req.tool === 'deploy_staging') {return 'ask'; // Pauses the loop until user approves in the UI}return 'allow';},});
Link to @smoke-monkey/ui (Streaming Cards & Permission Approval)
Render custom tool cards in the chat canvas and approve destructive permission requests from the browser.
// Frontend: Next.js or React page using @smoke-monkey/uiimport { ChatCanvas, ToolCard, useAgentStream } from '@smoke-monkey/ui';import '@smoke-monkey/ui/dist/styles.css';export default function AgentWorkbenchPage() {// Connects via Server-Sent Events (SSE) to the backend agent runnerconst { messages, events, sendPrompt, approvePermission } = useAgentStream({endpoint: '/api/agent/stream',permissionEndpoint: '/api/agent/permission',});return (<div className="h-screen w-full bg-[#07090e]"><ChatCanvasmessages={messages}events={events}onSend={sendPrompt}// Custom tool card renderer for custom tools like deploy_staging:renderCustomTool={(event) => {if (event.toolName === 'deploy_staging') {return (<div className="p-4 rounded-xl bg-[#0d121c] border border-cyan-500/30 space-y-2"><div className="flex items-center justify-between text-xs font-mono"><span className="text-cyan-400 font-bold">🚀 STAGING DEPLOYMENT</span><span className="text-emerald-400">STATUS: {event.status}</span></div>{event.data?.url && (<ahref={event.data.url}target="_blank"rel="noreferrer"className="text-xs text-mono-300 underline block">View Live Preview: {event.data.url}</a>)}</div>);}return null; // Fallback to native Smoke Monkey ToolCard}}// Interactive Human-in-the-Loop permission dialogonApprovePermission={approvePermission}/></div>);}
24 Built-In Tools Reference
Core tool suite included with smoke-monkey-harness with deterministic permission policies:
Read file contents with byte and line slice bounds
Create new files or overwrite existing ones safely
Search and replace exact target strings in code
Single line insert, delete, or replace operations
Multi-line block replacements by line ranges
Apply unified diff patches directly to files
Delete file with safety check against project root
List files and directories with depth controls
Inspect metadata, file sizes, timestamps, and types
Run shell commands with timeout and output truncation
Execute automated test suites and parse test exit codes
Fast pattern matching across workspace files
Ripgrep-style content search across directories
Get uncommitted changes, staged files, and branch status
View line-by-line unified git diffs for workspace
Inspect recent commit history and author messages
Pause execution and solicit interactive input from developer
Explicitly prune or compact active prompt messages
Persist plan tasks and track completion status
Declare goal completion with final status and summary
Discover all available SKILL.md skills in workspace and global dirs
Load full SKILL.md workflow into context just-in-time