Skip to content

Built-in tool reference ​

Source baseline commit: e1318eca83a40b9418d873ad85c31686ea6b57d0.

67 built-in tools, in registry order, grouped by definition module. Descriptions are the complete affordance-decorated output of get_tool_definitions(); core flags and input schemas come from the same registry. This is the static catalog, not a snapshot of a running installation: backend availability, permissions and disabled-tool policy can reduce visibility. Agent limits and model/effort fields are conditioned on configuration at catalog build time. No installed extensions or externally published tools are enumerated.

Dynamic native tools are outside this static catalog: computer_session, computer_observe, and computer_act are registered separately. See the computer-use operator reference for their workflow, capability limits and consent requirements. The count above does not describe their availability in a configured running installation.

Hyprland release_confirmed may mean only a drained guardian ledger and closed local resources without a compositor ACK; it is not compositor or receiver proof.

Core marks is_core (not a permission grant). Required means the property appears in its containing object's required list; nested rows do not make an optional parent required. Constraints show enums, defaults and numeric bounds.

Regenerate from the repository checkout with python scripts/docs/generate_tool_reference.py; add --check for a read-only drift check. The explicit source baseline is stable across docs-only commits; advance it when documenting a new source baseline.

system_files ​

Source: src/tools/defs/system_files.py.

run_command ​

Core: Yes

Runs a shell command on a managed host. Returns stdout/stderr; large output has a retained preview and get_tool_output(cursor=...) continuation without re-running. On failure: 'Command failed (exit N): output'. For multi-line scripts, use run_script. For multiple hosts, use run_command_multi. Host may be omitted only when an explicit requester or runtime default host exists.

[affordances: cost=medium risk=high latency=seconds] (requires: managed host alias configured; SSH key available for non-local hosts)

NameTypeRequiredDescription
hoststringNoHost alias from config (e.g. 'myserver', 'webhost')
commandstringYesShell command to execute (single line; for multi-line use run_script)

run_script ​

Core: Yes

Runs a multi-line script on a managed host via temp file. Handles heredocs, code blocks, and complex quoting. Large stdout/stderr has a retained preview and get_tool_output(cursor=...) continuation without re-running. On failure: 'Script failed (exit N): output'. Interpreters: bash (default), python3, python, sh, node, ruby, perl. For single commands, use run_command. Host may be omitted only when an explicit requester or runtime default host exists.

[affordances: cost=medium risk=high latency=seconds] (requires: managed host alias configured)

NameTypeRequiredDescription
hoststringNoHost alias from config
scriptstringYesFull script content to execute
interpreterstringNoInterpreter (default: bash)
filenamestringNoTemp filename (default: auto-generated)

run_command_multi ​

Core: Yes

Runs a command on multiple hosts in parallel. Returns per-host '### hostname\n```\noutput\n```'. Pass ['all'] for all hosts visible to the requester. For one host, use run_command.

[affordances: cost=high risk=high latency=seconds] (requires: managed host aliases configured)

NameTypeRequiredDescription
hostsarray<string>YesList of host aliases, or ['all'] for all hosts
commandstringYesShell command to execute on each host

read_file ​

Core: Yes

Returns a contiguous range from a file on a managed host. start_line is one-based; lines is a count (default 200, max 1000). Numbered output is the default. Set raw=true for byte-faithful UTF-8 text in a length-framed metadata envelope carrying the exact interval, truncation state, content byte count, and continuation cursor. Consume only the framed source content. Large ranges never use head+tail truncation. To edit files, use apply_patch.

[affordances: cost=medium risk=none latency=fast] (requires: path accessible by ssh user)

NameTypeRequiredDescription
hoststringYesHost alias from config
pathstringYesAbsolute path to the file
start_lineintegerNoOne-based first source line to read (default 1)
Constraints: {"minimum":1,"maximum":9007199254740991}
linesintegerNoNumber of lines to read (default 200, max 1000)
Constraints: {"minimum":1,"maximum":1000}
rawbooleanNoReturn byte-faithful UTF-8 text in a length-framed metadata envelope with explicit truncation/cursor state (default false)

apply_patch ​

Core: Yes

Applies a strict, context-checked patch to text files on a managed host. The host, absolute root directory, and patch text are all required; every file path inside the patch must be relative to root. Supports *** Add File, *** Update File (optionally *** Move to), and *** Delete File sections inside one *** Begin Patch / *** End Patch envelope. Update hunks start with @@; consecutive named @@ lines before a hunk body are ordered anchors, and the complete monotonic anchor-chain plus body must match exactly once. Every hunk must contain at least one + or - line. To narrow a location, chain named @@ anchors. A context-only bare @@ block immediately followed by another @@ is treated as locating context for that following edit hunk. Add File and Move to create missing parent directories beneath root; the complete envelope is validated before any write, and multi-file application rolls back files and patch-created directories on failure. Requires a Linux host with glibc 2.28 or newer and filesystem support for renameat2(RENAME_NOREPLACE); no unsafe fallback is used.

[affordances: cost=medium risk=high latency=seconds] (requires: root writable by ssh user)

NameTypeRequiredDescription
hoststringYesManaged host alias; no default is inferred
rootstringYesExisting absolute root directory for all relative patch paths
patch_textstringYesComplete *** Begin Patch / *** End Patch envelope using relative POSIX paths

media_scheduling ​

Source: src/tools/defs/media_scheduling.py.

purge_messages ​

Core: No

Deletes recent messages in the current Discord channel and resets conversation history. Default 100, max 500.

