Tools
apfelclaw loads its runtime tool catalog from a JSON manifest (tools.json). The model does not read this file directly — the app converts it into an OpenAI-compatible tools payload, sends that to apfel, and maps approved tool calls back to local Swift executors.
Most tools are read-only. add_calendar_event and write_note write to the user’s calendar or Apple Notes and always require confirmation before execution. Whether the user is prompted before execution depends on the configured approval mode and each tool’s confirmation policy. The local TUI auto-approves tools. Telegram can create notes only after tool auto-approve is enabled.
find_files
Find files on this Mac using Spotlight-backed search.
| Property | Value |
|---|---|
| Domain | files |
| Read-only | Yes |
| Follow-up reuse | No |
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
query | string | Yes | Search phrase or filename |
limit | integer | No | Maximum results (prefer 5 or fewer) |
Use when: The user needs to locate files by name or search phrase.
Avoid when: The user already has an exact absolute path — use get_file_info instead.
Examples:
- “Find my resume”
- “Where is the project proposal?”
- “Search for files named budget”
get_file_info
Get metadata for one exact file or directory path, including paths that start with ~/.
| Property | Value |
|---|---|
| Domain | files |
| Read-only | Yes |
| Follow-up reuse | No |
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
path | string | Yes | Exact file or directory path. Prefer an absolute path; ~/... is also supported |
Use when: The user already provided the exact path and wants metadata (size, dates, type).
Avoid when: The user needs to search for the path first — use find_files instead.
Examples:
- “What’s in ~/Documents/report.pdf?”
- “Get info on /Applications/Xcode.app”
list_calendar_events
Read upcoming events from the user’s calendars via EventKit.
| Property | Value |
|---|---|
| Domain | calendar |
| Read-only | Yes |
| Follow-up reuse | Yes |
| Deterministic fallback | No |
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
timeframe | string | Yes | Natural-language time range in the Mac’s locale, such as today, tomorrow, next week, April 12, or 2026-04-12 |
limit | integer | No | Maximum events (prefer 10 or fewer) |
Use when: The user asks about meetings or schedule items for a specific time range.
Avoid when: The user wants to create, edit, or delete events.
Relative phrases such as “today” or “this week” are parsed in the Mac’s current locale, so the same tool call works for heute, demain, and other local equivalents. There is no English keyword table.
Examples:
- “What meetings do I have today?”
- “Show my schedule for tomorrow”
- “Any events this week?”
This tool supports follow-up reuse: if the user asks about “today” and then follows up with “what about tomorrow?”, the classifier sees the last calendar snapshot and can select this tool again.
add_calendar_event
Create one calendar event in the user’s calendars via EventKit.
| Property | Value |
|---|---|
| Domain | calendar |
| Read-only | No |
| Follow-up reuse | No |
| Confirmation | Always |
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Event title |
starts_at | string | Yes | Event start time as natural language in the system locale or ISO 8601. It must include a specific time |
ends_at | string | No | Explicit end time as natural language in the system locale or ISO 8601 |
duration_minutes | integer | No | Event duration in minutes when no explicit end time is provided |
location | string | No | Event location |
notes | string | No | Event notes |
Use when: The user asks to add, create, or schedule a calendar event, meeting, or appointment.
Avoid when: The user wants to list events, edit or delete an existing event, or create a recurring event.
Notes:
- This tool creates single events only in v1.
- If the user did not clearly specify an end time or duration, the assistant should ask one short clarification question instead of guessing.
- Start and end times are parsed in the Mac’s current locale, or as ISO 8601.
- apfelclaw uses the system default calendar for new events.
Examples:
- “Add my weekly sync meeting for today at 14:00 to my calendar”
- “Create a dentist appointment tomorrow at 9am”
- “Schedule lunch with Sam on Friday from 12:00 to 13:00”
get_mac_status
Read current status information from this Mac.
| Property | Value |
|---|---|
| Domain | system |
| Read-only | Yes |
| Follow-up reuse | Yes |
| Deterministic fallback | Yes |
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
sections | array | No | Optional section list. Allowed values: battery, power, thermal, memory, storage, uptime. Omit for an overview |
Use when: The user asks about this Mac’s current battery, power, thermal state, memory, disk space, or uptime.
Avoid when: The question is about files, calendar, mail, or requires a shell command rather than direct system status APIs.
Examples:
- “How much battery do I have left?”
- “What’s my Mac status?”
- “How much free disk space do I have?”
This tool supports follow-up reuse: if the user first asks for an overview and then follows up with a narrower system-health question, the classifier can select this tool again.
run_safe_command
Run one read-only native macOS terminal command from the safe allowlist.
| Property | Value |
|---|---|
| Domain | terminal |
| Read-only | Yes |
| Follow-up reuse | No |
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
command | string | Yes | Command name from the allowlist |
arguments | array | No | Array of string arguments. Each command has its own safe argument rules |
Use when: A single allowlisted read-only shell command directly answers the question.
Avoid when: The task needs shell syntax, write access, or commands not on the list.
Safe command allowlist
The following commands are permitted:
pwd ls whoami date mdfind mdls stat find ps lsof
Examples:
- “What’s my username?”
- “List files in my Downloads folder”
- “Show running processes”
list_recent_mail
Read recent messages from the Apple Mail inbox.
| Property | Value |
|---|---|
| Domain | mail |
| Read-only | Yes |
| Follow-up reuse | Yes |
| Deterministic fallback | Yes |
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
limit | integer | No | Maximum messages (prefer 5 or fewer) |
Use when: The user asks for latest or recent emails.
Avoid when: The user asks for specific mail search, message bodies, or mail actions.
Examples:
- “Check my email”
- “Any new mail?”
- “Show me the last 3 emails”
This tool supports follow-up reuse: if the user asks “any new mail?” and then follows up with “show me more”, the classifier can select this tool again.
write_note
Create one new note in Apple Notes.
| Property | Value |
|---|---|
| Domain | notes |
| Read-only | No |
| Follow-up reuse | No |
| Confirmation | Always |
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Short specific note title |
body | string | Yes | Full note text, preserving the user’s wording |
Use when: The user asks to write, create, save, or jot down a note in Apple Notes, including incomplete requests and later replies that supply the title, body, or a confirmation to save.
Avoid when: The user wants to list, search, edit, or delete notes; create a calendar event or reminder; or find or write a file.
Notes:
- This tool creates one note in the default Notes folder.
- If the user dictated one block of text, the assistant should derive a short title and put the full text in the body.
- If the user did not say what to write, the assistant should ask one short clarification question instead of inventing content.
- Creating a note requires macOS Automation permission for Notes.app, the same class of prompt as Apple Mail.
- The local TUI auto-approves this write. Telegram keeps it denied until you run
/remotecontrol enable-tools telegram. - The assistant should not claim a note was saved unless this tool actually ran.
Examples:
- “Write a note that I need milk”
- “Can you write a note for me?”
- “Create a note titled Groceries with eggs, bread, and coffee”
- “Save this as a note: call the dentist tomorrow”
Tool behavior notes
Argument normalization
Each tool module validates the model’s raw argument JSON before execution. Unexpected keys and missing required parameters are rejected instead of being guessed from the user’s message. Optional limits are still clamped to safe ranges.
Result snapshots
After execution, each tool can produce a ToolResultSnapshot — a structured summary of what the tool covered. This snapshot includes:
- scopeSummary: A human-readable description (e.g., “Previous calendar lookup covered today (2026-04-07) and returned 3 event(s).”)
- machineReadableScope: A JSON object the router uses to compare previous vs. requested scope
These snapshots are injected into the Intent Router’s classifier context for subsequent turns, so it can decide whether to select the same tool again or pick a different one.
Deterministic fallback
Tools marked with “deterministic fallback” (list_recent_mail) can be invoked with empty {} arguments when the model fails to produce valid arguments but routing has already decided a tool should run.