Mutating vs Read-Only Actions
Every tool declares one or more actions, each classified as either mutating or read-only. This classification drives the operator approval workflow and the read-only subagent wrapper.
Read-only actions have no external side effects (searches, reads, listing). Mutating actions create, modify, or delete resources (sending email, writing files, executing commands).
Tools with mutating actions
| Tool | Mutating actions |
|---|---|
| exec | execute |
| write_file | write |
| edit_file | edit |
| http | request |
| spawn | spawn |
| image_gen | generate |
| google_mail | send, reply, modify_labels |
| google_calendar | create_event, update_event, delete_event |
| google_tasks | create_task, update_task, delete_task, create_list, delete_list |
| github | create_issue, create_pr_review, trigger_workflow |
| todoist | create_task, update_task, close_task, delete_task, create_project |
| cron | add, remove, toggle, update |
| browser | navigate, click, type_text, fill, eval, screenshot |
| obsidian | create, append |
When operator approval is enabled, mutating actions pause for an Approve/Deny button click before executing. Read-only actions always execute immediately.
Parallel Tool Execution
When the LLM issues multiple tool calls in a single turn, oxicrab groups them into waves based on each tool's concurrency classification. Tools within the same wave execute concurrently; waves run in order.
| Concurrency | Behavior | Examples |
|---|---|---|
| ReadOnly | Runs concurrently with other ReadOnly tools in the same wave | read_file, list_dir, web_search, memory_search, weather |
| SideEffect | Runs sequentially (one at a time), but can share a wave with ReadOnly tools that complete first | write_file, exec, google_mail (send), cron (add) |
| Exclusive | Runs alone in its own wave, no other tools execute concurrently | browser (navigate/eval) |
Each tool declares its concurrency level via the concurrency field on ToolCapabilities. The wave scheduler groups compatible calls and executes them with tokio::join! for maximum throughput while preserving safety for tools with side effects.
read_file Core
Read the contents of a file at the given path. Includes path traversal protection to prevent access outside the workspace.
write_file Core
Write content to a file at the given path. Creates parent directories if needed. Saves versioned backups (up to 14) in ~/.oxicrab/backups/ before overwriting existing files.
edit_file Core
Edit a file by replacing old_text with new_text. The old_text must exist exactly in the file. Useful for surgical edits without rewriting entire files.
list_dir Core
List the contents of a directory. Returns file names, sizes, and types.
exec Core
Execute a shell command and return its output. Secured with configurable command allowlists, environment scrubbing, and output size limits. Dangerous patterns (rm -rf, raw device access, command substitution, netcat, hex decode piping) are blocked.
Security
- Shell AST analysis — pre-execution structural analysis via brush-parser detects subshells, command/process substitution, eval/source, interpreter inline execution (python -c, perl -e), dangerous pipe targets (| bash), function definitions, and dangerous device redirections. Runs before regex blocklist for defense-in-depth.
- Process sandbox — kernel-level sandboxing restricts filesystem access (read-only for system dirs, read-write for workspace + /tmp) and blocks network connections. On Linux, uses Landlock LSM (degrades gracefully on older kernels). On macOS, uses Seatbelt (
sandbox_init). No-op on other platforms. - Environment scrubbing — child processes inherit only safe variables (PATH, HOME, USER, LANG, TZ, TERM, RUST_LOG, TMPDIR). Secrets are never leaked.
- Output cap — combined stdout+stderr is truncated at 1 MB to prevent memory exhaustion.
- Workspace enforcement — when
restrictToWorkspaceis enabled, absolute paths in commands are validated against the workspace boundary.
Configuration
[tools]
restrictToWorkspace = true
[tools.exec]
timeout = 60
additionalAllowedCommands = ["python3", "node"]
# allowedCommands = ["ls", "grep", "git", "cargo"] # full override (replaces defaults)
[tools.exec.sandbox]
enabled = true
additionalReadPaths = ["/opt/data"]
additionalWritePaths = ["/home/user/output"]
blockNetwork = true
The default allowlist includes 70+ commands: file ops (ls, find, tree), text processing (grep, awk, sed, jq), dev tools (git, cargo, npm), and networking (curl, wget, dig). Use additionalAllowedCommands to add commands without replacing defaults, or allowedCommands for a full override. A startup warning is emitted when allowedCommands is empty (unrestricted shell access).
Set restrictToWorkspace: true to restrict filesystem access to the workspace directory.
The sandbox block controls kernel-level process sandboxing. On Linux, uses Landlock LSM. On macOS, uses Seatbelt (sandbox_init). Default read-only: /usr, /lib, /lib64, /bin, /sbin, /etc (plus /System, /Library, /opt/homebrew, /usr/local on macOS). Default read-write: workspace dir, /tmp, /var/tmp (plus /private/tmp, /private/var/folders on macOS). Use additionalReadPaths/additionalWritePaths to extend. Set blockNetwork: false to allow outbound connections from shell commands.
tmux Core
Manage persistent tmux shell sessions. Create long-running sessions, send commands, and read output. Ideal for processes that outlive a single tool call (dev servers, builds, etc.).
web_search Core
Search the web. Returns titles, URLs, and snippets. Uses Brave Search if an API key is configured, otherwise falls back to DuckDuckGo (no key required).
Optional: Brave Search API
- Get an API key from api.search.brave.com
- Set in config:
[tools.webSearch]
provider = "brave"
apiKey = "your-brave-search-api-key"
maxResults = 5
BRAVE_API_KEY environment variable.web_fetch Core
Fetch a URL and extract readable content. Converts HTML to markdown/text. Binary responses (images, PDFs) are saved to ~/.oxicrab/media/.
web_fetch_summary Core
Fetch a URL and return a small-model summary instead of the full extracted text. Use when the user wants "what does this page say" rather than a quote or specific extraction. Avoids dragging tens of KB of HTML into the main agent context. Adopted from IronClaw PR #2959.
Parameters
| Parameter | Description |
|---|---|
| url | Required. http(s) URL to fetch. |
| prompt | Optional framing for the summariser (e.g. "what's the API rate limit?"). Defaults to a generic key-points instruction. |
| max_input_chars | Cap on extracted page chars sent to the summariser. Default 12000; clamped to [1000, 60000]. |
| summary_max_tokens | Cap on summary length in tokens. Default 600; clamped to [64, 4096]. |
Model routing
The summariser uses the provider/model at agents.defaults.modelRouting.tasks.web_summary when set; otherwise the main provider. Configure to a cheap model (e.g. Haiku, Gemini Flash, Mistral small) to keep summary cost negligible.
[agents.defaults.modelRouting.tasks]
web_summary = "anthropic/claude-haiku-4-5"
Cache
Identical (url, prompt, summary_max_tokens) requests are cached for 15 minutes (in-memory LRU, 64 entries). Cache survives across LLM turns within a single process; clears at restart. Cache hits are flagged with a [cached] prefix in the output.
SSRF
The fetch step delegates to web_fetch's SSRF validator (no internal IPs, redirects bounded by MAX_REDIRECTS). The summariser only sees the extracted text, never the raw bytes.
http Core
Make HTTP requests (GET, POST, PUT, PATCH, DELETE). For REST APIs, webhooks, and external services. Supports custom headers and JSON bodies. Binary responses are saved to disk.
reddit Core
Browse Reddit. Get hot, new, or top posts from a subreddit, or search within a subreddit. Read-only, no authentication required.
rss Core
RSS/Atom feed reader with adaptive content recommendations. Subscribes to feeds, pre-filters articles using keyword matching and LinTS (Linear Thompson Sampling for binary rewards, trained on your accept/reject signals), and surfaces candidates for review. Uses an onboarding state machine to guide setup before scanning.
Actions
| Action | Description |
|---|---|
| onboard | Guided setup wizard. Detects the current onboarding step (needs_profile → needs_feeds → needs_calibration → complete) and returns the next instruction. Call this first to get started. |
| set_profile | Set or update your interest description (minimum 20 characters). Used to pre-filter articles before LinTS ranking. |
| add_feed | Subscribe to an RSS or Atom feed by URL. Validates and parses the feed on add, rejecting invalid or unreachable URLs. |
| remove_feed | Unsubscribe from a feed by ID. Cascades to all stored articles for that feed. |
| enable_feed | Re-enable a feed that was auto-disabled after consecutive failures. Resets failure counter. |
| list_feeds | List all subscribed feeds with fetch stats (last fetched, article counts, error counts). |
| scan | Fetch all feeds, pre-filter new articles by interest profile, rank candidates with the LinTS model, and return the top results for review. Call accept or reject on results to train the model. |
| get_articles | List articles with optional filters: status (new/accepted/rejected), feed_id. Supports limit and offset for pagination. |
| accept | Mark one or more articles as accepted. Accepts a single article_id or an array of IDs. Each accepted article is used as a positive training signal for the LinTS model. |
| reject | Mark one or more articles as rejected. Accepts a single article_id or an array of IDs. Each rejected article is used as a negative training signal for the LinTS model. |
| get_article_detail | Fetch the full page content for an article by ID. Downloads and extracts readable text from the article URL. |
| feed_stats | Analytics dashboard. Shows per-feed acceptance rates, overall LinTS model weights, total article counts, and current cron scan job status. |
| done | Mark the current review batch as complete. Commits all pending accept/reject decisions and updates the LinTS model. |
How it works
- Onboarding state machine — the tool enforces a setup sequence: set an interest profile, add at least one feed, calibrate the model by accepting/rejecting a few articles, then scanning is unlocked.
- LinTS ranking — Linear Thompson Sampling for binary rewards. Maintains a Bayesian posterior over feature weights (feed source, tags, profile keywords) updated via Sherman-Morrison rank-1 updates after each accept/reject. Covariance inflation each scan cycle prevents over-confidence.
- Cron integration — after onboarding completes, a recurring scan job is created automatically via
CronServiceso new articles are fetched on a schedule without user prompting. - Pre-filtering — before LinTS ranking, articles are checked against your interest description using keyword overlap to avoid scoring obviously irrelevant content.
Getting started
- Call
rss { action: "onboard" }— the tool walks you through setup. - Describe your interests:
rss { action: "set_profile", interests: "Rust, AI engineering, distributed systems" } - Add feeds from the suggestions (or your own):
rss { action: "add_feed", url: "https://this-week-in-rust.org/rss.xml" } - Fetch articles:
rss { action: "scan" } - Review at least 5 articles with
accept/rejectto calibrate the model. - Call
rss { action: "onboard" }again — setup completes and a cron job is created to scan every 6 hours automatically.
After setup, articles arrive via cron. Use get_articles to browse, feed_stats for analytics, and accept/reject to keep training the model.
Configuration
| Field | Default | Description |
|---|---|---|
enabled | true | Enable or disable the RSS tool |
scanTimeout | 15 | Per-feed HTTP fetch timeout in seconds |
maxArticlesPerFeed | 50 | Maximum new articles ingested per feed per scan cycle |
purgeDays | 90 | Delete articles older than this many days (all statuses) |
candidatesPerScan | 20 | Number of top-ranked articles returned to the LLM per scan |
covarianceInflation | 0.01 | Exploration parameter — inflates the model covariance each scan cycle to prevent over-fitting |
No external API key required. Behind the tool-rss cargo feature flag (default enabled). Feed data is stored in SQLite tables (rss_feeds, rss_articles, rss_article_tags, rss_profile, rss_model) in the workspace memory database.
spawn Core
Spawn a subagent to handle a task in the background. Tools are filtered by capability metadata — each tool declares its own subagent access level. Concurrency is limited by a semaphore (default: 5 concurrent subagents).
Subagent tool access
Each tool declares one of three subagent access levels via its capability metadata:
| Access Level | Behavior | Tools |
|---|---|---|
| Full | Passed through directly | read_file, write_file, edit_file, list_dir, exec, web_search, web_fetch |
| ReadOnly | Wrapped — only read-only actions exposed, mutating actions hidden from schema and blocked at execution | github, google_mail, google_calendar, google_tasks, cron, todoist, reddit, media, obsidian, browser, weather, memory_search, workspace |
| Denied | Not available | http, tmux, spawn, subagent_control, image_gen, stash_retrieve, tool_search, all MCP tools |
When the exfiltration guard is enabled, tools with network_outbound capability are additionally blocked unless listed in allowTools. This affects web_search, web_fetch (Full) and most ReadOnly tools that make network calls.
subagent_control Core
List running subagents, check capacity, or cancel a subagent by ID.
cron Core
Schedule recurring or one-shot tasks. Two job types: agent (default) processes the message as a full LLM turn with all tools; echo delivers the message directly to channels without invoking the LLM.
Schedule types
- cron_expr — Standard 5-field cron expression (e.g.
0 9 * * *) - every_seconds — Run every N seconds
- at_time — One-shot at an ISO 8601 datetime
- delay_seconds — One-shot relative delay (1s–1 year). Resolves to an absolute timestamp server-side, avoiding LLM timestamp miscalculation. Mutually exclusive with
at_time. - event_pattern — Regex pattern that triggers the job when an inbound message matches. Additional params:
event_channel,cooldown_secs,max_concurrent.
Actions
| Action | Description | Subagent |
|---|---|---|
| add | Create a new scheduled job | — |
| list | List all scheduled jobs | ✓ |
| remove | Delete a job by ID | — |
| run | Manually trigger a job | — |
| pause | Pause (disable) a job by ID | — |
| resume | Resume (re-enable) a paused job by ID | — |
| dlq_list | List dead letter queue entries (failed job executions). Optional dlq_status filter. | ✓ |
| dlq_replay | Retry a failed job by DLQ entry ID (dlq_id) | — |
| dlq_clear | Purge DLQ entries. Optional dlq_status filter. | — |
| traces | List recent execution traces. Optional job_id filter and limit (default 10). | ✓ |
| trace_detail | Show full execution trace by trace_id, including all events. | ✓ |
Optional limits: expires_at (auto-disable after datetime), max_runs (auto-disable after N executions).
Dead Letter Queue (DLQ): Failed cron job executions are automatically recorded in the DLQ with job ID, payload, error message, and timestamp. The DLQ auto-purges to keep the 100 most recent entries.
Execution Traces: Every cron job run is traced with structured events (started, tool calls, LLM requests/responses, errors, completion). Traces are stored in SQLite and auto-purged to keep the 200 most recent. Use traces to list and trace_detail to inspect individual runs.
finish_cron Core Deferred
Explicit completion signal for cron-driven agent runs. Adopted from IronClaw PR #2807. Without this tool, cron jobs end via the heuristic "LLM stopped calling tools" — which fails the moment a hallucination drives the model to claim success after a tool returned is_error=true. finish_cron flips the contract: the LLM signals completion explicitly, and the cron callback uses the supplied summary verbatim for the trace's Completed / Failed event.
Registered as deferred — invisible by default in interactive contexts (it's only meaningful inside scheduled jobs). Surfaces in the cron system prompt; discoverable via tool_search if explicitly requested.
Parameters
| Parameter | Description |
|---|---|
| summary | Required. One-paragraph description of what actually happened. Stored verbatim in the trace; capped at 1000 chars. |
| success | Default true. Set to false to mark the run as a failure — the trace transitions to the Failed state and a DLQ entry is written. |
| reason | Required when success = false. Short reason field surfaced in the trace and DLQ for the operator. |
Behavior
- Cron context: the call's metadata sideband (
__cron_finish) is lifted into the agent'sDirectResultmetadata and consumed by the cron callback ingateway_setup.rs. The trace is closed using your summary; ifsuccess=falsea DLQ entry is created. - Interactive context: harmless annotation — the tool returns the summary as the result content but no special handling fires.
memory_search Core
Search long-term memory. Recall user preferences, past conversations, and important facts. Uses SQLite FTS5 full-text search, with optional hybrid vector+keyword search via local ONNX embeddings.
Actions
| Action | Description | Subagent |
|---|---|---|
| search | Search memory by keyword or semantic query | ✓ |
| explain_last | Show provenance details of the most recent search | ✓ |
| list_sources | List all memory source keys with entry counts | ✓ |
| delete | Delete all entries for a source key (knowledge: entries are protected). Requires source_key parameter. | — |
Parameters
| Parameter | Description |
|---|---|
| query | Search query string. Required for search action. |
| source_key | Source key for the delete action. Required when action is delete. |
Memory configuration
[agents.defaults.memory]
embeddingsEnabled = true
embeddingsModel = "BAAI/bge-small-en-v1.5"
hybridWeight = 0.5
Hybrid vector+keyword search is enabled by default. The embeddings model is downloaded automatically on first use.
claim Core
Manage structured claims about the user, project, or world. Each claim has text, confidence (0.0–1.0), status (open/accepted/retracted/contradicted), and optional evidence pointers. Use this when you need to record a fact you'll re-quote later — the structure prevents low-confidence hedges from rounding to fact, and the lint action surfaces contradictions before they accumulate.
Pairs with the _Source: …_ trailer on memory_search results: citations cover retrieval grounding, claims cover ingestion grounding. Adopted from openclaw's claims/wiki_lint pattern.
Actions
| Action | Description | Subagent |
|---|---|---|
| add | Assert a claim with text + confidence + optional evidence pointers | — |
| list | List claims, optionally filtered by status (open/accepted/retracted/contradicted) | ✓ |
| get | Fetch one claim by id (with evidence). Bumps last_seen_ms — the re-observation signal that keeps the staleness lint accurate. | ✓ |
| lint | Run all three lint passes (contradictions, stale low-confidence, orphans) and return a markdown report | ✓ |
| update_status | Move a claim through the lifecycle: open → accepted | retracted | contradicted | — |
Confidence guidance
- Hedges ("I think", "maybe", "probably") → ≤ 0.5
- Default when unspecified → 0.6
- Explicit assertions → ≥ 0.8
- Cross-corroborated facts → 0.95+
Evidence pointer kinds
Each evidence pointer has a kind + value. The kind is freeform but conventional values are:
message:{channel}:{msg_id}e.g.telegram:msg-1234file: filesystem path e.g.ROADMAP.mdtool: tool name (with optional action) e.g.github/list_issues
Lint passes
- Contradiction: token-overlap (≥ 2 shared non-stopword tokens) AND opposite-polarity heuristic (negation markers like "not" / "never" / "dislike", or shared verb with different objects like "prefers Rust" vs "prefers Go"). Conservative — operator decides whether to mark either side
contradicted. - Stale low-confidence: confidence ≤ 0.4 AND
last_seen_ms> 90 days. Probably stale guesses; review and retract or re-observe. - Orphan: claims with zero evidence pointers. Either retract or assign a pointer.
query_activity Core
Search the activity journal — an append-only NDJSON timeline of every conversation turn (user/agent) at <workspace>/activity_journal.ndjson. Accepts free-form natural-language time expressions. Only registered when agents.defaults.activityJournal.enabled = true.
Actions
| Action | Description | Subagent |
|---|---|---|
| query | Return records within window_minutes of the resolved anchor time. Read-only. | ✓ |
Parameters
| Parameter | Description |
|---|---|
| time_expression | Required. NL anchor: 30 minutes ago, 2pm yesterday, this morning, three days ago, now, etc. |
| window_minutes | Half-window width; the search covers anchor ± window. Defaults to defaultWindowMinutes (60); clamped at maxWindowMinutes (1440). |
| session_only | When true, restrict results to the current session_key. |
Time expression grammar
Case-insensitive. Word numbers (one, two, ..., ten) are accepted in place of digits. The tool returns the resolved anchor in its response so the model can sanity-check the parser.
- Relative:
N minutes/hours/days/weeks/months ago - Clock + day:
3pm yesterday,9am today,14:30 tomorrow - Named part of day:
this morning(~09:00),yesterday afternoon(~14:00),today evening(~19:00),tonightalias not yet wired - Calendar:
yesterday,today(defaults to noon UTC),now
The journal is never auto-rotated — archive or delete the file manually if it grows beyond your taste.
workspace Core
Manage workspace files: list, search, organize, and clean up files in the workspace. Tracks files in a SQLite manifest with category, creation time, and access time for lifecycle management.
Actions
| Action | Description | Subagent |
|---|---|---|
| list | List tracked workspace files, optionally filtered by category | ✓ |
| search | Search workspace files by filename pattern | ✓ |
| info | Get detailed info about a specific tracked file | ✓ |
| tree | Show workspace directory tree | ✓ |
| move | Move a file to a different workspace category | — |
| delete | Delete a tracked workspace file | — |
| tag | Add or update tags on a tracked file | — |
| cleanup | Run workspace cleanup to remove expired files based on TTL config | — |
| send | Send a workspace file to the current conversation | — |
Pagination
The list action accepts limit (integer, default 50, max 200) and offset (integer, default 0) parameters for pagination.
File Organization
Files written via write_file to workspace category directories (code/, documents/, data/, images/, downloads/, temp/) are automatically tracked in the manifest. Categories are inferred from file extensions. Files are organized into date-based subdirectories ({category}/{YYYY-MM-DD}/{filename}).
Reserved directories (memory/, knowledge/, skills/, sessions/) are not managed by the workspace tool. TTL-based expiration is configured via agents.defaults.workspaceTtl.
stash_retrieve Core
Retrieve truncated tool output from the in-memory stash. When a tool produces output that exceeds the truncation limit, the full result is preserved in an LRU cache (32 entries, 32 MB). Use this tool to recover the truncated portion by key, with optional offset and limit for pagination.
Parameters
| Parameter | Description |
|---|---|
| key | The stash key (provided in truncation notices). Required. |
| offset | Byte offset to start reading from. Default: 0. |
| limit | Maximum bytes to return. Default: 50000. |
tool_search Core
Discover deferred and MCP tools by keyword search. Registered automatically when MCP servers are configured.
Parameters
| Parameter | Description |
|---|---|
| query | Keyword to search for among deferred tool names and descriptions. |
collections Core
Manage structured data collections with typed schemas. Create collections, then use per-collection tools (registered dynamically and discoverable via tool_search) for CRUD and aggregation operations.
Actions (collections tool)
| Action | Description | Subagent |
|---|---|---|
| create | Create a new collection with typed field schema | — |
| list | List all collections with record counts | ✓ |
| describe | Show full schema and metadata for a collection | ✓ |
| delete | Delete a collection and all its records | — |
| alter_schema | Add or remove fields from a collection schema | — |
Actions (per-collection data tools)
Each collection gets its own tool named after the collection (e.g. grocery_list). Discover it via tool_search.
| Action | Description | Subagent |
|---|---|---|
| add | Insert a record with typed data | — |
| query | Search records with filters, pagination | ✓ |
| update | Update a record by ID | — |
| delete | Delete a record by ID | — |
| count | Count records matching optional filters | ✓ |
| aggregate | Run count/sum/avg/min/max with optional group_by | ✓ |
Field types
text, number, bool, enum (with allowed values), date, datetime. Collection names must be alphanumeric + underscore, 1–64 chars, starting with a letter.
Dynamic registration
Per-collection data tools are registered as deferred tools at startup and dynamically when new collections are created. Auto-generated skill files provide schema context to the LLM. Data is stored in SQLite tables (collections, collection_records) in the workspace memory database.
google_mail Requires config
Interact with Gmail. Search, read, send, reply, list labels, and apply labels.
Actions
| Action | Description | Subagent |
|---|---|---|
| search | Search emails with Gmail query syntax | ✓ |
| read | Read a specific email by ID | ✓ |
| send | Send a new email | — |
| reply | Reply to an existing email thread | — |
| list_labels | List all Gmail labels | ✓ |
| label | Apply or remove labels from messages | — |
Setup
- Create a Google Cloud project at console.cloud.google.com
- Enable the Gmail API
- Create OAuth 2.0 credentials (Desktop application)
- Copy Client ID and Client Secret to config
- Run
./oxicrab auth googleto complete the OAuth flow
[tools.google]
clientId = "your-google-client-id"
clientSecret = "your-google-client-secret"
gmail = true
calendar = true
tasks = true
Each tool can be individually enabled/disabled. OAuth scopes are derived automatically from which tools are enabled. Tokens are stored in the workspace database and auto-refresh. Run oxicrab auth google to authenticate.
google_calendar Requires config
Interact with Google Calendar. List, create, update, and delete events across calendars.
Actions
| Action | Description | Subagent |
|---|---|---|
| list_events | List upcoming events | ✓ |
| get_event | Get details of a specific event | ✓ |
| create_event | Create a new calendar event | — |
| update_event | Update an existing event | — |
| delete_event | Delete an event | — |
| rsvp | Set attendance status (accepted, declined, tentative) for a calendar event | — |
| list_calendars | List available calendars | ✓ |
Parameters
Mutating actions (create_event, update_event, delete_event, rsvp) accept a send_updates parameter (string: "all", "externalOnly", or "none", default "all") to control who receives email notifications.
Setup
Uses the same Google OAuth config as google_mail. Set "calendar": true and enable the Google Calendar API in your Cloud project.
google_tasks Requires config
Interact with Google Tasks. Create, list, update, and complete tasks across task lists.
Actions
| Action | Description | Subagent |
|---|---|---|
| list_task_lists | List all task lists | ✓ |
| list_tasks | List tasks in a task list | ✓ |
| get_task | Get details of a specific task | ✓ |
| create_task | Create a new task | — |
| update_task | Update a task (title, notes, status, due date) | — |
| delete_task | Delete a task | — |
Pagination
list_task_lists and list_tasks automatically paginate through all results using Google's nextPageToken mechanism.
Setup
Uses the same Google OAuth config as google_mail. Set "tasks": true and enable the Google Tasks API in your Cloud project.
github Requires config
Interact with GitHub. Issues, pull requests, file content, PR reviews, CI/CD workflows, and notifications.
Actions
| Action | Description | Subagent |
|---|---|---|
| list_issues | List issues for a repository | ✓ |
| create_issue | Create a new issue | — |
| get_issue | Get issue details | ✓ |
| list_prs | List pull requests | ✓ |
| get_pr | Get pull request details | ✓ |
| get_pr_files | List files changed in a pull request | ✓ |
| create_pr_review | Submit a PR review (approve, request changes, or comment) | — |
| get_file_content | Get file content from a repository | ✓ |
| trigger_workflow | Trigger a GitHub Actions workflow | — |
| get_workflow_runs | List recent workflow runs | ✓ |
| notifications | List recent notifications | ✓ |
Subagents get read-only access (8 of 11 actions). Mutating actions (create_issue, create_pr_review, trigger_workflow) are hidden from the schema and blocked at execution.
Pagination
List actions support page (integer, default 1) and per_page (integer, default 10, max 100) parameters. Pagination applies to: list_issues, list_prs, get_workflow_runs, notifications.
Setup
- Create a Personal Access Token at github.com/settings/tokens
- Select scopes:
repo,read:user - Add to config:
[tools.github]
enabled = true
token = "ghp_your-github-token"
weather Requires config
Get current weather or forecast for a location. Uses the OpenWeatherMap API.
Setup
- Sign up at openweathermap.org/api (free tier available)
- Copy your API key
- Add to config:
[tools.weather]
enabled = true
apiKey = "your-openweathermap-api-key"
todoist Requires config
Manage Todoist tasks and projects.
Actions
| Action | Description | Subagent |
|---|---|---|
| list_tasks | List tasks (optionally filtered by project or filter query) | ✓ |
| get_task | Get detailed info for a single task | ✓ |
| create_task | Create a new task | — |
| update_task | Update a task's content, description, due date, priority, or labels | — |
| complete_task | Mark a task as complete | — |
| delete_task | Permanently delete a task | — |
| add_comment | Add a comment to a task | — |
| list_comments | List all comments on a task | ✓ |
| list_projects | List all projects | ✓ |
Setup
- Get your API token from todoist.com/app/settings/account
- Add to config:
[tools.todoist]
enabled = true
token = "your-todoist-api-token"
media Requires config
Manage movies and TV series via Radarr (movies) and Sonarr (TV).
Actions
| Action | Description | Subagent |
|---|---|---|
| search_movie | Search for movies by name | ✓ |
| add_movie | Add a movie by TMDB ID | — |
| get_movie / list_movies | View library movies | ✓ |
| search_series | Search for TV series by name | ✓ |
| add_series | Add a series by TVDB ID | — |
| get_series / list_series | View library series | ✓ |
| profiles | List quality profiles | ✓ |
| root_folders | List root folder paths | ✓ |
Setup
- Install Radarr and/or Sonarr
- Get API keys: Settings > General > API Key (in each app)
- Add to config:
[tools.media]
enabled = true
[tools.media.radarr]
url = "http://localhost:7878"
apiKey = "your-radarr-api-key"
[tools.media.sonarr]
url = "http://localhost:8989"
apiKey = "your-sonarr-api-key"
obsidian Requires config
Read, write, search, and list notes in an Obsidian vault via the Local REST API plugin.
Actions
| Action | Description | Subagent |
|---|---|---|
| read | Read a note by path | ✓ |
| write | Create or overwrite a note (auto-generates YAML frontmatter) | — |
| append | Append content to an existing note | — |
| search | Full-text search across the vault | ✓ |
| list | List notes, optionally filtered by folder | ✓ |
Pagination
The list (default 100, max 500) and search (default 50, max 500) actions accept limit and offset parameters for pagination.
Setup
- Install the Local REST API plugin in Obsidian (Community Plugins > search "Local REST API")
- Enable the plugin
- Copy the API key from the plugin settings
- Add to config:
[tools.obsidian]
enabled = true
apiUrl = "https://127.0.0.1:27124"
apiKey = "your-obsidian-local-rest-api-key"
vaultName = "MyVault"
syncInterval = 300
timeout = 15
syncInterval controls background cache refresh in seconds.browser Requires config
Control a headless browser for web automation via Chrome DevTools Protocol. Open pages, click elements, type text, take screenshots, and execute JavaScript.
Actions
| Action | Description | Subagent |
|---|---|---|
| open | Open a URL in the browser | — |
| click | Click an element by selector | — |
| type_text | Type text into a focused element | — |
| fill | Fill an input element by selector | — |
| screenshot | Take a screenshot of the current page | — |
| snapshot | Get the accessibility tree of the page | ✓ |
| eval | Execute JavaScript in the page context | — |
| get | Get page content as text or HTML | ✓ |
| scroll | Scroll the page by a given amount | — |
| wait | Wait for an element or a timeout | — |
| close | Close the browser session | — |
| navigate | Navigate back, forward, or reload | — |
Setup
- Install Chrome or Chromium:
sudo apt install chromium-browser - Enable in config:
[tools.browser]
enabled = true
headless = true
timeout = 30
Set headless: false to see the browser window. Set chromePath if Chrome is not in the default location. Screenshots are saved to ~/.oxicrab/media/.
image_gen Requires config
Generate images from text prompts. Supports OpenAI gpt-image-1 (DALL-E) and Google Imagen 3.
Setup
Uses API keys from the providers section. At least one provider key is required:
- OpenAI: Set
providers.openai.apiKey - Google: Set
providers.gemini.apiKey
[tools.imageGen]
enabled = true
defaultProvider = "openai"
MCP External
Connect external tool servers via the Model Context Protocol. Tools are auto-discovered at startup from child processes and registered as native tools with full middleware pipeline support. MCP tools cannot shadow built-in tools (rejected if they share a name with a built_in tool) and are not available to subagents. Null parameters are automatically stripped from tool calls before forwarding to MCP servers. Environment variable values containing CRLF characters are rejected at startup.
Configuration
[tools.mcp.servers.filesystem]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/documents"]
enabled = true
[tools.mcp.servers.git]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-git"]
enabled = true
[tools.mcp.servers.git.env]
GIT_DIR = "/path/to/repo"
[tools.mcp.servers.git.sandbox]
enabled = true
additionalReadPaths = ["/path/to/repo"]
blockNetwork = false
Server config fields
| Field | Description |
|---|---|
| command | The executable to run (e.g. npx, python, a binary path) |
| args | Command-line arguments |
| env | Environment variables passed to the child process |
| enabled | Set to false to skip without removing the config |
| trust | Trust level: "local" (default, full tool access), "verified" (requires approval per call), or "community" (read-only safe tools only) |
| sandbox | Process sandbox config for the server process. Same fields as tools.exec.sandbox: enabled (default true), additionalReadPaths, additionalWritePaths, blockNetwork (default true). Restricts the MCP server's filesystem and network access at the kernel level (Landlock on Linux, Seatbelt on macOS). |
Voice Transcription
Voice messages from channels are automatically transcribed to text. Not a tool itself, but a service that feeds into the agent. Supports dual backends with automatic fallback.
Local backend (whisper.cpp)
On-device inference. Requires ffmpeg and a GGML model file:
# Install ffmpeg
sudo apt install ffmpeg
# Download the model (~574 MB)
mkdir -p ~/.oxicrab/models
wget -O ~/.oxicrab/models/ggml-large-v3-turbo-q5_0.bin \
https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3-turbo-q5_0.bin
Cloud backend (Whisper API)
Uses Groq, OpenAI, or any OpenAI-compatible transcription endpoint. Groq offers free inference and is recommended.
Configuration
[voice.transcription]
enabled = true
localModelPath = "~/.oxicrab/models/ggml-large-v3-turbo-q5_0.bin"
preferLocal = true
threads = 4
apiKey = "your-groq-or-openai-api-key"
apiBase = "https://api.groq.com/openai/v1/audio/transcriptions"
model = "whisper-large-v3-turbo"
preferLocal: true (default) tries local first, falls back to cloud. Set to false to prefer cloud. Either backend alone is sufficient.