[affordances: cost=high risk=critical latency=seconds]

NameTypeRequiredDescription
countintegerNoNumber of messages to delete (default 100, max 500)

post_file ​

Core: No

Fetches a file from a managed host and posts it as a Discord attachment. Max 25MB. For generated content, use generate_file.

[affordances: cost=high risk=low latency=seconds]

NameTypeRequiredDescription
hoststringYesHost alias from config
pathstringYesAbsolute path to the file on the host
captionstringNoOptional message to include with the file

generate_file ​

Core: Yes

Creates a file (script, code, CSV, report, etc.) and posts it as a Discord attachment. For files on a host, use post_file.

[affordances: cost=medium risk=low latency=seconds]

NameTypeRequiredDescription
filenamestringYesFilename with extension (e.g. 'containers.csv', 'report.md', 'deploy.sh')
contentstringYesFile content to generate
captionstringNoOptional message to include with the file

schedule_task ​

Core: Yes

Schedules a recurring (cron), one-time (run_at), or webhook-triggered task. Use parse_time to convert natural language to run_at. Actions: 'reminder' = post message, 'check' = run_command check, 'digest' = infrastructure digest, 'workflow' = multi-step tool chain.

[affordances: cost=low risk=high latency=fast] (gotchas: workflow steps need populated tool_input with all required fields; run_at must be offset-aware ISO — use parse_time first for natural language)

NameTypeRequiredDescription
descriptionstringYesHuman-readable description (e.g. 'Daily disk check on server')
cronstringNoCron expression for recurring tasks (e.g. '0 9 * * *' = daily 9am). Omit for one-time.
cron_timezonestringNoIANA timezone for the cron expression (e.g. 'America/New_York'). The task fires on that timezone's wall clock across DST. Defaults to UTC.
run_atstringNoOffset-aware ISO datetime for one-time tasks (e.g. '2026-03-20T09:00:00Z'). Use parse_time to convert natural language. Omit for recurring.
triggerobjectNoWebhook trigger (AND logic). E.g. {"source": "github", "event": "push", "repo": "myproject"}.
trigger.sourcestringNoWebhook source to match
Constraints: {"enum":["gitea","grafana","generic","github","gitlab"]}
trigger.eventstringNoEvent type (e.g. 'push', 'pull_request', 'alert')
trigger.repostringNoRepository name substring (case-insensitive)
trigger.alert_namestringNoGrafana alert name substring (case-insensitive)
actionstringYes'reminder' = post message, 'check' = run_command check, 'digest' = infrastructure digest, 'workflow' = multi-step tool chain
Constraints: {"enum":["reminder","check","digest","workflow"]}
messagestringNoFor reminders: the message to post
tool_namestringNoTool to run for 'check' action (e.g. 'run_command')
tool_inputobjectNoParameters for the tool (for action='check'). Alternatively use the 'command' and 'host' shortcuts below for run_command.
report_formatstringNoOptional generic paginated Discord embed renderer for a check result. The command must emit the paginated_embed_v1 JSON contract.
Constraints: {"enum":["paginated_embed_v1"]}
commandstringNoShortcut: shell command to run (auto-builds tool_input for run_command). Use this instead of nesting inside tool_input.
hoststringNoShortcut: target host (default 'localhost'). Paired with 'command' for run_command checks.
stepsarray<object>NoWorkflow steps (sequential). Each step MUST include tool_input populated with that tool's parameters.
steps[].tool_namestringYesTool to run
steps[].tool_inputobjectYesREQUIRED — parameters for tool_name, e.g. {'host':'localhost','command':'ls'} for run_command
steps[].descriptionstringNoStep description
steps[].conditionstringNoRun if previous output contains this (! to negate)
steps[].on_failurestringNoDefault: abort
Constraints: {"enum":["abort","continue"]}

list_schedules ​

Core: Yes

Lists all scheduled tasks with IDs, descriptions, and next run times. To delete, use delete_schedule.

[affordances: cost=low risk=none latency=fast]

No input properties.

update_schedule ​

Core: Yes

Updates an existing schedule by ID. Only provided fields are changed. Can change description, cron, run_at, trigger, message, tool_name, tool_input, steps, channel_id, report_format, or paused. Changing timing (cron/run_at/trigger) replaces the previous timing mode. Set paused=true to suspend a schedule without deleting it; paused=false to resume.

[affordances: cost=low risk=high latency=fast]

NameTypeRequiredDescription
schedule_idstringYesSchedule ID to update (from list_schedules)
descriptionstringNoNew description
cronstringNoNew cron expression (replaces previous timing)
cron_timezonestringNoIANA timezone for the cron expression (e.g. 'America/New_York'). Defaults to UTC.
run_atstringNoNew offset-aware ISO datetime for one-time (replaces previous timing)
triggerobjectNoNew webhook trigger (replaces previous timing)
messagestringNoNew message (for reminder actions)
tool_namestringNoNew tool name (for check actions)
tool_inputobjectNoNew tool input parameters
report_formatstringNoGeneric paginated Discord embed renderer for check output; empty string disables structured rendering.
Constraints: {"enum":["paginated_embed_v1",""]}
stepsarray<object>NoNew workflow steps
steps[].tool_namestringYes—
steps[].tool_inputobjectNo—
steps[].descriptionstringNo—
channel_idstringNoNew channel ID for notifications
pausedbooleanNoPause (true) or resume (false) the schedule

delete_schedule ​

Core: Yes

Deletes a scheduled task by ID. To list schedules first, use list_schedules.

