Docs24 Built-In Tools Reference
Tools Architecture
Backend & UI Integration

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.

01

Define the Custom Tool (`ToolDefinition`)

Specify schema, execution handler, annotations for safety pauses, and UI presentation metadata.

src/tools/deploy-staging.tstypescript
import { ToolDefinition, createAgent } from '@smoke-monkey/harness';
// 1. Define your custom backend tool
export const deployStagingTool: ToolDefinition = {
name: 'deploy_staging', // Unique snake_case identifier
description:
'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 UI
ctx.eventEmitter?.emit('tool.progress', {
toolCallId: ctx.toolCallId,
message: `Validating staging build for branch: ${branch}...`,
});
// 3. Execute external operation
const deployResult = await triggerStagingDeploy({ branch, dryRun: !!input.dryRun });
// 4. Return results: output for the LLM, data for the React UI
return {
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.

02

Register Custom Tools in the Backend Harness

Mix built-in tool groups (filesystem, terminal, git) with your custom tool definitions.

src/agent.tstypescript
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 tools
const 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 policy
permission: async (req) => {
// Non-destructive tools auto-pass; destructiveHint triggers this check
if (req.tool === 'deploy_staging') {
return 'ask'; // Pauses the loop until user approves in the UI
}
return 'allow';
},
});
03

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.

src/app/workbench/page.tsxtypescript
// Frontend: Next.js or React page using @smoke-monkey/ui
import { 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 runner
const { messages, events, sendPrompt, approvePermission } = useAgentStream({
endpoint: '/api/agent/stream',
permissionEndpoint: '/api/agent/permission',
});
return (
<div className="h-screen w-full bg-[#07090e]">
<ChatCanvas
messages={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 && (
<a
href={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 dialog
onApprovePermission={approvePermission}
/>
</div>
);
}
Reference

24 Built-In Tools Reference

Core tool suite included with smoke-monkey-harness with deterministic permission policies:

read_file
filesystem

Read file contents with byte and line slice bounds

Default Policy:allow
> read_file({ path: "src/index.ts", startLine: 1, endLine: 50 })
write_file
filesystem

Create new files or overwrite existing ones safely

Default Policy:ask
> write_file({ path: "src/config.ts", content: "export const PORT = 3000;" })
edit_file
filesystem

Search and replace exact target strings in code

Default Policy:ask
> edit_file({ path: "src/auth.ts", target: "verifySession()", replacement: "verifySessionV2()" })
line_edit
filesystem

Single line insert, delete, or replace operations

Default Policy:ask
> line_edit({ path: "package.json", line: 14, mode: "replace", content: " "version": "1.2.0"," })
replace_lines
filesystem

Multi-line block replacements by line ranges

Default Policy:ask
> replace_lines({ path: "src/api.ts", start: 20, end: 25, content: " return res.status(200).json(data);" })
apply_patch
filesystem

Apply unified diff patches directly to files

Default Policy:ask
> apply_patch({ path: "src/math.ts", patch: "@@ -1,3 +1,3 @@ -let x = 1; +let x = 2;" })
delete_file
filesystem

Delete file with safety check against project root

Default Policy:deny
> delete_file({ path: "temp.txt" })
list_directory
filesystem

List files and directories with depth controls

Default Policy:allow
> list_directory({ path: "src", recursive: false })
inspect
filesystem

Inspect metadata, file sizes, timestamps, and types

Default Policy:allow
> inspect({ path: "package.json" })
run_command
terminal

Run shell commands with timeout and output truncation

Default Policy:ask
> run_command({ command: "pnpm lint" })
run_test
terminal

Execute automated test suites and parse test exit codes

Default Policy:ask
> run_test({ command: "npm test" })
glob
search

Fast pattern matching across workspace files

Default Policy:allow
> glob({ pattern: "**/*.test.ts" })
grep
search

Ripgrep-style content search across directories

Default Policy:allow
> grep({ query: "createAgent", searchPath: "src" })
git_status
git

Get uncommitted changes, staged files, and branch status

Default Policy:allow
> git_status()
git_diff
git

View line-by-line unified git diffs for workspace

Default Policy:allow
> git_diff({ staged: false })
git_log
git

Inspect recent commit history and author messages

Default Policy:allow
> git_log({ count: 5 })
ask_user
agent

Pause execution and solicit interactive input from developer

Default Policy:allow
> ask_user({ question: "Which port should the server bind to?" })
context_manage
agent

Explicitly prune or compact active prompt messages

Default Policy:allow
> context_manage({ action: "compact" })
todo_write
agent

Persist plan tasks and track completion status

Default Policy:allow
> todo_write({ todos: ["Fix tests", "Deploy"] })
finish_task
agent

Declare goal completion with final status and summary

Default Policy:allow
> finish_task({ summary: "Refactored auth to JWT." })
list_skills
agent

Discover all available SKILL.md skills in workspace and global dirs

Default Policy:allow
> list_skills()
use_skill
agent

Load full SKILL.md workflow into context just-in-time

Default Policy:allow
> use_skill({ name: "frontend-ui-engineering" })