hoot tools reference
Complete reference for all 52 public web hoot tools from web/lib/mcp-tools.ts, organized by tier.
tier system
| tier | type | approval | count |
|---|---|---|---|
| 1 | Read-only | Auto-approved | 16 |
| 2 | Process & machine management | Auto-approved | 25 |
| 3 | Privileged | Requires user confirmation | 11 |
Server-side tools (
get_site_logs,get_system_presets,deploy_software,update_process,add_process,delete_process,create_talon,list_talons,set_talon_enabled,schedule_followup,cancel_followup) execute in the Next.js server process. They do not route through the agent command queue. Talons are site-level records and follow-ups are chat records, so neither is ever relayed to a machine.
execution-mode matrix
Web hoot chooses an execution path by tool name in web/lib/hoot-utils.server.ts. Server-side tools run in the Next.js server process. Legacy command tools write existing machine command types. Firestore tools create mcp_tool_call entries for the agent to execute. Local Agent SDK MCP is separate: agent/src/cortex_tools.py exposes only the tools returned by _make_tier1_tools, _make_tier2_tools, and _make_tier3_tools.
| tool | tier | web hoot execution | local Agent SDK MCP |
|---|---|---|---|
get_site_logs | 1 | Server-side | Not exposed |
get_system_info | 1 | Firestore mcp_tool_call | Yes, direct |
get_process_list | 1 | Firestore mcp_tool_call | Yes, direct |
get_running_processes | 1 | Firestore mcp_tool_call | Yes, direct |
get_gpu_processes | 1 | Firestore mcp_tool_call | Defined, but not returned |
get_network_info | 1 | Firestore mcp_tool_call | Yes, direct |
get_disk_usage | 1 | Firestore mcp_tool_call | Yes, direct |
get_event_logs | 1 | Firestore mcp_tool_call | Yes, direct |
get_service_status | 1 | Firestore mcp_tool_call | Yes, direct |
get_agent_config | 1 | Firestore mcp_tool_call | Yes, direct |
get_agent_logs | 1 | Firestore mcp_tool_call | Yes, direct |
get_agent_health | 1 | Firestore mcp_tool_call | Yes, direct |
get_system_presets | 1 | Server-side | Not exposed |
check_pending_reboot | 1 | Firestore mcp_tool_call | Not exposed |
schedule_followup | 1 | Server-side | Not exposed |
cancel_followup | 1 | Server-side | Not exposed |
restart_process | 2 | Legacy command-mapped | Yes, IPC |
kill_process | 2 | Legacy command-mapped | Yes, IPC |
start_process | 2 | Legacy command-mapped | Yes, IPC |
set_launch_mode | 2 | Legacy command-mapped | Yes, IPC |
update_process | 2 | Server-side | Not exposed |
add_process | 2 | Server-side | Not exposed |
delete_process | 2 | Server-side | Not exposed |
capture_screenshot | 2 | Firestore mcp_tool_call | Yes, IPC |
manage_process | 2 | Firestore mcp_tool_call | Not exposed |
manage_windows_service | 2 | Firestore mcp_tool_call | Not exposed |
configure_gpu_tdr | 2 | Firestore mcp_tool_call | Not exposed |
manage_windows_update | 2 | Firestore mcp_tool_call | Not exposed |
suppress_setup_screens | 2 | Firestore mcp_tool_call | Not exposed |
manage_notifications | 2 | Firestore mcp_tool_call | Not exposed |
configure_power_plan | 2 | Firestore mcp_tool_call | Not exposed |
manage_scheduled_task | 2 | Firestore mcp_tool_call | Not exposed |
network_reset | 2 | Firestore mcp_tool_call | Not exposed |
registry_operation | 2 | Firestore mcp_tool_call | Not exposed |
clean_disk_space | 2 | Firestore mcp_tool_call | Not exposed |
get_event_logs_filtered | 2 | Firestore mcp_tool_call | Not exposed |
manage_windows_feature | 2 | Firestore mcp_tool_call | Not exposed |
show_notification | 2 | Firestore mcp_tool_call | Not exposed |
create_talon | 2 | Server-side | Not exposed |
list_talons | 2 | Server-side | Not exposed |
set_talon_enabled | 2 | Server-side | Not exposed |
run_command | 3 | Firestore mcp_tool_call | Yes, direct |
run_powershell | 3 | Firestore mcp_tool_call | Yes, direct |
run_python | 3 | Firestore mcp_tool_call | Not exposed |
read_file | 3 | Firestore mcp_tool_call | Yes, direct |
write_file | 3 | Firestore mcp_tool_call | Yes, direct |
list_directory | 3 | Firestore mcp_tool_call | Yes, direct |
execute_script | 3 | Firestore mcp_tool_call | Yes, direct |
deploy_software | 3 | Server-side | Not exposed |
reboot_machine | 3 | Legacy command-mapped | Not exposed |
shutdown_machine | 3 | Legacy command-mapped | Not exposed |
cancel_reboot | 3 | Legacy command-mapped | Not exposed |
Local Agent SDK coverage is intentionally smaller than the web registry: at maximum tier it returns 21 tools, and at the default max_tier=2 it returns 15. agent/src/cortex_tools.py defines a get_gpu_processes wrapper, but the function is omitted from the returned tier-1 list, so local Agent SDK hoot does not expose it today. agent/src/mcp_tools.py also contains internal handlers that are not public web hoot tools, including get_display_layout and apply_display_topology.
tier 1: read-only tools
get_site_logs
Get activity logs across all machines in the site. Useful for finding errors, crashes, and events across the fleet. Server-side — queries Firestore directly.
| parameter | type | required | description |
|---|---|---|---|
level | string | No | Filter: error, warning, info |
hours | number | No | Look back this many hours (default: 24) |
limit | number | No | Max logs to return (default: 50) |
action | string | No | Filter by action type, e.g. process_crash, agent_started |
get_system_info
Get comprehensive system information including hostname, OS (with correct Windows 10/11 detection), CPU model and usage, memory (used/total GB), disk (used/total GB), GPU model, driver version, VRAM (used/total GB), GPU load %, uptime, and agent version.
| parameter | type | required | description |
|---|---|---|---|
| (none) |
get_process_list
Get all owlette-configured processes with their current status, PID, launch mode, executable path, file path / command arguments, working directory, and whether they are running.
| parameter | type | required | description |
|---|---|---|---|
| (none) |
get_running_processes
Get all running OS processes with CPU and memory usage. Can filter by name.
| parameter | type | required | description |
|---|---|---|---|
name_filter | string | No | Filter by process name (case-insensitive) |
limit | number | No | Max results (default: 50, max: 200) |
Returns: Processes sorted by memory usage with name, PID, CPU%, memory%.
get_gpu_processes
Get per-process GPU memory (VRAM) usage via Windows Performance Counters — same data source as Task Manager. Shows dedicated and shared GPU memory per process, sorted by usage. Works cross-vendor (NVIDIA, AMD, Intel) and for all GPU APIs (DirectX, OpenGL, CUDA, Vulkan).
| parameter | type | required | description |
|---|---|---|---|
| (none) |
get_network_info
Get network interfaces with IP addresses, netmasks, and link status.
| parameter | type | required | description |
|---|---|---|---|
| (none) |
get_disk_usage
Get disk usage for all drives including total, used, free space and percentage.
| parameter | type | required | description |
|---|---|---|---|
| (none) |
get_event_logs
Get Windows event log entries from Application, System, or Security logs.
| parameter | type | required | description |
|---|---|---|---|
log_name | string | No | Application, System, or Security (default: Application) |
max_events | number | No | Max entries (default: 20, max: 100) |
level | string | No | Filter: Error, Warning, Information |
get_service_status
Get the status and start type of a Windows service. Returned start_type disambiguates "stopped" states: automatic (should be running), demand_start (stopped-is-normal idle state, e.g. wuauserv/BITS), disabled (intentionally off).
| parameter | type | required | description |
|---|---|---|---|
service_name | string | Yes | Windows service name to query |
get_agent_config
Get the current owlette agent configuration (sensitive fields stripped).
| parameter | type | required | description |
|---|---|---|---|
| (none) |
get_agent_logs
Get recent owlette agent log entries.
| parameter | type | required | description |
|---|---|---|---|
max_lines | number | No | Max lines (default: 100, max: 500) |
level | string | No | Filter: ERROR, WARNING, INFO, DEBUG |
get_agent_health
Get agent health status including connection state and health probe results.
| parameter | type | required | description |
|---|---|---|---|
| (none) |
get_system_presets
Get available software deployment presets managed by the site admin. Returns installer URLs, silent install flags, verification paths, and other deployment parameters for software like TouchDesigner, Unreal Engine, media players, etc. Use this before deploy_software to find the correct preset and parameters. Server-side — queries Firestore directly.
| parameter | type | required | description |
|---|---|---|---|
software_name | string | No | Filter by name (case-insensitive partial match), e.g. TouchDesigner |
category | string | No | Filter by category, e.g. Creative Software, Media Server |
check_pending_reboot
Detect whether a system reboot is currently pending (from Windows Update, Component Based Servicing, pending file rename operations, or SCCM client). Read-only diagnostic — use during incident investigations, after a suspected update, or when the machine is behaving unusually. The agent also emits a site-level auto-alert the first time it detects a pending reboot (idempotent via a flag file).
| parameter | type | required | description |
|---|---|---|---|
| (none) |
Returns: pending (bool), reasons (array), last update install time, next scheduled update run time (if available).
schedule_followup
Schedule a follow-up turn on this conversation. At the scheduled time hoot is re-opened in the same chat with note injected as the instruction, acts on it, and reports back — the way a promise to "check back in ten minutes" actually happens, since a turn ends when the assistant stops typing. Server-side — the follow-up is a chat record (cortex-followups/{id}, a data-at-rest name), acted on by the cron sweep and never relayed to a machine.
| parameter | type | required | description |
|---|---|---|---|
note | string | Yes | What the follow-up turn should do, written as a self-contained instruction to hoot's future self — the conversation is not in view when it fires. Max 1000 characters |
delay_minutes | number | Exactly one of delay_minutes / at | Fire this many minutes from now: 1 to 10080 (one minute to seven days) |
at | string | Exactly one of delay_minutes / at | Fire at this absolute ISO 8601 timestamp with a timezone offset (e.g. 2026-01-31T14:00:00Z). Must be in the future and within seven days |
watch_command_id | string | No | Id of a machine command already dispatched in this conversation. The follow-up then fires as soon as that command finishes, or at its scheduled time, whichever comes first |
Returns: followup_id, fires_at (ISO), and watch_command_id when one was passed. Keep followup_id — cancel_followup needs it.
Pass exactly one of delay_minutes and at — both, or neither, is rejected with invalid_schedule rather than silently picking a winner. Out-of-range values return invalid_delay_minutes, at_in_the_past, or at_too_far_out.
Early fire. watch_command_id is a shortcut, not a replacement for the schedule — the scheduled time stays the backstop. The sweep resolves the watched command from the machine's commands/completed document and treats only the terminal statuses (completed, failed, error, cancelled) as finished; the agent's non-terminal running marker does not fire it. A follow-up scheduled against more than one machine — a subset of a site, or a site-wide chat — has no single command whose finish means the work is done, so the id is ignored there and the follow-up waits for its scheduled time.
Firing. The follow-up pass rides the once-a-minute talons cron sweep (/api/cron/talons). Each sweep scans the 25 soonest scheduled follow-ups and starts at most 10 turns; a backlog drains over the following minutes. An early fire is therefore only found while the follow-up sits inside that scan window — past it, the follow-up still fires at its own scheduled time.
Tier 3 always waits for a person inside a fired follow-up. The turn runs with forceTier3Approval, which overrides the site's requireTier3Approval setting: a site that lets an operator auto-run tier 3 while they watch has not agreed to it running while nobody does. The model may still reach for a tier-3 tool — the turn simply parks at approval-requested until the owner comes back to the chat.
Where it fires. A follow-up fires on the machines the scheduling turn was targeting, not on whatever the chat is pointed at when it comes due — the selection may have moved since the promise was made. A site-wide follow-up stays dynamic: a machine added in the meantime is included. The target is re-validated at fire time, so machines that have left the site, gone offline, or had hoot switched off are dropped from it; if nothing is left the follow-up is marked failed with the reason on the record rather than dispatched.
Other fire-time guarantees. Site access is re-resolved on every fire and never trusted from scheduling time, so a user removed or demoted in the meantime cannot keep driving tools through a promise they left behind; the chat must still exist and still belong to the same user (chat_deleted / chat_owner_mismatch). A follow-up never supersedes a live turn — if someone is mid-conversation the doc goes back to scheduled and the next sweep retries.
Where it is not available. The tool requires a user chat: unattended hoot (autonomous dispatch, talon directives) runs as a system actor with no chat to re-open and no user whose access could be re-resolved, and gets followup_unavailable. Both follow-up tools are also withheld from the public conversations API — that surface's chatId is a chat_conversations id while the sweep resolves chats/{chatId}, so a follow-up scheduled there could never fire (it would fail closed as chat_deleted). Withholding the tools is deliberate: better no promise than one the sweep silently breaks.
cancel_followup
Cancel a scheduled follow-up before it fires. Use it when the thing the follow-up was going to check has already been settled in the conversation, or when the operator asks for it to be dropped. Server-side — reaches the same store helper as DELETE /api/hoot/followups/{followupId}, which is what the chip above the composer calls.
| parameter | type | required | description |
|---|---|---|---|
followup_id | string | Yes | The id returned by schedule_followup. Never guess one |
Ownership is enforced inside the store transaction (the Admin SDK bypasses firestore.rules, so that is the only gate every caller passes through): only the user who scheduled a follow-up can cancel it, and only while it is still scheduled. Failure results are followup_not_found (404), followup_forbidden (403, it belongs to another user), and followup_not_scheduled (409, it already fired or was cancelled — a cancel that loses the race with the sweep's claim lands here). Like schedule_followup, it is unavailable to unattended hoot and withheld from the public conversations API.
tier 2: process & machine management tools
These execute immediately without user confirmation. Owlette-configured process control tools (restart_process, kill_process, start_process, set_launch_mode) wrap existing commands. Process config tools (update_process, add_process, delete_process) run server-side through the same validated action functions as the dashboard, and the talon tools (create_talon, list_talons, set_talon_enabled) run server-side through the same talon store as the talon editor. The rest are purpose-built with validated parameters and narrower blast radius than raw shell scripts.
restart_process
Restart an owlette-configured process by name.
| parameter | type | required | description |
|---|---|---|---|
process_name | string | Yes | Must match a configured process name |
kill_process
Kill/stop a running owlette-configured process.
| parameter | type | required | description |
|---|---|---|---|
process_name | string | Yes | Must match a configured process name |
start_process
Start a stopped owlette-configured process.
| parameter | type | required | description |
|---|---|---|---|
process_name | string | Yes | Must match a configured process name |
set_launch_mode
Set the launch mode for a process.
| parameter | type | required | description |
|---|---|---|---|
process_name | string | Yes | Must match a configured process name |
mode | string | Yes | off (not managed), always (24/7 with crash recovery), or scheduled |
schedules | array | When mode=scheduled | Schedule blocks with days and time ranges |
Schedule block format:
{
"days": ["mon", "tue", "wed", "thu", "fri"],
"ranges": [
{ "start": "09:00", "stop": "18:00" }
]
}update_process
Update an owlette-configured process by name. Only fields provided in the tool call are changed. Runs server-side through updateProcess; the agent picks up the config change through the existing config listener and launch-mode diff.
| parameter | type | required | description |
|---|---|---|---|
process_name | string | Yes | Current configured process name |
name | string | No | New display name |
exe_path | string | No | Full path to the executable |
file_path | string | No | Project file path or command arguments |
cwd | string | No | Working directory |
priority | string | No | Low, Normal, High, or Realtime |
visibility | string | No | Normal or Hidden |
time_delay | string | No | Launch delay in seconds, stored as a string |
time_to_init | string | No | Initialization timeout in seconds, stored as a string |
relaunch_attempts | string | No | Crash relaunch attempt count, stored as a string |
launch_mode | string | No | off, always, or scheduled |
schedules | array | When setting launch_mode=scheduled | Schedule blocks with days and time ranges |
schedulePresetId | string or null | No | Named schedule preset id, or null to clear |
add_process
Create a new owlette-managed process on the target machine. Runs server-side through createProcess; the new process defaults to launch_mode: "off" unless a launch mode is supplied.
| parameter | type | required | description |
|---|---|---|---|
name | string | Yes | Display name for the process |
exe_path | string | Yes | Full path to the executable |
file_path | string | No | Project file path or command arguments |
cwd | string | No | Working directory |
priority | string | No | Low, Normal, High, or Realtime |
visibility | string | No | Normal or Hidden |
time_delay | string | No | Launch delay in seconds, stored as a string |
time_to_init | string | No | Initialization timeout in seconds, stored as a string |
relaunch_attempts | string | No | Crash relaunch attempt count, stored as a string |
launch_mode | string | No | off, always, or scheduled |
schedules | array | When setting launch_mode=scheduled | Schedule blocks with days and time ranges |
schedulePresetId | string or null | No | Named schedule preset id, or null to clear |
delete_process
Delete an owlette-configured process by name. Runs server-side through deleteProcess. Deleting a process removes it from the machine config; it does not terminate an already-running OS process. Use kill_process first when the running process should also be stopped.
| parameter | type | required | description |
|---|---|---|---|
process_name | string | Yes | Configured process name to delete |
capture_screenshot
Capture a screenshot of the remote machine's desktop. Returns the image for visual analysis — use to diagnose display issues, verify process state, or see what's currently on screen.
| parameter | type | required | description |
|---|---|---|---|
monitor | number | No | 0 = all monitors combined (default), 1 = primary, 2 = second, etc. |
manage_process
Kill, suspend, or resume OS processes by name pattern. Works on any process, not just Owlette-managed ones. Safer than run_command + taskkill: validated params, no shell, refuses to touch critical system processes (lsass, winlogon, csrss, etc.) via an internal blocklist.
| parameter | type | required | description |
|---|---|---|---|
name_pattern | string | Yes | Process name with .exe or glob (e.g. chrome.exe, FreeFileSync*) |
action | string | Yes | kill, suspend, or resume |
match_exact | boolean | No | Exact match (default true) vs glob via fnmatch |
force | boolean | No | For kill: force immediately (default true), else graceful first |
manage_windows_service
Full services.msc parity — start, stop, restart, pause/continue, set startup type, configure failure recovery, or get full service details in one call. Use set_recovery to configure auto-restart on crash (critical for unattended media installations). Use get_details to query status, startup type, binary path, dependencies, and recovery config at once.
| parameter | type | required | description |
|---|---|---|---|
service_name | string | Yes | Service name (not display name) |
action | string | Yes | start, stop, restart, pause, continue, set_startup, set_recovery, get_details |
startup_type | string | For set_startup | auto, auto_delayed, manual, disabled |
first_failure | string | For set_recovery | restart, run_program, reboot, none |
second_failure | string | For set_recovery | Same options as first_failure |
subsequent_failures | string | For set_recovery | Action on third and later failures |
restart_delay_ms | number | No | Delay before recovery action (default: 60000) |
reset_counter_days | number | No | Days with no failures before counter resets (default: 1) |
reboot_message | string | No | Broadcast message if action is reboot |
run_program_path | string | If any action is run_program | Program to run on failure |
configure_gpu_tdr
Configure Windows GPU Timeout Detection and Recovery. Writes TdrDelay (and optionally TdrDdiDelay) to the registry. Critical for TouchDesigner / Unreal / Unity installations with heavy shader work — the default 2-second timeout causes silent crashes on complex GPU operations. A reboot is required for changes to take effect.
| parameter | type | required | description |
|---|---|---|---|
timeout_seconds | number | Yes | TdrDelay in seconds (2-300). Default Windows value is 2; heavy creative workloads usually need 10-60 |
ddi_timeout_seconds | number | No | Optional TdrDdiDelay in seconds (2-300). Max time GPU can spend in Present/Draw calls |
manage_windows_update
Pause, resume, or schedule Windows Update. Pause before live events; use set_active_hours to block auto-reboot during quiet hours; set_scheduled_install for exact install timing; set_feature_deferral / set_quality_deferral to delay rollouts. Windows Update is the #1 threat to unattended 24/7 installations.
| parameter | type | required | description |
|---|---|---|---|
action | string | Yes | get_status, pause, resume, set_active_hours, set_scheduled_install, set_restart_deadline, set_feature_deferral, set_quality_deferral |
pause_days | number | For pause | Days to pause (1-35) |
start_hour / end_hour | number | For set_active_hours | Hours (0-23) |
day_of_week | number | For set_scheduled_install | 0 = every day, 1-7 = Sun–Sat |
hour | number | For set_scheduled_install | Hour of day (0-23) |
deadline_days | number | For set_restart_deadline | Days before force reboot (2-14) |
days | number | For deferral actions | Feature (0-365) or quality (0-30) deferral days |
suppress_setup_screens
Suppress the full-screen Windows setup screens that hijack the display at sign-in after updates: the "Choose privacy settings" experience, the Windows Welcome Experience, "Let's finish setting up your device" (SCOOBE), and the Edge first-run tour. Writes the machine-wide policies plus the per-user keys for every existing profile (mounting signed-out profiles' hives) and the Default profile, so future accounts inherit the suppression. apply is idempotent — feature updates are known to reset these keys, so re-assert on a schedule (the update guard talon preset does exactly this).
| parameter | type | required | description |
|---|---|---|---|
action | string | Yes | get_status (read-only per-profile drift report) or apply (write all suppression keys) |
manage_notifications
Control Windows toast notifications and Focus Assist. Essential for kiosks and video walls where a surprise "Updates are ready" toast would interrupt an exhibit. Use disable_all_toasts to fully silence the system, enable_focus_assist with alarms_only for total silence, or disable_for_app to silence a specific app.
| parameter | type | required | description |
|---|---|---|---|
action | string | Yes | get_status, disable_all_toasts, enable_focus_assist, disable_focus_assist, disable_for_app |
app_name | string | For disable_for_app | App identifier (e.g. Microsoft.WindowsStore, MSTeams) |
focus_mode | string | For enable_focus_assist | priority_only or alarms_only |
configure_power_plan
Set Windows power plan and disable sleep/hibernate/screen blanking. Required for any 24/7 unattended installation — default power settings will sleep the machine, blank the screen, or hibernate, all of which break live deployments.
| parameter | type | required | description |
|---|---|---|---|
plan | string | No | high_performance, balanced, or ultimate_performance (omit to keep current) |
disable_sleep | boolean | No | Set standby timeout to Never on both AC and battery |
disable_hibernate | boolean | No | Disable hibernation (removes hiberfil.sys) |
disable_screen_blanking | boolean | No | Disable monitor timeout |
manage_scheduled_task
Full Task Scheduler parity — list, enable, disable, delete, run_now, stop, create new tasks, get details, and get run history. Use create for weekly memory-flush reboots, boot-time media app launches, or event-triggered restarts.
| parameter | type | required | description |
|---|---|---|---|
action | string | Yes | list, enable, disable, delete, run_now, stop, create, get_details, get_history |
task_name | string | For non-list actions | Task name; can include folder path (e.g. \Folder\TaskName) |
name_filter | string | For list | Substring filter |
description | string | No | For create: human-readable description |
trigger | object | For create | {type: "boot"|"logon"|"once"|"daily"|"weekly"|"on_event"|"on_idle", ...}. Additional fields depend on type |
task_action | object | For create | {type: "run_program", program, arguments?, working_directory?} |
principal | object | For create | {run_as: SYSTEM|LOCAL_SERVICE|NETWORK_SERVICE|current_user, run_level: highest|limited} |
settings | object | No | {start_when_available, execution_time_limit_minutes, restart_count, restart_interval_minutes, run_only_if_network_available, allow_start_on_batteries, hidden, multiple_instances, delete_expired_task_after_days} |
network_reset
Flush DNS, renew IP lease, restart a network adapter, or reset the winsock stack. Common fix for NDI dropouts, Firebase connectivity loss, DNS resolution issues at venue networks. reset_winsock requires a reboot to fully take effect.
| parameter | type | required | description |
|---|---|---|---|
action | string | Yes | flush_dns, renew_ip, restart_adapter, reset_winsock |
adapter_name | string | For restart_adapter | Adapter name (e.g. Ethernet, Wi-Fi) |
registry_operation
Read, write, or delete Windows registry values. Restricted to an allowlist of safe registry paths (Winlogon, GraphicsDrivers, WindowsUpdate, Notifications, Power, Services, etc.) — system hives like SAM, SECURITY, and Cryptography are blocked.
| parameter | type | required | description |
|---|---|---|---|
action | string | Yes | read, write, delete |
hive | string | Yes | HKLM (machine) or HKCU (current user) |
key_path | string | Yes | Key path under hive (must match an allowed prefix) |
value_name | string | For write/delete | Omit for read to enumerate all values in the key |
value_data | string | For write | Data to write (dword as "8", binary as hex string, etc.) |
value_type | string | For write | string, dword, binary, expand_string, multi_string |
clean_disk_space
Clean temp files, Windows temp, prefetch cache, recycle bin, or Owlette logs with an age filter. Use dry_run=true to preview what would be deleted.
| parameter | type | required | description |
|---|---|---|---|
target | string | Yes | temp, windows_temp, prefetch, recycle_bin, owlette_logs |
older_than_days | number | No | Only delete files older than N days (default: 7). Ignored for recycle_bin |
dry_run | boolean | No | Return counts/sizes without deleting (default: false) |
get_event_logs_filtered
Fast filtered event log query via Get-WinEvent -FilterHashtable. Orders of magnitude faster than get_event_logs when searching for specific crashes, process sources, or event IDs.
| parameter | type | required | description |
|---|---|---|---|
log_name | string | Yes | Application, System, Security, Setup |
process_name | string | No | Filter by provider/source name |
event_id | number | No | Specific event ID (e.g. 41 for unexpected shutdown, 1000 for app crash) |
hours_back | number | No | Look back this many hours (1-168, default: 24) |
level | string | No | Critical, Error, Warning, Information, Verbose |
max_events | number | No | Max events (1-200, default: 50) |
manage_windows_feature
Add, remove, or list Windows Optional Features (DISM, e.g. NetFx3, OpenSSH-Server), Windows Capabilities (FoD, e.g. OpenSSH.Client), or AppX Packages (Store apps like OneDrive, Xbox Game Bar, Cortana, Teams). Critical features for Owlette itself are blocklisted and cannot be disabled. AppX install is not supported.
| parameter | type | required | description |
|---|---|---|---|
type | string | Yes | optional_feature, capability, appx_package |
action | string | Yes | list, install, remove |
name | string | For install/remove | Feature/capability/package name |
all_users | boolean | No | For appx_package remove: also remove provisioning package (default: false) |
name_filter | string | For list | Substring filter |
show_notification
Display an on-screen message on the remote machine — useful when a technician is physically nearby. Toast style is a subtle corner notification; modal style uses msg.exe to block the screen briefly. Opposite of manage_notifications, which suppresses notifications.
| parameter | type | required | description |
|---|---|---|---|
message | string | Yes | Notification body |
title | string | No | Notification title |
style | string | No | toast (default, subtle corner) or modal (blocking msg.exe box) |
duration_seconds | number | No | For modal: how long the box stays up (default: 5) |
create_talon
Create a talon on this site — a saved automation of trigger → optional condition → outputs. See talons for the product-level picture. Server-side — talons are site-level records written through the same store as the dashboard editor, never relayed to a machine.
Confirm before calling. A talon runs unattended against real machines, so hoot is instructed never to call this from a vague request: it states back the exact talon it intends to create — trigger, condition, every output, the machines in scope, the cooldown — and waits for the operator to confirm.
| parameter | type | required | description |
|---|---|---|---|
name | string | Yes | Short lowercase name shown in the dashboard, 80 characters or fewer |
trigger | object | Yes | What makes the talon fire — one of the four shapes below |
outputs | array | Yes | 1 to 5 output entries, executed in order |
description | string | No | Lowercase note about what the talon is for, 500 characters or fewer |
condition | object | No | Gate evaluated after the trigger fires. Defaults to {"type":"none"} |
scope | object | No | {"machineIds":["..."]}. Omit for every machine in the site |
cooldownMinutes | number | No | Minimum minutes between runs, 0-1440 (default: 60) |
enabled | boolean | No | Whether the talon is armed as soon as it is created (default: true) |
Trigger shapes (exactly one form):
{"type": "schedule", "entries": [{"id": "e1", "days": ["mon", "wed"], "time": "09:00"}]}
{"type": "schedule", "intervalMinutes": 30}
{"type": "threshold", "metric": "cpu_percent", "operator": ">", "value": 90}
{"type": "event", "eventTypes": ["process_crash", "machine_offline"], "delayMinutes": 2}- schedule / entries — 24-hour
HH:MMin the site's timezone, up to 50 entries.entriesandintervalMinutesare mutually exclusive. - schedule / intervalMinutes — 5 to 1440 minutes, but 15 minutes minimum when the condition is a
visual_check. - threshold — metrics
cpu_percent,memory_percent,disk_percent,gpu_percent,cpu_temp,gpu_temp,network_latency,network_packet_loss; operators>,<,>=,<=. Threshold talons ride the existing alert pipeline: one fires when an alert rule fires and the breach matches the talon's own metric, operator, and bound — so a threshold talon does nothing until a matching alert rule exists. - event —
process_crash,machine_offline,process_start_failed,process_restarted,exe_missing, and thedisplay_*events. Event triggers only:delayMinutes(0-1440) waits that long after the event before running, e.g. letting a restarted app finish booting before avisual_checklooks at it.
Condition — {"type":"none"} (default), or {"type":"visual_check","expectation":"the lobby wall is playing the loop, not showing a desktop","monitor":0}, which captures a fresh screenshot and asks a vision model whether the expectation holds. expectation is 500 characters or fewer; monitor is 0 for all displays combined, 1 for primary.
Output entries — each entry is an object keyed by type:
| field | applies to | description |
|---|---|---|
type | all | email, webhook, cortex, or command |
url | webhook | An https URL. Private, loopback, and link-local addresses are rejected (DNS-resolving SSRF check at authoring time, re-validated at send time) |
directive | cortex | What hoot should do when the talon fires, 1000 characters or fewer |
commandType | command | restart_process, start_process, or stop_process |
processName | command | The configured process name to act on |
processId | command | The configured process id, when hoot already holds it |
type: "cortex" is the hoot output — the wire literal is a deliberate survivor of the cortex → hoot rename (it is persisted on every talon and every talon-run summary, and the MCP tool schema is itself a published contract). Every label a human reads says hoot. See web/lib/hoot/WIRE_NAMES.md class B.
Refusals. A command output takes the same privilege as issuing the command by hand — site admins only, refused with command_output_forbidden (403) both in the tool and again in the store. A visual_check condition or a cortex output spends the talon author's own LLM key, so authoring one without a saved key returns llm_key_required (400). Exceeding 20 talons on the site returns talon_limit_reached (409). Validation rejects unknown top-level fields outright, so the model can never stamp a server-owned field onto the document; field-level failures come back as invalid_talon with field_errors rather than throwing and taking the turn down.
Returns: talon_id, name, enabled, next_run_at.
Unattended hoot cannot call this tool: authoring a talon is standing fleet policy that outlives the incident, so create_talon is excluded from the autonomous investigator's tool list regardless of tier.
list_talons
List the talons on this site, ordered by name. Call it before set_talon_enabled to get a talon id, and before create_talon so an existing talon is not duplicated.
| parameter | type | required | description |
|---|---|---|---|
| (none) |
Returns: count, plus per talon talon_id, name, enabled, trigger (the normalized object, not a prose summary, so the exact metric / interval / event values are available for follow-up calls), outputs (types only), last_run_status, last_run_at, next_run_at.
Read-only, so unlike the two writing talon tools this one stays available to unattended hoot.
set_talon_enabled
Arm or disarm an existing talon. Disabling leaves the talon in place — it does not delete it.
| parameter | type | required | description |
|---|---|---|---|
talon_id | string | Yes | As returned by list_talons or create_talon. Never guessed |
enabled | boolean | Yes | true to arm, false to disarm |
Enabling recomputes nextRunAt from now in the site's timezone, so a talon that sat disabled for a while does not fire the moment it comes back, and re-checks the author's LLM key when the talon has a visual_check condition or a hoot output (llm_key_required if it is gone). Either edge clears a system-set disable reason, so a re-armed talon does not still claim it was switched off. Like create_talon, this tool is excluded from unattended hoot.
Returns: talon_id, name, enabled, next_run_at.
tier 3: privileged tools
These require explicit user confirmation before execution.
run_command
Execute a shell command on the remote machine.
| parameter | type | required | description |
|---|---|---|---|
command | string | Yes | Must start with an allowed command |
user_session | boolean | No | Run in the logged-in user's desktop session (needed for GUI/display access) |
Returns: stdout, stderr, exit code.
Allowed commands (first word must be one of):
ipconfig, systeminfo, hostname, whoami, tasklist, netstat, ping, tracert, nslookup, dir, type, echo, set, ver, wmic, sc, net, reg, nvidia-smi, dxdiag
This is the default set (DEFAULT_ALLOWED_COMMANDS); it is overridable via config.mcp.allowed_commands. A running command can be cancelled from its tool card, which kills the process tree on the machine.
run_powershell
Execute a PowerShell command on the remote machine.
| parameter | type | required | description |
|---|---|---|---|
script | string | Yes | PowerShell script to execute |
user_session | boolean | No | Run in the logged-in user's desktop session |
Returns: stdout, stderr, exit code.
No command restrictions — every invocation is audit-logged to the site events feed and the local [MCP-AUDIT] log. Fixed 25-second timeout; for long-running work use execute_script. A running command can be cancelled from its tool card, which kills the process tree on the machine.
run_python
Execute Python code on the remote machine in the user's desktop session.
| parameter | type | required | description |
|---|---|---|---|
code | string | Yes | Python code to execute |
Sandboxed execution (since v2.6.5). When invoked via this tool, code runs with:
- Restricted
__builtins__—eval,exec,compile,globals,locals,breakpoint,input,exit,quitare all removed.open,print,getattr/setattr, and common types/exceptions remain available. - Gated imports — only a curated subset of the standard library is importable:
math,json,re,datetime,time,random,collections,itertools,functools,operator,string,textwrap,decimal,fractions,statistics,copy,pprint,base64,hashlib,hmac,struct,io,csv,pathlib,typing,dataclasses,enum,abc. Dangerous modules —os,subprocess,shutil,ctypes,socket, and third-party packages likepsutilormss— raiseImportErrorwith guidance to useexecute_scriptorrun_commandinstead. - No filesystem access beyond
output_dir— the code canopen()files it writes into the providedoutput_dirvariable, but cannot reach the rest of the filesystem without going through a gated import.
The LLM cannot escape this sandbox. Internal first-party callers (e.g. the agent's own screenshot capture path in agent/src/session_exec.py) pass trusted=True, which restores full builtins and unrestricted imports; that flag is not reachable from the LLM-exposed tool schema.
Returns: stdout from print(), plus any files written to output_dir.
read_file
Read the contents of a file on the remote machine.
| parameter | type | required | description |
|---|---|---|---|
path | string | Yes | Absolute file path (max 100KB) |
write_file
Write content to a file on the remote machine.
| parameter | type | required | description |
|---|---|---|---|
path | string | Yes | Absolute file path |
content | string | Yes | Content to write |
list_directory
List the contents of a directory with file sizes and modification dates.
| parameter | type | required | description |
|---|---|---|---|
path | string | Yes | Absolute directory path |
execute_script
Execute a PowerShell script on the remote machine with no command restrictions. Use for software installs, diagnostics, stress tests, service management, registry edits, or any other admin task. For most routine sysadmin scenarios, prefer a purpose-built Tier 2 tool (e.g. manage_windows_service, registry_operation, clean_disk_space) — execute_script is the escape hatch when no purpose-built tool fits.
| parameter | type | required | description |
|---|---|---|---|
script | string | Yes | PowerShell script to execute (can be multi-line) |
timeout_seconds | number | No | Timeout in seconds (default: 120, capped at 3300 / 55 min) — set higher for long operations like installs |
working_directory | string | No | Optional working directory for script execution |
Returns: stdout, stderr, exit code.
Timeouts are capped at 3300 seconds (55 minutes) so a result stays retrievable; for jobs that run longer than that, launch the work detached (e.g. a background job or scheduled task) and check back in a follow-up turn rather than blocking the tool call. A running execute_script can be cancelled from its tool card — the process tree is killed within a few seconds and the card resolves to "cancelled by user".
deploy_software
Deploy and install software on the remote machine using the full deployment pipeline: download installer, run silent install, verify installation, and track progress. Creates a tracked deployment visible on the Deployments page. Server-side — orchestrated by the server, not the agent directly.
Requires user confirmation before execution. hoot will summarize the deployment plan (software, version, install path, parallel install status, processes to close) and wait for explicit approval before proceeding.
| parameter | type | required | description |
|---|---|---|---|
software_name | string | Yes | Software name, e.g. TouchDesigner, Unreal Engine |
version | string | No | Version string, e.g. 2025.32280. Required for version-specific software |
preset_id | string | No | System preset ID from get_system_presets |
installer_url | string | No | Direct HTTPS installer URL (overrides preset URL) |
installer_name | string | No | Installer filename (auto-derived from URL if omitted) |
silent_flags | string | No | Silent install flags (overrides preset value) |
close_processes | array | No | Process names to terminate before install, e.g. ["TouchDesigner.exe"] |
parallel_install | boolean | No | Install alongside existing versions (auto-enabled for TouchDesigner) |
timeout_minutes | number | No | Max installation time in minutes (default: 40) |
TouchDesigner specifics: Download URL is auto-constructed from version number. parallel_install is automatically enabled to prevent the installer from removing existing builds. Use the full installer, not the WebInstaller.
Silent flag formats by installer type:
- Inno Setup:
/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /DIR="path" - NSIS:
/S /D=path - MSI:
/quiet /norestart INSTALLDIR="path"
reboot_machine
Reboot the remote machine with a 30-second countdown delay. Can be cancelled from the dashboard or via cancel_reboot within the countdown window.
| parameter | type | required | description |
|---|---|---|---|
| (none) |
shutdown_machine
Shut down the remote machine with a 30-second countdown delay. The machine will NOT automatically restart.
| parameter | type | required | description |
|---|---|---|---|
| (none) |
cancel_reboot
Cancel a pending reboot or shutdown. Must be called within the 30-second countdown window.
| parameter | type | required | description |
|---|---|---|---|
| (none) |
security model
tool execution flow
LLM decides to call a tool
|
+-- Tier 3: pause for in-chat approval (when the per-site approval gate is on)
| +-- User approves: continue to the tool-name execution path
| +-- User denies: return "denied by user"
|
+-- Server-side tools
| +-- get_site_logs / get_system_presets query Firestore on the web server
| +-- deploy_software creates deployment records and install commands server-side
| +-- update_process / add_process / delete_process call process action functions server-side
| +-- create_talon / list_talons / set_talon_enabled call the talon store server-side
| +-- schedule_followup / cancel_followup write the chat's follow-up records;
| the once-a-minute cron sweep fires them, with tier 3 forced to wait
| for approval and site access re-resolved at fire time
|
+-- Legacy command-mapped tools
| +-- Write existing command types such as restart_process or reboot_machine
| +-- Agent handles the legacy command and writes completion state
|
+-- Firestore mcp_tool_call tools
+-- Create an mcp_tool_call command in Firestore
+-- Agent receives and executes the MCP tool
+-- Agent writes result to completed queue
+-- Turn runner polls for the result (bounded by the tool's own timeout)The turn runs server-side, detached from the browser connection — it keeps executing and its results still land in the chat even if the connection drops or the page reloads, and the client reattaches to stream it. Long-running shell tools (run_command, run_powershell, execute_script) can be cancelled from their tool card mid-flight: the agent kills the process tree and the card resolves to "cancelled by user". The whole turn can be stopped server-side from the chat.
command allowlists
run_command enforces an allowlist on the agent side. Even if a command is sent via Firestore, the agent rejects it if the first command isn't in the allowlist. run_powershell has no allow-list — it accepts arbitrary PowerShell, with accountability provided by mandatory audit logging (site events feed + local [MCP-AUDIT] log). run_python enforces its sandbox on the agent side — the LLM cannot override the import gate or restore blocked builtins.
tier 2 blocklists
Tier 2 tools enforce per-tool blocklists to prevent self-inflicted outages:
manage_process— critical system processes (lsass, winlogon, csrss, etc.) cannot be killedregistry_operation— SAM, SECURITY, and Cryptography hives are unreachable; only an allowlist of safe key prefixes is permittedmanage_windows_feature— core Windows features Owlette depends on (NetFx4, WMI-*, PowerShell*) cannot be removedcreate_talon—commandoutputs are site-admin only, and webhook URLs that resolve to private, loopback, or link-local addresses are rejected
Agent-executed Tier 2 tools emit structured [MCP-AUDIT] log entries for each invocation. Server-side process config tools use the process mutation audit path with actor cortex:user_<userId>. Talon tools emit talon_mutated rows with the same actor, via: "cortex", and the originating chat id. The follow-up tools emit no mutation row of their own — the follow-up document is the record, and the DELETE /api/hoot/followups/{followupId} route behind the composer chip audits its own cancels as chat_mutated / verb cancel_followup.
agent-side limits
- Subprocess timeout: 25 seconds (default; overridable per-tool where applicable)
- Max output size: 50KB
- Screenshot max size: 10MB