[affordances: cost=low risk=critical latency=fast]

NameTypeRequiredDescription
schedule_idstringYesSchedule ID to delete

parse_time ​

Core: Yes

Converts natural language time to ISO datetime (e.g. 'in 2 hours', 'tomorrow at 9am', 'next Friday at 3pm'). Uses bot timezone. For schedule_task's run_at parameter.

[affordances: cost=free risk=none latency=instant]

NameTypeRequiredDescription
expressionstringYesNatural language time (e.g. 'in 2 hours', 'tomorrow at 9am', 'next Friday at 3pm')

memory_skills ​

Source: src/tools/defs/memory_skills.py.

search_history ​

Core: Yes

Searches past conversation history and full channel message logs from all users. Uses keyword, semantic, and FTS matching. Returns '[date] (role): content'. For ingested docs, use search_knowledge. Large results preserve the original returned ranking and whole matches with showing/deferred counts; use get_tool_output(cursor=...) for deferred matches or an oversized match, without re-running search.

[affordances: cost=low risk=none latency=fast]

NameTypeRequiredDescription
querystringYesSearch query
limitintegerNoMax results (default 10)

memory_manage ​

Core: Yes

Persistent memory that survives across conversations. 'save'/'get'/'list'/'delete' notes. 'personal' = per-user, 'global' = shared with everyone.

[affordances: cost=low risk=low latency=fast]

NameTypeRequiredDescription
actionstringYes'save' a note, 'get' a single note by key, 'list' all notes, or 'delete' a note
Constraints: {"enum":["save","get","list","delete"]}
keystringNoShort identifier for the note (required for save/get/delete)
valuestringNoContent to remember (required for save)
scopestringNo'personal' (default, this user only) or 'global' (shared, visible to all)
Constraints: {"enum":["personal","global"]}

search_audit ​

Core: Yes

Searches audit log of tool executions. Returns '[date] tool_name by user (status, Nms)'. Filterable by tool, user, host, keyword, date, status, errors, duration.

[affordances: cost=low risk=none latency=fast]

NameTypeRequiredDescription
tool_namestringNoFilter by tool name
userstringNoFilter by user name or ID
hoststringNoFilter by host alias
keywordstringNoFree-text search across all fields
datestringNoFilter by date prefix (e.g. '2026-03-12')
statusstringNoFilter by status (e.g. 'error', 'success')
has_errorbooleanNoIf true, only return entries with non-empty error fields
min_duration_msintegerNoOnly return entries that took at least this many milliseconds
limitintegerNoMax results (default 20)

create_skill ​

Core: No

Creates a skill (custom tool) from Python code. Available immediately.
Define: async def execute(inp: dict, context: SkillContext) -> str

