Documentation Index
Fetch the complete documentation index at: https://mintlify.com/sipeed/picoclaw/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Tools extend agent capabilities by providing interfaces to external systems, APIs, and operations. PicoClaw’s tool system is designed for safety, extensibility, and minimal overhead.
All tools implement the Tool interface (pkg/tools/types.go):
type Tool interface {
Name() string // Tool identifier
Description() string // Human-readable description
Parameters() map[string]any // JSON Schema for arguments
Execute(ctx context.Context, args map[string]any) *ToolResult
}
type ToolResult struct {
ForLLM string // Result sent to LLM
ForUser string // Result shown to user (if different)
Silent bool // If true, don't send ForUser to user
IsError bool // Indicates execution failure
Err error // Original error (if any)
Async bool // Tool running in background
Media []string // Media references (media://...)
}
Optional Interfaces
ContextualTool
Tools that need channel/chat context:
type ContextualTool interface {
Tool
SetContext(channel, chatID string)
}
Examples: message, spawn, cron
Tools that run in background:
type AsyncTool interface {
Tool
SetCallback(cb AsyncCallback)
}
type AsyncCallback func(ctx context.Context, result *ToolResult)
Examples: spawn
Central registry for all available tools (pkg/tools/registry.go):
type ToolRegistry struct {
tools map[string]Tool
mu sync.RWMutex
}
// Core methods
func (r *ToolRegistry) Register(tool Tool)
func (r *ToolRegistry) Get(name string) (Tool, bool)
func (r *ToolRegistry) Execute(ctx context.Context, name string, args map[string]any) *ToolResult
func (r *ToolRegistry) ToProviderDefs() []providers.ToolDefinition
Features:
- Thread-safe registration and execution
- Automatic conversion to LLM tool definitions
- Deterministic ordering (sorted alphabetically) for cache stability
- Context injection for contextual tools
- Async callback support
read_file
Read file contents.
Parameters:
{
"path": "./data/config.json"
}
Restrictions:
- Restricted to workspace if
restrict_to_workspace: true
- Respects
allow_read_paths patterns
- Symlink escape prevention
Implementation: pkg/tools/filesystem.go
write_file
Write content to file.
Parameters:
{
"path": "./output.txt",
"content": "Hello, world!"
}
Features:
- Atomic write with sync (flash-safe)
- Creates parent directories automatically
- Uses secure permissions (0o600)
Restrictions:
- Restricted to workspace if
restrict_to_workspace: true
- Respects
allow_write_paths patterns
list_dir
List directory contents.
Parameters:
Returns:
DIR: components
FILE: main.go
FILE: README.md
edit_file
Search and replace in files.
Parameters:
{
"path": "./config.json",
"old_text": "\"debug\": false",
"new_text": "\"debug\": true"
}
Implementation: pkg/tools/edit.go
append_file
Append content to file.
Parameters:
{
"path": "./log.txt",
"content": "New log entry\n"
}
exec
Execute shell commands with safety guards.
Parameters:
{
"command": "ls -la",
"working_dir": "./src" // Optional
}
Safety Features:
-
Dangerous Pattern Blocking:
rm -rf, del /f, rmdir /s
format, mkfs, diskpart
dd if=, writes to /dev/sd*
shutdown, reboot, poweroff
- Fork bombs
- Command substitution (
$(...), `...`)
- Pipe to shell (
| sh, | bash)
sudo, chmod, chown
- Package managers (
apt, yum, npm -g)
docker run/exec
git push/force
eval, source
-
Workspace Restriction:
- Absolute paths validated against workspace
- Path traversal blocked (
../)
- Safe paths allowed (
/dev/null, /dev/urandom, etc.)
-
Custom Patterns:
{
"tools": {
"exec": {
"enable_deny_patterns": true,
"custom_deny_patterns": ["\\bcurl\\b.*--upload-file"],
"custom_allow_patterns": ["^ls\\s"]
}
}
}
-
Timeout: Default 60s, configurable
Implementation: pkg/tools/shell.go
Security Notes:
- Even with
restrict_to_workspace: false, dangerous commands are blocked
- Use
custom_allow_patterns to override specific blocks
web_search
Search the web for information.
Parameters:
{
"query": "latest AI news",
"count": 5 // Optional, 1-10
}
Supported Providers (priority order):
- Perplexity (LLM-enhanced search)
- Brave Search (fast, high-quality)
- Tavily (AI-optimized)
- DuckDuckGo (free, no API key)
Configuration:
{
"tools": {
"web": {
"brave": {
"enabled": true,
"api_key": "BSA...",
"max_results": 5
},
"duckduckgo": {
"enabled": true,
"max_results": 5
}
}
}
}
Returns:
Results for: latest AI news
1. AI Breakthrough Announced
https://example.com/ai-news
Description of the article...
2. New Model Released
https://example.com/model
Details about the model...
Implementation: pkg/tools/web.go
web_fetch
Fetch and extract content from URLs.
Parameters:
{
"url": "https://example.com/article",
"maxChars": 10000 // Optional
}
Features:
- HTML to text conversion
- JSON formatting
- Redirect following (max 5)
- Size limit (default 10MB)
- Timeout: 60s
Returns:
{
"url": "https://example.com/article",
"status": 200,
"extractor": "text",
"truncated": false,
"length": 5432,
"text": "Article content..."
}
message
Send message to user on a chat channel.
Parameters:
{
"content": "Task completed successfully!",
"channel": "telegram", // Optional, uses current channel
"chat_id": "123456" // Optional, uses current chat
}
Use Cases:
- Subagent → User communication
- Multi-channel messaging
- Background task notifications
Behavior:
- Returns
Silent: true (user already received message)
- Tracks sends per round to prevent duplicates
Implementation: pkg/tools/message.go
cron
Schedule reminders, tasks, or commands.
Actions:
add
Create new scheduled task.
One-time reminder:
{
"action": "add",
"message": "Meeting in 10 minutes",
"at_seconds": 600 // 10 minutes from now
}
Recurring task:
{
"action": "add",
"message": "Daily standup reminder",
"every_seconds": 86400, // Daily
"deliver": true // Send directly to chat
}
Cron expression:
{
"action": "add",
"message": "Check server status",
"cron_expr": "0 9 * * *", // Daily at 9am
"deliver": false // Process through agent
}
Shell command:
{
"action": "add",
"message": "Check disk usage",
"command": "df -h",
"every_seconds": 3600 // Hourly
}
list
List all scheduled jobs.
remove
Delete a job.
{
"action": "remove",
"job_id": "abc123"
}
enable/disable
Toggle job execution.
{
"action": "disable",
"job_id": "abc123"
}
Job Execution:
deliver: true: Send message directly to channel
deliver: false: Process through agent (for complex tasks)
command: Execute shell command, report output
Implementation: pkg/tools/cron.go
spawn
Spawn subagent for background tasks.
Parameters:
{
"task": "Search for AI news and write a summary report",
"label": "AI News Research", // Optional, for display
"agent_id": "researcher" // Optional, target agent
}
Behavior:
- Creates independent subagent with fresh context
- Subagent has access to all tools (message, web, etc.)
- Non-blocking (main agent continues)
- Subagent communicates via
message tool
Permissions:
Controlled via subagents.allowlist config:
{
"agents": {
"agents": [
{
"id": "main",
"subagents": {
"allowlist": ["researcher", "coder"]
}
}
]
}
}
Use Cases:
- Long-running research tasks
- Web scraping and analysis
- Background monitoring
- Parallel task execution
Implementation: pkg/tools/spawn.go
i2c
I2C bus communication.
Parameters:
{
"bus": 1,
"address": 0x48,
"operation": "read",
"register": 0x00,
"length": 2
}
Availability: Linux only, returns error on other platforms
Implementation: pkg/tools/i2c.go
spi
SPI bus communication.
Parameters:
{
"device": "/dev/spidev0.0",
"data": [0x01, 0x02, 0x03]
}
Availability: Linux only
Implementation: pkg/tools/spi.go
find_skills
Search skill registries.
Parameters:
{
"query": "web scraping"
}
Implementation: pkg/tools/skills_search.go
install_skill
Install skill from registry.
Parameters:
{
"skill_id": "web-scraper",
"registry": "clawhub" // Optional
}
Implementation: pkg/tools/skills_install.go
Dynamic tools loaded from MCP (Model Context Protocol) servers.
Configuration:
{
"tools": {
"mcp": {
"enabled": true,
"servers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
}
}
}
}
}
Features:
- Auto-registers tools from connected MCP servers
- Tool names prefixed with server name (e.g.,
filesystem_read)
- Supports all MCP tool types
Implementation: pkg/tools/mcp_tool.go
1. LLM returns tool call
↓
2. AgentLoop extracts tool calls
↓
3. For each tool call:
│
├─ Lookup tool in registry
│
├─ If ContextualTool: SetContext(channel, chatID)
│
├─ If AsyncTool: SetCallback(asyncCallback)
│
├─ Execute tool with args
│
├─ If ForUser and not Silent: Send to user
│
├─ If Media: Send media to user
│
└─ Append ForLLM to messages
↓
4. Continue to next LLM iteration
Workspace Sandboxing
When restrict_to_workspace: true (default):
File Tools:
- All paths resolved relative to workspace
- Absolute paths validated
- Symlink escape prevention
- Path traversal blocked
Shell Tool:
- Absolute paths in commands validated
- Workspace boundary enforced
- Dangerous commands blocked
Example:
# Workspace: /home/user/.picoclaw/workspace
# Allowed:
./data/file.txt → /home/user/.picoclaw/workspace/data/file.txt
/home/user/.picoclaw/workspace/file.txt → OK
# Blocked:
../../../etc/passwd → Access denied (path traversal)
/etc/passwd → Access denied (outside workspace)
/home/user/documents/ → Access denied (outside workspace)
Path Whitelisting
Allow specific paths outside workspace:
{
"tools": {
"allow_read_paths": [
"^/etc/hosts$",
"^/proc/cpuinfo$"
],
"allow_write_paths": [
"^/tmp/picoclaw-.*"
]
}
}
Pattern Syntax: Regular expressions
Exec Safety Guards
Multi-layer protection for shell commands:
- Deny Patterns: Block dangerous commands
- Allow Patterns: Override blocks for specific cases
- Workspace Restriction: Path validation
- Timeout: Prevent infinite execution
Disable All Deny Patterns (dangerous):
{
"tools": {
"exec": {
"enable_deny_patterns": false
}
}
}
Standard Result
return &ToolResult{
ForLLM: "File written successfully",
ForUser: "Saved to output.txt",
}
Silent Result
return &ToolResult{
ForLLM: "Message sent",
Silent: true, // Don't send ForUser to user
}
Error Result
return &ToolResult{
ForLLM: "Failed to read file: file not found",
IsError: true,
Err: err,
}
Async Result
return &ToolResult{
ForLLM: "Subagent spawned, task running in background",
Async: true,
}
return &ToolResult{
ForLLM: "Screenshot captured",
Media: []string{"media://abc123"},
}
package customtools
import (
"context"
"github.com/sipeed/picoclaw/pkg/tools"
)
type GreetTool struct{}
func (t *GreetTool) Name() string {
return "greet"
}
func (t *GreetTool) Description() string {
return "Greet a person by name"
}
func (t *GreetTool) Parameters() map[string]any {
return map[string]any{
"type": "object",
"properties": map[string]any{
"name": map[string]any{
"type": "string",
"description": "Person's name",
},
},
"required": []string{"name"},
}
}
func (t *GreetTool) Execute(ctx context.Context, args map[string]any) *tools.ToolResult {
name, ok := args["name"].(string)
if !ok {
return tools.ErrorResult("name is required")
}
greeting := fmt.Sprintf("Hello, %s!", name)
return tools.NewToolResult(greeting)
}
Modify pkg/agent/loop.go:
func registerSharedTools(...) {
for _, agentID := range registry.ListAgentIDs() {
agent, _ := registry.GetAgent(agentID)
// ... existing tools ...
// Register custom tool
agent.Tools.Register(&customtools.GreetTool{})
}
}
3. Rebuild and Test
make build
./build/picoclaw agent -m "Greet Alice"
Best Practices
- Use lowercase with underscores:
read_file, web_search
- Be descriptive and action-oriented
- Avoid conflicts with existing tools
2. Parameter Validation
- Always validate required parameters
- Provide clear error messages
- Use JSON Schema for type safety
3. Error Handling
- Return
ErrorResult() for user-facing errors
- Include original error in
Err field
- Keep error messages concise and actionable
- Set appropriate timeouts
- Avoid blocking operations in Execute()
- Use Async pattern for long tasks
5. Security
- Validate all user inputs
- Sanitize file paths
- Use workspace restrictions
- Follow principle of least privilege