Overview
BabyClaw provides a rich set of tools that enable the agent to interact with files, execute commands, search the web, manage schedules, and communicate across channels.
All tools follow the Vercel AI SDK tool format and are automatically available to the agent based on context and permissions.
Workspace File operations, reading/writing, directory listing
Shell Command execution with allowlist or approval
Web Search Brave Search API integration
Scheduler Create, list, and cancel scheduled tasks
Messaging Send messages to linked chats
Media Send images and files
State Persistent key-value storage
Working Memory Session-scoped ephemeral memory
Self Runtime status and management
File system operations within the workspace.
workspace_read
workspace_write
workspace_list
workspace_delete
workspace_move
Read text or JSON files: workspace_read ({
path: "config.json" ,
format: "json" // or "text"
})
// Returns:
{
ok : true ,
path : "config.json" ,
format : "json" ,
value : { /* parsed JSON */ }
}
Features:
Reads text files up to 10MB
Auto-parses JSON with validation
Bundled skills: ~bundled/skill-name/file.md
Path traversal protection
Write files with three modes: workspace_write ({
path: "data.json" ,
format: "json" ,
mode: "create" , // or "overwrite", "append"
value: { key: "value" }
})
workspace_write ({
path: "log.txt" ,
format: "text" ,
mode: "append" ,
content: "New log entry \n "
})
Modes:
create: Fail if file exists
overwrite: Replace existing file
append: Add to end (text only)
List directory contents with pagination: workspace_list ({
path: "src" ,
recursive: true ,
limit: 100 ,
cursor: null // for pagination
})
// Returns:
{
ok : true ,
path : "src" ,
items : [
{ path: "src/index.ts" , type: "file" , size: 1234 },
{ path: "src/utils" , type: "directory" , size: 4096 }
],
next_cursor : "src/utils/helpers.ts" // null if done
}
Delete files or directories: workspace_delete ({
path: "temp/old-data.json" ,
recursive: false
})
workspace_delete ({
path: "temp" ,
recursive: true // required for directories
})
Move or rename: workspace_move ({
from_path: "old-name.txt" ,
to_path: "new-name.txt" ,
overwrite: false
})
Source: packages/gateway/src/tools/workspace.ts
Execute shell commands with permission controls.
shell_exec
Basic Usage
Allowlist Mode
Full Access Mode
Approval Flow
shell_exec ({
command: "git status" ,
timeout_ms: 30000 ,
working_directory: "."
})
// Returns:
{
ok : true ,
exit_code : 0 ,
stdout : "On branch main \n Your branch is up to date..." ,
stderr : "" ,
timed_out : false ,
truncated : false
}
Configure allowed commands: {
"tools" : {
"shell" : {
"mode" : "allowlist" ,
"allowedCommands" : [
"git" , "node" , "npm" , "pnpm" , "curl" ,
"grep" , "find" , "cat" , "ls" , "systemctl"
]
}
}
}
Commands not in the list will be blocked or sent for approval. {
"tools" : {
"shell" : {
"mode" : "full-access"
}
}
}
Full access allows ANY command. Only use in trusted environments.
When a command needs approval:
Agent calls shell_exec({ command: "rm -rf temp" })
Tool detects rm not in allowlist
Sends approval prompt to Telegram:
Shell command requires approval.
Command: `rm -rf temp`
Not in allowlist: rm
[Approve] [Approve All] [Deny]
User clicks button
Tool proceeds or throws error
Approve All: Allows all commands for the current session
Features:
Pipes and command chaining: git log | grep "fix"
Environment variables: ENV=prod npm start
Output truncation at 5MB
Timeout protection (default 30s, max 120s)
Source: packages/gateway/src/tools/shell.ts
Integration with Brave Search API.
web_search
web_search ({
query: "Next.js 14 app router" ,
count: 5 ,
freshness: "pw" // past week
})
// Returns:
{
ok : true ,
result_count : 5 ,
results : [
{
title: "App Router - Next.js Documentation" ,
url: "https://nextjs.org/docs/app" ,
description: "The Next.js App Router introduces a new model for building applications..." ,
age: "2 weeks ago"
},
// ... more results
]
}
Parameters:
query: Search query string
count: Number of results (1-20, default 5)
freshness: Time filter
pd: past day
pw: past week
pm: past month
py: past year
Configuration:
{
"tools" : {
"webSearch" : {
"braveApiKey" : "${BRAVE_API_KEY}"
}
}
}
Get an API key: brave.com/search/api
Source: packages/gateway/src/tools/web-search.ts
Manage scheduled tasks (covered in detail in Scheduler ).
create_schedule
list_schedules
cancel_schedule
get_current_time
create_schedule ({
title: "Daily backup" ,
task: "Run backup script and verify completion" ,
job_type: "recurring" ,
cron_expression: "0 2 * * *" ,
target_chat_ref: null
})
list_schedules ({
include_inactive: false
})
cancel_schedule ({
query: "backup"
})
get_current_time ()
// Returns:
{
ok : true ,
iso : "2026-02-28T15:30:00Z" ,
unix : 1772272200 ,
timezone : "America/Los_Angeles"
}
Source: packages/gateway/src/tools/scheduler.ts
Send messages to linked chats (main session only).
send_message
send_message ({
recipient: "team-chat" , // alias from /link command
message: "Deployment complete. All systems operational."
})
// Returns:
{
ok : true ,
recipient : "team-chat" ,
message_id : "12345" ,
message : "Message sent to 'Team Chat' (telegram:-1001234567890)"
}
list_known_chats
list_known_chats ()
// Returns:
{
ok : true ,
chats : [
{
alias: "team-chat" ,
title: "Engineering Team" ,
platform: "telegram" ,
chat_id: "-1001234567890" ,
type: "supergroup" ,
is_main: false ,
is_linked: true
}
]
}
Source: packages/gateway/src/tools/messaging.ts
Messaging tools are only available in the main session to prevent cross-chat information leakage.
Send images and files to chats.
send_image
send_image ({
file_path: "workspace/charts/sales-report.png" ,
caption: "Q1 Sales Report"
})
send_file
send_file ({
file_path: "workspace/exports/data.csv" ,
file_type: "document" , // document, audio, video, animation
caption: "Customer data export"
})
Source: packages/gateway/src/tools/media.ts
Persistent key-value storage.
state_get
state_set
state_delete
state_list
state_get ({ key: "last_deploy_commit" })
// Returns:
{
ok : true ,
key : "last_deploy_commit" ,
value : "abc123def456" ,
found : true
}
state_set ({
key: "last_deploy_commit" ,
value: "def789ghi012"
})
state_delete ({ key: "last_deploy_commit" })
state_list ({
prefix: "deploy_" // optional filter
})
// Returns:
{
ok : true ,
items : [
{ key: "deploy_commit" , value: "abc123" },
{ key: "deploy_timestamp" , value: "1772272200" }
]
}
Use cases:
Store last operation results
Track counters or metrics
Cache external API data
Remember user preferences
Source: packages/gateway/src/tools/state.ts
Session-scoped ephemeral memory (covered in Memory ).
update_working_memory
update_working_memory ({
content: `
Current debugging session:
- tmux: debug-auth
- log file: /var/log/auth.log
- test user: [email protected] (id: 12345)
`
})
// Returns:
{
ok : true ,
bytes : 156 ,
message : "Working memory updated (156 bytes)"
}
Source: packages/gateway/src/tools/working-memory.ts
Install skills from ClawHub registry (covered in Skills ).
clawhub_install
clawhub_install ({
slug: "gcalcli-calendar" ,
version: "1.2.0" ,
force: false ,
skipSetup: false
})
Source: packages/gateway/src/tools/clawhub.ts
Manage the BabyClaw runtime itself.
self_status ()
// Returns:
{
ok : true ,
state : "running" ,
uptime_ms : 3600000 ,
config_path : "/workspace/babyclaw.json" ,
pid : 12345 ,
version : "1.0.0" ,
log_level : "info" ,
log_output : "/workspace/.babyclaw/logs/gateway.log" ,
scheduler_active : true ,
heartbeat_active : true
}
self_restart ({
confirm: true // required to prevent accidents
})
// Returns:
{
ok : true ,
message : "Restarting gateway. Process manager will bring it back."
}
Requires a process manager (systemd, pm2) to restart automatically.
Source: packages/gateway/src/tools/self.ts
Tools are dynamically assembled based on execution context:
function createUnifiedTools ({
toolDeps ,
executionContext ,
sourceText ,
createdByUserId ,
getActiveTurnCount ,
chatModel ,
channelSender ,
commandApprovalService ,
sessionKey
}) {
const tools = {
// Always available:
... createSchedulerTools ({ ... }),
... createSelfTools ({ ... }),
};
// Only if generic tools enabled:
if ( enableGenericTools ) {
Object . assign ( tools , {
... createStateTools ({ ... }),
... createWorkspaceTools ({ ... }),
... createShellTools ({ ... }),
... createWebSearchTools ({ ... }),
... createClawhubTools ({ ... })
});
}
// Only in main session:
if ( executionContext . isMainSession ) {
Object . assign ( tools , {
... createMessagingTools ({ ... }),
... createMediaTools ({ ... })
});
}
// Only in sessions (not scheduled tasks):
if ( sessionKey ) {
Object . assign ( tools , {
... createWorkingMemoryTools ({ ... })
});
}
return tools ;
}
Source: packages/gateway/src/tools/registry.ts:29-127
Tool Execution Context
Every tool receives context about the execution environment:
type ToolExecutionContext = {
workspaceRoot : string ;
bundledSkillsDir ?: string ;
botTimezone : string ;
platform : string ;
chatId ?: string ;
threadId ?: string ;
directMessagesTopicId ?: string ;
runSource : "user-message" | "scheduled-task" | "heartbeat" ;
isMainSession : boolean ;
};
Source: packages/gateway/src/utils/tool-context.ts
Error Handling
Tools use structured errors:
class ToolExecutionError extends Error {
code : string ;
message : string ;
hint ?: string ;
retryable ?: boolean ;
}
// Example:
throw new ToolExecutionError ({
code: "FILE_NOT_FOUND" ,
message: "Cannot read missing file: config.json" ,
hint: "Create the file first with workspace_write" ,
retryable: false
});
Errors are logged and returned to the agent with context.
Source: packages/gateway/src/tools/errors.ts
All tools log execution for observability:
await withToolLogging ({
context ,
toolName: "workspace_read" ,
defaultCode: "WORKSPACE_READ_FAILED" ,
input: { path , format },
action : async () => {
// Tool implementation
}
});
Logs include:
Tool name and input parameters
Execution duration
Success/failure status
Error details if failed
Source: packages/gateway/src/tools/errors.ts:39-79
Payload Limits
Tools enforce payload size limits to prevent context overflow:
const MAX_TOOL_PAYLOAD_BYTES = 10 * 1024 * 1024 ; // 10MB
ensurePayloadWithinLimit ({ value: fileContent , maxBytes: MAX_TOOL_PAYLOAD_BYTES });
ensureJsonWithinLimit ({ value: parsedJson , maxBytes: MAX_TOOL_PAYLOAD_BYTES });
If exceeded:
Text: Truncated with “[truncated]” marker
JSON: Error thrown
Lists: Paginated with cursor
Source: packages/gateway/src/utils/payload.ts
To disable generic tools (workspace, shell, etc.):
{
"tools" : {
"enableGenericTools" : false
}
}
This leaves only:
Scheduler tools
Self management tools
Use case: Locked-down agent that only does scheduled tasks.
Best Practices
Use state for persistence
Don’t rely on working memory for data that needs to survive sessions. Use state_set for persistent storage.
Allowlist common commands
Start with allowlist mode and add commands as needed: "allowedCommands" : [
"git" , "node" , "npm" , "curl" , "jq" ,
"docker" , "kubectl" , "systemctl"
]
Use cursor pagination for large directories: let cursor = null ;
do {
const result = await workspace_list ({ path: "." , limit: 100 , cursor });
// Process result.items
cursor = result . next_cursor ;
} while ( cursor );
Handle timeouts gracefully
Set appropriate timeouts for shell commands: shell_exec ({
command: "npm install" ,
timeout_ms: 120000 // 2 minutes for slow installs
})
Agent Loop How the agent uses tools
Skills Skills leverage tools
Scheduler Scheduler tool details
Configuration Tool configuration