SkillContext methods (all async):
- run_on_host(alias, cmd), read_file(host, path)
- execute_tool(name, input), http_get(url), http_post(url, json=)
- post_message(text), post_file(data, filename, caption)
- search_knowledge(query), ingest_document(content, source), search_history(query)
- remember(key, value), recall(key), schedule_task(...), get_hosts(), log(msg)
See data/skills/*.template.

[affordances: risk=high]

NameTypeRequiredDescription
namestringYesSkill name (lowercase, underscores only, e.g. 'check_ssl_expiry')
codestringYesFull Python source code

edit_skill ​

Core: No

Replaces the code of an existing skill. Immediately reloaded after edit.

[affordances: risk=high]

NameTypeRequiredDescription
namestringYesSkill name to edit
codestringYesNew full Python source code

delete_skill ​

Core: No

Deletes a user-created skill. Immediately removed from available tools.

[affordances: cost=low risk=critical latency=fast]

NameTypeRequiredDescription
namestringYesSkill name to delete

list_skills ​

Core: No

Lists all user-created skills with descriptions, status, and input schemas.

[affordances: cost=low risk=none latency=fast]

No input properties.

enable_skill ​

Core: No

Re-enables a disabled skill.

[affordances: cost=low risk=low latency=fast]

NameTypeRequiredDescription
namestringYesName of the skill to enable

disable_skill ​

Core: No

Disables a skill without deleting it. File preserved.

[affordances: cost=low risk=low latency=fast]

NameTypeRequiredDescription
namestringYesName of the skill to disable

install_skill ​

Core: No

Installs a skill from a URL. Downloads the Python file, validates it, and loads it as a new tool.

[affordances: risk=high]

NameTypeRequiredDescription
urlstringYesURL to a Python skill file (http/https)

export_skill ​

Core: No

Exports a skill as a Python file attachment for sharing.

[affordances: cost=low risk=low latency=fast]

NameTypeRequiredDescription
namestringYesName of the skill to export

skill_status ​

Core: No

Shows detailed status for a skill: version, author, dependencies, config, execution stats, diagnostics.

[affordances: cost=low risk=none latency=fast]

NameTypeRequiredDescription
namestringYesName of the skill to inspect

invoke_skill ​

Core: No

Executes a skill by name, passing the given input dict. Use this to run a skill you just created or edited without waiting for tool-registry cache refresh. Returns the skill's string result. Equivalent to the skill appearing as a direct tool call, but works the same turn it's created. ALWAYS pass the skill's parameters via the 'input' object — top-level fields other than 'name' are ignored. If the skill declares required fields, omitting them will return an error.

[affordances: risk=high] (requires: skill must exist and be enabled) (gotchas: pass skill arguments under input, not at top level; use list_skills first if unsure about parameter names)

NameTypeRequiredDescription
namestringYesSkill name to invoke (must already be created and enabled)
inputobjectNoInput dict passed to the skill's execute() — matches the skill's declared input_schema

tasks_knowledge ​

Source: src/tools/defs/tasks_knowledge.py.

delegate_task ​

Core: Yes

Runs a multi-step task in the background, posting progress to Discord. Steps run sequentially with conditions (substring match, ! to negate), on_failure (abort/continue), store_as ({var.name}), {prev_output} substitution. IMPORTANT: each step using run_command MUST have tool_input with 'command' key. Example step: {"tool_name": "run_command", "description": "List files", "tool_input": {"command": "ls -la /tmp"}}. Track with list_tasks, stop with cancel_task.

[affordances: cost=high risk=high latency=unbounded] (gotchas: every run_command step needs tool_input.command; steps execute sequentially — use {prev_output} to chain results)

NameTypeRequiredDescription
descriptionstringYesTask description
stepsarray<object>YesOrdered tool calls to execute
steps[].tool_namestringYesTool to run
steps[].tool_inputobjectNoInput parameters
steps[].descriptionstringNoStep description
steps[].conditionstringNoRun if previous output contains this (prefix ! to negate)
steps[].on_failurestringNoDefault: abort
Constraints: {"enum":["abort","continue"]}
steps[].store_asstringNoSave output as named variable

list_tasks ​

Core: Yes

Lists background tasks. Without task_id: overview. With task_id: step-by-step details. See delegate_task, cancel_task.

[affordances: cost=low risk=none latency=fast]

NameTypeRequiredDescription
task_idstringNoTask ID for detailed results (omit for overview)

cancel_task ​

Core: Yes

Cancels a running background task. Get task IDs from list_tasks.

[affordances: cost=low risk=medium latency=fast]

NameTypeRequiredDescription
task_idstringYesTask ID to cancel (from list_tasks)

search_knowledge ​

Core: No

Searches ingested knowledge base (docs, runbooks, configs). Returns ranked '[source] (score: N) content'. Search here FIRST before web_search. To add, use ingest_document. To list, use list_knowledge. Large results preserve the original returned ranking and whole matches with showing/deferred counts; use get_tool_output(cursor=...) for deferred matches or an oversized match, without re-running search.

[affordances: cost=low risk=none latency=fast]

NameTypeRequiredDescription
querystringYesSearch query
limitintegerNoMax results (default 5)

ingest_document ​

Core: No

Ingests a document into the knowledge base (chunked + embedded for search). Re-ingesting same source replaces previous. For host files, use one complete, untruncated read_file raw=true response and ingest only its framed UTF-8 source content; exclude the metadata envelope, end marker, and continuation cursor; files too large for one raw read are not ingestible through this tool. Search with search_knowledge.

[affordances: cost=high risk=medium latency=seconds]

NameTypeRequiredDescription
sourcestringYesDocument identifier (e.g. 'ansible/roles/apache/README.md', 'server-runbook')
contentstringYesDocument text content

bulk_ingest_knowledge ​

Core: No

Bulk-import documents into the knowledge base. Accepts a list of items: directories or individual markdown/text files, PDF URLs, or web page URLs. Each item needs a type ('directory', 'file', 'pdf', or 'url') plus type-specific params.

[affordances: cost=high risk=medium latency=minutes]

NameTypeRequiredDescription
itemsarray<object>YesImport jobs. Each object needs 'type' plus: directory → 'path' (+ optional 'pattern', default '**/*.md'); file → 'path'; pdf → 'url' (+ optional 'source'); url → 'url' (+ optional 'source')
items[].typestringYes
Constraints: {"enum":["directory","file","pdf","url"]}
items[].pathstringNo—
items[].urlstringNo—
items[].sourcestringNo—
items[].patternstringNo—

list_knowledge ​

Core: No

Lists all knowledge base documents with source names and chunk counts. To search, use search_knowledge. To remove, use delete_knowledge.

[affordances: cost=low risk=none latency=fast]

No input properties.

delete_knowledge ​

Core: No

Removes a document from the knowledge base by source name. To list sources first, use list_knowledge.

[affordances: cost=low risk=critical latency=fast]

NameTypeRequiredDescription
sourcestringYesSource name to remove

browser_web ​

Source: src/tools/defs/browser_web.py.

browser_screenshot ​

Core: No

Takes a screenshot of a URL (renders JavaScript) and posts to Discord. Works on dashboards, SPAs, and dynamic pages unlike fetch_url. For text, use browser_read_page.

[affordances: cost=high risk=low latency=seconds] (requires: browser enabled; installed Chromium or reachable configured CDP endpoint)

NameTypeRequiredDescription
urlstringYesURL to screenshot
full_pagebooleanNoCapture full scrollable page (default false = viewport only)
wait_secondsintegerNoExtra wait after page load for dynamic content (default 0, max 10)

browser_read_page ​

Core: No

Reads a URL's text content (renders JavaScript). Returns 'Title (url)\n\ntext'. Works on SPAs/dynamic pages unlike fetch_url. Scope via CSS selector. For tables, use browser_read_table. For screenshots, use browser_screenshot. Large results have retained previews; use get_tool_output(cursor=...) without reloading the page.

[affordances: cost=high risk=low latency=seconds] (requires: browser enabled; installed Chromium or reachable configured CDP endpoint)

NameTypeRequiredDescription
urlstringYesURL to read
selectorstringNoCSS selector to scope extraction (e.g. '#main-content', '.results')
wait_secondsintegerNoExtra wait for dynamic content (default 0, max 10)
max_charsintegerNoLegacy direct-helper text limit (default 16000, max 32000); retained tool delivery uses the shared preview budget.

