Skip to content

Tools

Tools are the actions the agent can take. Each tool is a Python class that inherits from BaseTool and declares: - name — used in tool schemas and audit log - description — what the AI sees - input_schema — JSON Schema for parameters (Anthropic-native format) - requires_confirmation — whether the agent must ask before executing - allowed_in_scheduled_tasks — whether the tool can be used by cron agents


Available tools

Tool Operations Confirmation Scheduled
bash execute shell commands yes no
brain capture, search, browse, stats no yes
browser fetch_page, screenshot, click, fill, select, press read: no / interactive: domain-based yes
caldav list_events, get_event, create_event, update_event, delete_event delete only yes
contacts list_contacts, search_contacts, create_contact, update_contact no yes
email list_emails, read_email, send_email, list_whitelist send only yes
filesystem read_file, list_directory, write_file, delete_file write/delete only yes
image_gen generate no yes
pushover send_notification no yes
telegram send_message no yes
web fetch_page, search no yes
webhook trigger_webhook, send_to_target no yes
whitelist list_domains, add_domain, remove_domain no yes

bash

Shell command execution. Admin only — never injected for non-admin users.

{
  "operation": "execute",
  "command": "ls -la /tmp"
}

Returns: stdout, stderr, exit code, execution time.

Why admin-only: Shell access is the most powerful capability in the system. Restricting it to admin users limits blast radius if the agent is manipulated.


brain

Interface to the 2nd Brain (PostgreSQL + pgvector). Requires the brain database to be configured.

Operation What it does
capture Save a memory or document with embedding
search Semantic similarity search
browse Retrieve recent entries
stats Count of entries, storage size

Per-user setting: brain_auto_approve — when enabled, the agent uses the brain tool proactively without being asked.


browser

Headless Chromium browser via Playwright. Useful for JavaScript-heavy pages where the web tool returns incomplete content.

Read operations (no confirmation): - fetch_page — navigate and extract page text - screenshot — capture PNG as base64

Interactive operations (confirmation required unless domain is trusted): - click — click an element by CSS selector - fill — type into an input field - select — choose a <select> option - press — press a keyboard key

Session state: Page state is kept across calls within the same session ID. Use fetch_page first to navigate, then interactive ops without a url to act on the current page.

Domain approval: Add domains to Settings → Whitelists → Browser Trusted Domains (or the user's Settings → Browser tab) to skip confirmation for interactive ops on those domains.

Requires: playwright install chromium in the container/environment.


caldav

CalDAV calendar integration. Connects to the URL and credentials configured per-user in Settings → CalDAV/CardDAV.

Operation What it does
list_events List events in a date range
get_event Get full event details by UID
create_event Create a new calendar event
update_event Update an existing event
delete_event Delete an event (requires confirmation)

Note: CalDAV must be configured per-user. There is no system-wide fallback.


contacts

CardDAV contacts integration. Uses the CardDAV URL configured per-user.

Operation What it does
list_contacts List all contacts
search_contacts Search by name or email
create_contact Create a new contact (vCard)
update_contact Update an existing contact

Implementation: Uses httpx directly with REPORT/PUT/DELETE HTTP methods (the caldav Python library does not support AddressBooks).


email

IMAP email reading and SMTP sending. Credentials configured per-user in Settings → Email Accounts.

Operation What it does
list_emails List inbox (or any folder), with optional unread-only filter
read_email Read a message by UID — body is sanitised before returning
send_email Send to one or more addresses (all must be in whitelist)
list_whitelist Return all approved recipient addresses

Security: send_email always requires confirmation in interactive sessions. Recipients must be in the email_whitelist table. Email bodies are sanitised with sanitize_external_content() before being returned to the agent.

Max body: 10,000 characters (6,000 when truncation is enabled in Security settings).


filesystem

Sandboxed file I/O. Access is restricted to directories in Settings → Whitelists → Filesystem.

Operation What it does
read_file Read a file's contents
list_directory List files and subdirectories
write_file Write text or binary content (requires confirmation)
delete_file Delete a file (requires confirmation)

Non-admin users: Get BoundFilesystemTool scoped to {base}/{username}/ instead of the global whitelist.

Path traversal prevention: Paths are resolved with os.path.realpath() before any containment check.


image_gen

Image generation via the configured provider. Returns base64-encoded PNG data URLs that the browser renders inline in the chat.

{
  "operation": "generate",
  "prompt": "A cozy home office with plants and warm lighting",
  "size": "1024x1024"
}

pushover

Push notifications to iOS/Android via Pushover.

{
  "operation": "send_notification",
  "message": "Daily summary: 3 new emails, calendar clear tomorrow",
  "title": "Jarvis",
  "priority": 0
}

Priorities: -2 (lowest), -1, 0 (normal), 1, 2 (emergency with retry).

Configuration: Admin sets pushover_app_token in Credentials. Each user sets their own pushover_user_key in Settings → Pushover.


telegram

Send messages to Telegram chats. Outbound only — the Telegram listener handles incoming messages separately.

{
  "operation": "send_message",
  "chat_id": "123456789",
  "message": "Weather alert: rain expected in 30 minutes"
}

Security: Chat IDs must be in telegram_whitelist for the calling user. Configured in Settings → Telegram.


web

Web search (DuckDuckGo) and page fetching. Does not require Playwright — pure HTTP.

Operation What it does
fetch_page Fetch a URL and extract text (strips scripts, styles, nav)
search DuckDuckGo search — returns titles, URLs, snippets

Tier 1 (whitelist): Always allowed. Seeded with: duckduckgo.com, wikipedia.org, weather.met.no, api.met.no, yr.no, timeanddate.com. Manage via Settings → Whitelists → Web.

Tier 2 (any domain): Only when the user's message suggests web research, or in a scheduled task that declared web access.

Content limit: 50 KB raw (20,000 chars when truncation is enabled).


webhook

Send HTTP requests to configured webhook targets or trigger inbound webhook endpoints.

Operation What it does
trigger_webhook Trigger a named inbound webhook endpoint
send_to_target POST JSON to a named outbound webhook target

Webhook targets are configured in Settings → Webhooks. Outbound webhooks can optionally include a secret header for authentication.


whitelist

Manage the Tier 1 web whitelist from within a conversation. Useful when accessing via Telegram (no browser access to the Settings UI).

Operation What it does
list_domains List all Tier 1 domains
add_domain Add a domain to the whitelist
remove_domain Remove a domain

Note: Modifies the global web_whitelist table. Changes are visible to all users immediately.


MCP proxy tools

MCP (Model Context Protocol) server tools are discovered dynamically. Each MCP tool is namespaced as mcp__{servername}__{toolname}. These are not listed here because they depend on your configured MCP servers.

Manage MCP servers in Settings → MCP Servers.


Adding a custom tool

  1. Create server/tools/my_tool.py inheriting BaseTool
  2. Implement execute() — never raise; return ToolResult
  3. Register in server/tools/__init__.py::build_registry()
class MyTool(BaseTool):
    name = "my_tool"
    description = "Does something useful."
    input_schema = {
        "type": "object",
        "properties": {
            "action": {"type": "string", "enum": ["do_thing"]},
        },
        "required": ["action"],
    }
    requires_confirmation = False

    async def execute(self, action: str, **kwargs) -> ToolResult:
        try:
            result = await some_async_operation()
            return ToolResult(success=True, data={"result": result})
        except Exception as e:
            return ToolResult(success=False, error=str(e))