Creating Tools
Extend Kibo with your own custom tools. Tools are Python functions decorated with @needle.tool.
Architecture Overview
agent/tools/
├── __init__.py # Registry - imports all tools
├── system.py # Notifications, battery, clipboard
├── hardware.py # Device info, screenshots, power
├── communication.py # Clipboard operations
├── media.py # Camera, TTS, audio recording
├── network.py # WiFi, internet, downloads
├── apps.py # App launching, file listing
├── sysadmin.py # Processes, files, packages
└── advanced.py # Remote terminal, media streamingTool Anatomy
Every tool follows the same pattern:
import needle
from agent.runner import some_function
@needle.tool
def my_tool(param1: str, param2: int = 10) -> str:
"""Description of what the tool does.
This docstring is used by the AI agent to
understand when and how to use this tool.
"""
print(f"[Tool] my_tool('{param1}', {param2})")
# Call runner function for OS-specific logic
result = some_function(param1, param2)
return f"Result: {result}"Key Rules
Every tool must be decorated with this. It registers the function with the AI agent.
The AI uses your docstring to decide when to call the tool. Write clearly.
Required. The AI uses them to understand expected inputs.
All tools must return a string. The AI processes the result.
Use print(f"[Tool] ...") for debugging output.
Return error messages as strings. Don't raise exceptions.
Step-by-Step Guide
Step 1: Create the tool file
Create a new file in agent/tools/:
# agent/tools/calculator.pyStep 2: Implement the tool
import needle
@needle.tool
def calculate(expression: str) -> str:
"""Evaluate a mathematical expression.
Examples: "2 + 2", "10 * 5", "100 / 7"
"""
print(f"[Tool] calculate('{expression}')")
try:
result = eval(expression, {"__builtins__": {}}, {})
return f"Result: {result}"
except Exception as e:
return f"Error: {e}"Step 3: Register the tool
Add the import and append to ALL_TOOLS in agent/tools/__init__.py:
# agent/tools/__init__.py
from agent.tools.calculator import calculate
ALL_TOOLS = [
# ... existing tools ...
calculate,
]Step 4: Test it
Start Kibo and try your new tool:
./run.sh
> calculate 2 + 2
Result: 4Using Runner Functions
For OS-specific logic, delegate to runner modules. This keeps your tools cross-platform:
import needle
from agent.runner import notify
@needle.tool
def remind_me(message: str, minutes: int = 5) -> str:
"""Set a reminder that shows a notification."""
print(f"[Tool] remind_me('{message}', {minutes})")
# Implementation...
return notify("Reminder", message)Runner functions in agent/runner/ handle platform differences (Linux, macOS, Windows).
Real Examples from Kibo
@needle.toolShow a brief toast popup. Takes a message string.
@needle.toolCapture screen. Returns file path to the screenshot.
@needle.toolCheck battery level. Returns percentage and charging status.
@needle.toolSet system volume. Takes an integer 0-100.
Tips
Each tool should do one thing well. Break complex operations into multiple tools.
Make common parameters required and optional ones have defaults. The AI handles this better.
Include examples in the docstring. The AI uses them to understand usage patterns.
Try your tool with both Needle 2 and FunctionGemma to ensure compatibility.