browser_read_table ​

Core: No

Extracts an HTML table from a URL as markdown (| col | col |). Renders JavaScript. For text, use browser_read_page. Large tables have retained previews; use get_tool_output(cursor=...) without reloading the page.

[affordances: cost=high risk=low latency=seconds] (requires: browser enabled; installed Chromium or reachable configured CDP endpoint)

NameTypeRequiredDescription
urlstringYesURL containing the table
table_indexintegerNoWhich table to extract (0-based, default 0 = first table)
wait_secondsintegerNoExtra wait for dynamic content (default 0, max 10)

browser_click ​

Core: No

Navigates to a URL and clicks an element by CSS selector. Returns a confirmation summary after clicking. To fill forms, use browser_fill. To read page content after clicking, follow up with browser_read_page.

[affordances: cost=high risk=high latency=seconds] (requires: browser enabled; installed Chromium or reachable configured CDP endpoint)

NameTypeRequiredDescription
urlstringYesURL to navigate to
selectorstringYesCSS selector to click (e.g. '#login-btn', 'button.submit')
wait_secondsintegerNoExtra wait before clicking (default 0, max 10)

browser_fill ​

Core: No

Navigates to a URL and fills a form field by CSS selector. Optionally submits by pressing Enter. To click buttons, use browser_click.

[affordances: cost=high risk=high latency=seconds] (requires: browser enabled; installed Chromium or reachable configured CDP endpoint)

NameTypeRequiredDescription
urlstringYesURL to navigate to
selectorstringYesCSS selector of the input (e.g. '#username', 'input[name=password]')
valuestringYesText to fill
submitbooleanNoPress Enter after filling (default false)

browser_evaluate ​

Core: No

Evaluates JavaScript on a URL and returns the result. For custom scraping or interaction. Large results have retained previews; use get_tool_output(cursor=...) without re-running the expression.

[affordances: cost=high risk=high latency=seconds] (requires: browser enabled; installed Chromium or reachable configured CDP endpoint)

NameTypeRequiredDescription
urlstringYesURL to navigate to
expressionstringYesJavaScript expression (e.g. 'document.title', 'document.querySelectorAll("a").length')
wait_secondsintegerNoExtra wait before evaluating (default 0, max 10)

Core: No

Searches the web via DuckDuckGo. Returns 'N. title\nurl\nsnippet' (max 10). For full content, use fetch_url or browser_read_page.

[affordances: cost=medium risk=none latency=seconds]

NameTypeRequiredDescription
querystringYesSearch query
max_resultsintegerNoMax results (default 5, max 10)

fetch_url ​

Core: No

Fetches a URL and returns text (HTML→readable text, JSON passed through). Static only — for JS-rendered pages use browser_read_page. Large results have retained previews; use get_tool_output(cursor=...) without fetching again.

[affordances: cost=medium risk=none latency=seconds]

NameTypeRequiredDescription
urlstringYesURL to fetch

set_permission ​

Core: No

Sets a Discord user's permission tier. Admin-only. Tiers: admin (full access), user (read-only), guest (chat only).

[affordances: cost=low risk=high latency=fast]

NameTypeRequiredDescription
user_idstringYesDiscord user ID (numeric string, e.g. '123456789012345678')
tierstringYesPermission tier
Constraints: {"enum":["admin","user","guest"]}

analyze_pdf ​

Core: No

Extracts text from a PDF (URL or host:path). Returns markdown text; large results have retained previews and get_tool_output(cursor=...) continuation. For image-heavy PDFs, use browser_screenshot.

[affordances: cost=high risk=none latency=seconds]

NameTypeRequiredDescription
urlstringNoURL to fetch PDF from
hoststringNoHost alias for file-based PDF
pathstringNoFile path on host
pagesstringNoPage range, e.g. '1-5' or '3' (default: all)

channel_process_loops ​

Source: src/tools/defs/channel_process_loops.py.

read_channel ​

Core: No

Reads recent messages from the CURRENT Discord channel into your context. Returns channel history from ALL users and bots. Do NOT pass channel_id — omit it to read the channel the message came from. The returned messages are for YOUR eyes only — do NOT paste or echo them. Read, understand, then respond with your own summary, analysis, or action.

[affordances: cost=medium risk=none latency=fast]

NameTypeRequiredDescription
limitintegerNoNumber of messages to read (default 10, max 100)
channel_idstringNoNumeric channel ID. Omit to use current channel (recommended).

add_reaction ​

Core: No

Adds an emoji reaction to a message. Unicode emoji or custom format (<:name:id>).

[affordances: cost=medium risk=low latency=fast]

NameTypeRequiredDescription
message_idstringYesDiscord message ID to react to
emojistringYesEmoji to react with

create_poll ​

Core: No

Creates a Discord native poll in the current channel. Max 10 options. Duration in hours (default 24, max 168/7 days).

[affordances: cost=medium risk=low latency=fast]

NameTypeRequiredDescription
questionstringYesThe poll question
optionsarray<string>YesList of answer options (max 10)
duration_hoursintegerNoPoll duration in hours (default 24)
multiplebooleanNoAllow multiple selections (default false)

manage_process ​

Core: Yes

Manages local or remote background processes (start/poll/write/kill/list). Start spawns a detached command on the selected managed host and returns PID. Poll defaults to newest 50 lines, with emitted/retained/shown-byte and capture-loss metadata. Offset 0, blank, null, or omitted means the newest-lines status view, not a page read. Use the preview's generation:0 cursor to read from the beginning, or offset >= 1 for a byte range. Use the returned cursor and limit (default 4000, 4-8000 UTF-8 bytes) for repeatable retained-output pages; follow cursor until truncated=false. A non-empty cursor takes precedence over offset. Reads never consume another reader's output. Local and remote capture retain at most 4 MiB. Output stays read-only for 24 hours after exit; access is rechecked on every read. Write sends stdin; Kill verifies process-group termination. Max 20 concurrent, auto-killed after 1hr. When monitoring a long-running process (build, test suite, download), poll with wait_seconds (60 is a good default) — one call waits server-side until exit or the deadline, instead of many rapid polls. Keep long-job output observable: stream stdout/stderr, or use bash with pipefail and tee to also save a log. Redirection alone hides progress. Silence is not proof of a hang; bounded slow polling is allowed until the original one-hour process deadline, not indefinitely.

[affordances: cost=low risk=high latency=unbounded]

NameTypeRequiredDescription
actionstringYesAction to perform
Constraints: {"enum":["start","poll","write","kill","list"]}
hoststringNoHost alias (required for start)
commandstringNoShell command to run (required for start)
pidintegerNoProcess ID (required for poll, write, kill)
input_textstringNoText to send to stdin (required for write)
wait_secondsnumberNoPoll only: wait up to this many seconds (0-120) for the process to exit before reporting. 0 (default) reports immediately. Exit ends the wait early.
cursorstringNoPoll only: opaque job-generation output cursor; a non-empty cursor takes precedence over offset; blank means no cursor. Use the preview's generation:0 cursor to read from the beginning.
offsetintegerNoPoll only: retained-output UTF-8 byte offset (>= 1 for an explicit range). 0, blank, null, or omitted means the newest-lines status view; ignored when cursor is non-empty. Read from the beginning with the preview's generation:0 cursor.
Constraints: {"minimum":0}
limitintegerNoPoll page maximum UTF-8 bytes (default 4000); complete envelope may reduce the page.
Constraints: {"minimum":4,"maximum":8000}

manage_list ​

Core: Yes

Manages named lists (grocery, todo, shopping, etc.). Created on first add. 'personal' = private, 'shared' = visible to all. Supports mark_done/mark_undone.

[affordances: cost=low risk=low latency=fast]

NameTypeRequiredDescription
actionstringYes'list_all' shows all lists. Other actions operate on a specific list_name.
Constraints: {"enum":["add","remove","show","clear","mark_done","mark_undone","list_all"]}
list_namestringNoList name (e.g. 'grocery', 'todo', 'hardware store'). Required for all actions except list_all.
itemsarray<string>NoItem(s) to add, remove, or mark.
ownerstringNo'personal' = this user only, 'shared' = everyone (default). Only applies on first add (list creation).
Constraints: {"enum":["personal","shared"]}

analyze_image ​

Core: No

Analyzes an image from URL or host path. Returns text description. For web page screenshots, use browser_screenshot.

[affordances: cost=high risk=none latency=seconds]

NameTypeRequiredDescription
urlstringNoURL of the image
hoststringNoHost alias for file-based image
pathstringNoFile path on host
promptstringNoWhat to look for (default: describe the image)

start_loop ​

Core: No

Starts an autonomous loop. Each iteration triggers a full LLM reasoning cycle with all tools. Use for monitoring, game playing, event watching, periodic updates. Returns loop ID. Check with list_loops, stop with stop_loop.

[affordances: cost=very_high risk=high latency=unbounded]

NameTypeRequiredDescription
goalstringYesGoal for each iteration (be specific). E.g. 'Monitor disk usage, warn if above 80%' or 'Watch /tmp/events.log, summarize new entries'
interval_secondsintegerNoSeconds between iterations (default: 60, min: 10)
modestringNonotify = report always, act = act + report, silent = act, report only if notable
Constraints: {"enum":["notify","act","silent"]}
stop_conditionstringNoAuto-stop condition, e.g. 'when disk below 50%' or 'after 5 iterations'. Evaluated each cycle.
max_iterationsintegerNoHard max iterations before auto-stop (default: 50)

stop_loop ​

Core: No

Stops an autonomous loop by ID. Use 'all' to stop all loops. To list loops first, use list_loops.

[affordances: cost=low risk=medium latency=fast]

NameTypeRequiredDescription
loop_idstringYesLoop ID to stop, or 'all'

list_loops ​

Core: No

Lists all autonomous loops with status, iterations, and last activity. To create, use start_loop. To stop, use stop_loop.

[affordances: cost=low risk=none latency=fast]

No input properties.

agents ​

Source: src/tools/defs/agents.py.

spawn_agent ​

Core: No

Spawns an autonomous agent for a sub-task. Runs silently in background with isolated context; it may spawn its own sub-agents up to the nesting limit. Results are NOT posted to Discord — use wait_for_agents to collect results, then deliver a cohesive summary yourself. Max 5/channel; lifetime limit for NEW agents: 14400 seconds. Budget warnings injected near iteration limit. Set 'model' to run THIS agent on a specific Codex model — gpt-6-astra (flagship: deepest reasoning for the hardest, highest-stakes work; the most expensive GPT-6 tier; rejects effort 'none'), gpt-6-sol (balanced default: complex coding and agentic work at near-Astra reliability, and cheaper than gpt-5.6-terra), gpt-6-luna (cheapest GPT-6: focused, high-volume work with a clear goal; raise effort before escalating), gpt-5.6-sol (previous generation; gpt-6-sol is stronger and cheaper, so use it only as a fallback), gpt-5.6-terra (previous-generation mid tier; costs more than gpt-6-sol, so use it only as a fallback), gpt-5.6-luna (previous-generation small tier; gpt-6-luna is stronger and cheaper, so use it only as a fallback); match the tier to the task. A model selection is required. Set 'reasoning_effort' (none/low/medium/high/xhigh/max) for THIS agent — higher is more thorough but slower/costlier. Omit to use the configured agent effort.

[affordances: cost=very_high risk=high latency=unbounded] (requires: agent tool enabled)

NameTypeRequiredDescription
labelstringYesShort name (e.g. 'disk-audit')
goalstringYesFull task description for the agent
modelstringYesRequired Codex model for this agent. gpt-6-astra = flagship: deepest reasoning for the hardest, highest-stakes work; the most expensive GPT-6 tier; rejects effort 'none'; gpt-6-sol = balanced default: complex coding and agentic work at near-Astra reliability, and cheaper than gpt-5.6-terra; gpt-6-luna = cheapest GPT-6: focused, high-volume work with a clear goal; raise effort before escalating; gpt-5.6-sol = previous generation; gpt-6-sol is stronger and cheaper, so use it only as a fallback; gpt-5.6-terra = previous-generation mid tier; costs more than gpt-6-sol, so use it only as a fallback; gpt-5.6-luna = previous-generation small tier; gpt-6-luna is stronger and cheaper, so use it only as a fallback. Choose a model explicitly.
reasoning_effortstringNoOptional reasoning effort for this agent — higher is more thorough but slower/costlier. Omit to inherit the configured agent effort.
Constraints: {"enum":["none","low","medium","high","xhigh","max"]}
parent_idstringNoParent agent ID for nested spawns (optional, set automatically when spawning from within an agent)

send_to_agent ​

Core: No

Queues a message to a running agent for its next safe boundary. Wakes an agent waiting for children; does not cancel ordinary tools. Acknowledges queued, not consumed. Use for instructions, data, or corrections.

[affordances: cost=low risk=high latency=fast] (requires: target agent exists and is running)

NameTypeRequiredDescription
agent_idstringYesAgent ID (from spawn_agent)
messagestringYesMessage text to inject

list_agents ​

Core: No

Lists all agents with status, iteration count, and runtime. Shows running, completed, failed, and timed-out agents.

[affordances: cost=low risk=none latency=fast]

No input properties.

kill_agent ​

Core: No

Terminates a running agent immediately. Agent status set to 'killed'.

[affordances: cost=low risk=critical latency=fast]

NameTypeRequiredDescription
agent_idstringYesAgent ID to kill

get_agent_results ​

Core: No

Returns the final results of a completed/failed agent. Returns result pages with UTF-8 byte length, preview, truncation flag and continuation cursor, tools used, iteration count, and runtime. Repeat with cursor for complete output. Retained after live registry cleanup. Returns 'still running' if active.

[affordances: cost=low risk=none latency=fast]

NameTypeRequiredDescription
agent_idstringYesAgent ID
cursorstringNoContinuation from previous page
limitintegerNoUTF-8 byte ceiling per page (default 4000, max 8000); may be smaller to fit serialized delivery budget
Constraints: {"minimum":4,"maximum":8000}

wait_for_agents ​

Core: No

Waits for one or more agents to complete. Essential for fan-out (spawn N agents → wait → collect results) and pipeline (spawn A → wait → spawn B with A's output) coordination patterns. Returns a snapshot for every requested agent once all finish or timeout. Returns status snapshots with up to 800 UTF-8 bytes of result preview per agent, possibly less under the aggregate budget. Use get_agent_results and follow its cursor until truncated=false for complete output. Inside an agent, a parent message interrupts the wait; children continue.

[affordances: cost=low risk=none latency=minutes]

NameTypeRequiredDescription
agent_idsarray<string>YesAgent IDs to wait for
timeoutnumberNoMax seconds to wait (default 300)

integrations_email ​

Source: src/tools/defs/integrations_email.py.

http_probe ​

Core: No

Probe an HTTP/HTTPS endpoint with timing, retries, and full response capture. Useful for API debugging, health checks, and latency measurement. Runs curl on a managed host (or locally if host omitted). Returns response headers, body, status code, and timing breakdown (DNS, connect, TLS, TTFB, total).

[affordances: cost=medium risk=high latency=seconds]

NameTypeRequiredDescription
urlstringYesURL to probe (http or https)
hoststringNoHost alias to run curl from (omit to run locally)
methodstringNoHTTP method (default GET)
Constraints: {"enum":["GET","POST","PUT","DELETE","PATCH","HEAD","OPTIONS"]}
headersobjectNoRequest headers as key-value pairs (e.g. {"Authorization": "Bearer tok"})
bodystringNoRequest body string (for POST/PUT/PATCH). Max 50KB.
timeoutintegerNoRequest timeout in seconds (default 30, max 120)
follow_redirectsbooleanNoFollow HTTP redirects (default true)
verify_sslbooleanNoVerify SSL certificates (default true)
retriesintegerNoNumber of retries on failure (default 0, max 5)
retry_delayintegerNoDelay between retries in seconds (default 1, max 30)

generate_image ​

Core: No

Generates an image from a text prompt with the native OpenAI image backend and posts it to Discord. Output dimensions and aspect ratio are selected by the provider.

[affordances: cost=very_high risk=low latency=minutes] (requires: Codex provider active; native image generation enabled; usable credentials)

NameTypeRequiredDescription
promptstringYesText description of the image to generate

validate_action ​

Core: Yes

Runs a bundle of validation checks after an operational change (deploy, restart, config push, migration) to confirm the system is actually healthy — not just that the preceding commands returned exit 0. Checks run concurrently on managed hosts. Never blocks; verdict is informational. Verdict: 'pass' (all OK), 'degraded' (only warn-severity failures), 'fail' (≥1 critical failure), 'error' (every check errored — likely config issue). ALWAYS call this automatically after deploys, service restarts, container replacements, compose up/down, config writes to running services, firewall changes, DNS updates, schema migrations — do not wait to be asked.

Check types:
  http            target=URL, expected=status code or list (default [200,201,204,301,302,307,308])
  port            target='host:port' or just 'port' (implies 127.0.0.1)
  service         target=systemd unit name, expected='active' or list of states
  process         target=pgrep pattern
  log_absent      target='unit=NAME:PATTERN' or plain regex — passes if pattern NOT found
  log_present     same target format — passes if pattern IS found
  command         target=shell command, compare='exit_zero'|'exit_nonzero'|'contains'|'not_contains'|'equals'|'regex_match'

Each check: {type, target, severity?, host?, expected?, compare?, window_seconds?, timeout_seconds?, name?}.
Severity 'critical' (default), 'warn', or 'info'. Only critical failures flip verdict to 'fail'.

[affordances: cost=high risk=high latency=seconds] (requires: validation checks reference reachable hosts) (gotchas: command checks execute real commands)

NameTypeRequiredDescription
bundle_namestringNoShort label for this bundle (e.g. 'after_nginx_restart')
default_hoststringNoHost alias used for any check without an explicit 'host'. Uses the requester's explicit default-host policy when omitted.
grace_secondsintegerNoOptional wait before running checks (0-60), to let services settle.
max_parallelintegerNoMax concurrent checks within this bundle (default 12, cap 25). Use a lower value when validating against a resource-constrained host.
formatstringNoOutput format: 'summary' (human-readable, default) or 'json' (full structured report).
checksarray<object>YesList of validation checks (max 25).
checks[].typestringYeshttp|port|service|process|log_absent|log_present|command
checks[].targetstringYes—
checks[].expectedanyNoType-specific expectation (int, string, list)
checks[].severitystringNocritical (default) | warn | info
checks[].hoststringNo—
checks[].comparestringNo—
checks[].window_secondsintegerNo—
checks[].timeout_secondsintegerNo—
checks[].namestringNo—

email_send ​

Core: No

Send an email via SMTP. Returns the sent message ID and recipient list. Supports plain-text body, CC/BCC, reply-to, and file attachments from allowed directories.

[affordances: cost=medium risk=high latency=seconds] (requires: email.enabled; SMTP credentials configured)

NameTypeRequiredDescription
toarray<string>YesRecipient email addresses
subjectstringYesEmail subject line
bodystringYesPlain-text email body
ccarray<string>NoCC recipients (optional)
bccarray<string>NoBCC recipients (optional)
reply_tostringNoReply-To address (optional)
attachmentsarray<string>NoFile paths to attach (must be within allowed_attachment_dirs)

Core: No

Search email via IMAP. On Gmail, uses native Gmail search syntax (e.g. 'from:alice newer_than:7d has:attachment subject:invoice'). On other providers, uses standard IMAP SEARCH criteria (e.g. 'FROM "alice" SINCE 01-Jun-2026'). Returns message summaries.

[affordances: cost=high risk=none latency=seconds] (requires: email.enabled; IMAP credentials configured)

NameTypeRequiredDescription
querystringYesSearch query
folderstringNoMailbox folder (default: INBOX)
limitintegerNoMax results to return (default: 20)

email_read ​

Core: No

Read a specific email by UID. Returns full headers, plain-text body (truncated to configured limit), and attachment metadata. Use email_search or email_list_recent to find UIDs first.

[affordances: cost=medium risk=none latency=seconds] (requires: email.enabled; IMAP credentials configured)

NameTypeRequiredDescription
uidstringYesMessage UID from search/list results
folderstringNoMailbox folder (default: INBOX)

email_list_recent ​

Core: No

List the most recent emails in a folder. Returns summaries with sender, subject, date, size, and flags. Use email_read for full content.

[affordances: cost=high risk=none latency=seconds] (requires: email.enabled; IMAP credentials configured)

NameTypeRequiredDescription
folderstringNoMailbox folder (default: INBOX)
limitintegerNoNumber of recent messages (default: 10)

output_delivery ​

Source: src/tools/defs/output_delivery.py.

get_tool_output ​

Core: No

Read retained tool evidence without re-running its tool. Follow cursor until truncated=false. Pages are contiguous head-only; initial labelled tails are context only. Evidence expires 24 hours after capture (fixed TTL), with per-result/global quotas. Original caller, channel, tool permission and host scope are rechecked; a cursor is not permission. Binary attachments return data_base64 pages with byte offsets, MIME and SHA-256; decode each page and concatenate bytes in order. No audio understanding. For process spools use the returned manage_process retrieval arguments instead.

[affordances: cost=low risk=none latency=fast]

NameTypeRequiredDescription
cursorstringYesExact cursor returned by tool output delivery.
limitintegerNoMaximum text/base64 characters; envelope budget may yield fewer.
Constraints: {"minimum":4,"maximum":8000,"default":4000}

Released under the MIT License.