Agent Tools

Built-in tools available to the Foxl desktop agent

The Foxl desktop agent comes with a set of built-in tools organized into profiles, plus a few capability-gated tools (like generate_image) that register automatically when their credentials are available. Which built-ins are loaded is decided by the tool profile (Full by default - see below), not per message; your own custom tools and MCP servers are added on top of whichever profile is active.

Browser

ToolDescription
browserOne pinned release of the agent-browser CLI (Rust + Playwright) driving Foxl's own Chrome profile under ~/.foxl/browser-profile - open <url>, snapshot -i, click @ref, fill @ref "text", screenshot. Asks first, unless you auto-approve it. See Browser Automation
browser_extensionControl your real Chrome tabs via the Chrome extension. Opening a page or tab, closing a tab, clicking (on an element or at a point), typing, pressing a key and choosing an option ask first, unless you auto-approve it; reading the page, listing tabs, scrolling and hovering do not
browser_take_overHand the page in Foxl's own browser to you when a step is yours (a CAPTCHA, an "are you human" check, a sign-in you would rather type yourself), and wait until you tap I'm done. In your own chats only. See When a step is yours

In both, a step that orders, pays or books (a click on "Place order", "Pay" or "Confirm booking", a priced "Reserve", an Enter in a checkout field) follows your other approval rules with no card of its own, and the chat then shows what was bought; to approve each one on its own card, even with auto-approve on, turn on Settings > Safety > Purchases > Ask before purchases. Sending money and trading always ask; see Approvals.

Code & Files

ToolDescription
file_readRead files from your filesystem
file_writeCreate or overwrite a file. Asks first, unless you auto-approve it
file_editChange part of a file: replace an exact piece of text, once or everywhere, and show the change as a diff. Follows the same approval rule as file_write
code_searchSearch across your codebase with ripgrep (regex, file type filters)
view_imageView and analyze images

A relative path in these tools means a path inside your workspace (~/.foxl/workspace/ on an installed app), so "save notes.md in your workspace" lands there; ~/... is your home folder. When a chat has its own folder (the folder button in the chat header), a path that names no folder points into that folder instead.

When the agent changes a file and reads or views it in the same step - for example rendering a diagram with a shell command and then looking at the PNG - the read waits for the change to finish, so it sees the new file rather than "file not found" or the old version. Reads that do not follow a change still run side by side.

Shell & System

ToolDescription
execRun shell commands (bash, zsh, etc.) - covers git, npm, curl, and arbitrary shell pipelines
processList, monitor, and kill running processes
terminalPersistent terminal session for stateful shell workflows
request_skill_keyAsk for a key a skill needs, in a key card in the chat. Saved on your computer and given only to commands in a chat that uses a skill declaring that key; Foxl's AI does not see it. See Skills

exec runs in your workspace (or the chat's folder, when the chat has one) unless the agent names another working directory, and a relative working directory is resolved against it too. On macOS and Linux, Settings > Safety > Run shell commands in a sandbox (off by default) runs exec and the terminals the agent opens inside a sandbox, the macOS sandbox on a Mac and bubblewrap on Linux; see Shell sandbox.

A command the agent runs in the background, such as a dev server or a long build, keeps running after the agent's reply until it exits or reaches its time limit (an hour, unless the agent sets another). Its step in the chat has a Stop button, in Foxl on your computer and on your phone. The button goes once the chat shows the command ended (for example when the agent checked on it), and otherwise stays until the time limit; a press after the command ended says it already finished.

When you ask the agent to tell you once such a command is done, the chat answers by itself when the command ends or reaches its time limit, with how it went, read from the last 2,000 characters of its output and of its errors, and you get the same notification as when an agent finishes, on your phone too. A command that succeeds without printing anything gets a one-line note in the chat instead of a reply ("finished, no output"). This works wherever the agent runs the command: a subagent's command answers in the chat that started the subagent, a scheduled run's in that run's conversation (a follow-up within the run's limits), a channel's such as Slack or Telegram in that thread, and a reply the chat continued by itself can arrange one too. A command started by a reply that itself followed a finished command can ask for one more report, up to three in a row, so a build, then its tests, then a deploy each report back. If Foxl restarts while the command runs (a restart stops background commands), the chat says once, after the restart, that the command stopped when Foxl restarted. No answer comes when you or the agent stopped the command, when the agent already read the result itself, or when you stopped the reply that started it: stopping that reply also stops what it arranged, including its subagents' reports, while a report you asked for in an earlier reply still comes.

Web

ToolDescription
web_fetchFetch web pages and API endpoints
request_loginAsk you for a website's sign-in in a Sign in to card in the chat. What you type goes to the vault on your computer, never to the model. See Sign-ins and saved keys
fill_loginSign in on a site's own https page in Foxl's browser with the sign-in saved in the vault, without the model seeing it, and say so in the chat. On another site, such as a single sign-on page, it asks once for that site and remembers your answer, or signs in right away when you named that site yourself in a chat where Foxl has read nothing else. The first time, it asks once whether to ask you first. With Settings > Safety > Ask before Foxl uses a saved sign-in on, it asks first, unless you saved that sign-in in a card in this chat in the last 30 minutes or chose Always allow for the site
imap_mailRead and tidy your Gmail, Naver Mail, Daum Mail, Kakao Mail, iCloud Mail or Yahoo Mail with the app password you saved in a card in the chat, and leave mailing lists when you ask. It changes mail only through the cleanup card you apply, and never sends or deletes. See Mail from Gmail, Naver, Daum, Kakao, iCloud and Yahoo
site_policyWhen you tell Foxl never to sign in to a site ("never sign in to coupang.com"), add it to the Web Access blocked list at once, with Undo on a line under the reply. Settings > Web Access lists these under Sites Foxl never signs in to. In your own chats only

Web search is the model provider's own search, not a Foxl tool, so it exists only where the provider runs one. On GPT-5.5 and GPT-5.4 through your own AWS account, the model searches with Amazon Bedrock Web Search when a question needs current information, and cites the pages it used; the searches stay inside AWS and are billed by AWS. Claude and GPT-6 models on Amazon Bedrock have no web search there, so with them the agent reads pages with web_fetch or the browser. Turn it off with the Web search switch in Settings > Web Access.

An answer that read web pages lists them under the answer as N sources: the pages it opened with web_fetch, its own browser or the Chrome extension, and the pages the model's own web search cited.

Memory

ToolDescription
memory_saveSave key-value pairs to the SQLite memory database
memory_recallSearch and retrieve from the memory database
workspace_memory_saveSave content to workspace markdown files (USER.md, MEMORY.md). Asks first, unless you auto-approve it
workspace_memory_searchSearch across all workspace markdown files
workspace_memory_readRead a specific workspace file
workspace_memory_editEdit sections within workspace files. Asks first, unless you auto-approve it. SOUL.md, HEARTBEAT.md and AGENTS.md change only when you ask in your own chat, with Undo on the card under the reply; after it read a page, a mail or a tool result in that turn, the change waits for your tap on Apply
conversation_searchSearch your own past conversations by content, so the agent can find what you decided last week
read_threadRead a Foxl conversation the agent was pointed at, newest turns first
notes_searchSearch your Foxl Notes meetings and notes, transcripts included, and read one in full. Offered while Let Foxl Agent search your notes is on in Settings > Notes; each note an answer used is listed under it as a source
integration_saveAdd what made a site or web API work (endpoints, steps, quirks) to its entry under Added by Foxl, once this chat reached it and its sign-in or key is saved in the vault on your computer, so the next task there starts from it. A site with no saved sign-in or key is not kept. A password, key, token or cookie is refused. No prompt: the note holds no secret
integration_readLook a website or API up by name or address before working with it, and read what was learned there before
writing_styleLearn how you write from messages you paste or your sent Outlook mail, show you the style, and save it per audience, with Undo on the card under the reply. In your own chats only. See Writing style

With Save memories off in Settings > Memory, the agent gets none of the memory_*, workspace_memory_*, integration_* and writing_style tools, nor request_login and fill_login. What integration_save keeps stays on your computer; see Security.

Scheduling

ToolDescription
scheduleCreate, list, update, delete, and trigger schedules (one-time, cron, webhook, and watches that wait for something on a page; the Feed Generator heartbeat is set up in Settings). Creating or changing one asks first, unless you auto-approve it
event_triggerSet up, list, pause, resume and delete triggers: new mail in Outlook, a new message in a Slack channel, or new mail in a mailbox Foxl reads with an app password (Naver Mail, iCloud, Gmail by app password and others) starts a run. It starts at once, with Pause and Delete on its card; one set up after the chat read a web page, an email or a command's output waits for your Start on the card (Settings > Safety can ask before each one starts). In your own chats only, and offered only while one of those can be read or a trigger exists
check_insSee or change when your check-ins run ("check in twice a day", "not before 9"), or pause them until a date. In your own chats only
feed_addHeartbeat runs only - posts an item to your For You feed; urgent also raises a system notification. Never offered in a chat

Agent

ToolDescription
session_statusGet current date/time, timezone, and session info
sessions_spawnSpawn an autonomous sub-agent for a parallel task (at most 5 at once, across all chats)
sessions_statusCheck sub-agent progress
sessions_stopStop a running sub-agent
sessions_messageMessage a sub-agent: a running one reads it at its next tool call, a finished one resumes with it. See Sub-agents
agent_roleMake a role (a sub-agent definition) from a chat: shows you the role and saves it, with Undo on the card under the reply. In your own chats only. See Making a role from a chat
skill_importTurn a workflow from the chat, or a skill you point it at, into a skill: shows you the whole skill and saves it, with Undo on the card under the reply. In your own chats only. See Skills
skill_saveWhen a job took several steps, you will ask for it again and no skill you have covers it, save it your way as a skill at once, with Undo under the reply. After a read from elsewhere, a skill that names an address you did not write waits for your tap, and a channel thread does not save one. In your own chats and your own channel threads only. See Skills
update_planThe checklist for a task with several steps, pinned above the message box and updated as the agent works. For the main conversation only - a sub-agent reports its progress in its result instead - and not available on a Claude Pro/Max sign-in
report_issuePass a problem to the Foxl team when you tell the agent something in Foxl went wrong. The report is shown as a card under the reply with exactly what it sends, and nothing is sent until you press Send: Edit changes its words first, and Not now keeps it unsent, with Show report to bring it back; the chat's last messages go with it only if you tick Attach the last messages of this chat, which shows them first. Don't ask again sends it and lets Foxl on your computer send later reports itself, without the chat's messages; the card then shows each one as sent, and Settings > Safety > Don't ask again removes it. In your own chats only - not in schedules, channels or sub-agents - and not available on a Claude Pro/Max sign-in or the on-device model; use Settings > General > Report an issue there
offer_repliesWhen a reply ends with a quick question ("Want me to dig in?"), offer up to three short answers as buttons under it in the phone apps and a phone's browser; a tap sends the answer word for word as your message. In your own chats only, and not on a Claude Pro/Max sign-in or the on-device model

Computer use

ToolDescription
computer_open_appOpen an app the agent may use. It does not ask first unless Settings > Safety > Ask before Foxl uses an app for the first time is on; then the first time a chat needs an app, Foxl asks in the chat (Deny, Allow, Always allow)
computerLook at a screenshot of that app's window only, and click, type, press keys and scroll in it with Foxl's own pointer
computer_elementsRead that app's window as a list of its controls (buttons, fields, checkboxes, menus) and press, fill, pick, check or expand one by name, checking each result, without a screenshot. On macOS and Linux

They are offered only while Allow computer use is on in Settings > Computer use (on by default), and only to a model that can view images, because computer_open_app and computer answer with screenshots; with any other model the agent says so and suggests switching. computer_elements is not offered on Windows. See Computer Use.

Integrations

Integration tools are only available after you connect the corresponding account in Settings > Tools > Integrations.

ToolActionsDescription
outlook25 actionsEmail (inbox, read, send, reply, forward, search, folders, drafts and reply drafts in the original conversation, sending a reviewed draft once, attachments, contacts, move, categories, update, tidying the inbox at once with Undo, and leaving mailing lists), Calendar (view, meeting, availability, room booking, search, shared list), To-Do (lists, tasks, checklist) via Microsoft Graph API
slack16 actionssearch_messages, whoami, get_recent_messages, channels_list, conversations_history/replies/add_message/open/members, check_replies_batch, users_lookup/profile_get, attachment_get_data, reactions_add/remove, file_upload
gmail1 action (4 with reading on)send: an email from your Gmail address to at most 25 recipients, plain addresses only, with no attachments. Send only unless you turned reading on when connecting: then also search, read and reply. It never deletes or changes mail. See Gmail

These tools use OAuth user tokens - they act as you, not as a bot. Connect them under Settings > Tools > Integrations.

Tidying your inbox. Ask Foxl to clean up your inbox, in Outlook or in a mailbox it reads with an app password (Gmail, Naver and the others), and it makes the changes right away: archive, move to a folder, flag or mark as read. The card that follows lists each message it changed, with who sent it, its subject and the change, and Undo on each one and Undo all put messages back, on your computer and your phone, for a day, also after Foxl restarts. Undo leaves a message you changed in your mail app since then as it is, and the card says so. Foxl never deletes mail: a move into the trash (Deleted Items in Outlook), Junk or Spam (your mail service deletes mail there on its own), sent mail, drafts or the Outbox is refused.

To check every change before anything happens, turn on Settings > Safety > Review inbox clean-ups before Foxl applies them. The card then comes first instead: uncheck anything you disagree with and press Apply, and only the checked messages change, once. See Steps that always ask.

Leaving mailing lists. Ask Foxl to unsubscribe you from newsletters or promotions, in Outlook or in a mailbox it reads with an app password, and it does it right away. A card under the message then shows, for each sender, what was done. Foxl uses only the unsubscribe address the sender put in the message's own headers. It never follows a link in the message's text, because fake "unsubscribe" links are a common phishing trap.

  • One-click unsubscribe: Foxl sends the sender's one-click request. It does this only when the sender's digital signature on those headers checks out.
  • Unsubscribe by email: in Outlook, Foxl sends the email from your account. It does this only when the address is at the domain that signed the headers. In a mailbox Foxl reads with an app password, the card shows the address for you to write to.
  • Unsubscribe page: the card links to it for you to open. Foxl never opens it itself.

Foxl leaves a list only when you ask in your own chat, never because a schedule, a check-in or a message asked it to.

Connecting a service from the chat

When a task needs a service that is not connected yet, Foxl asks for it in the chat with a Connect card that names the service (request_connection). It does this for Microsoft 365, Slack and Gmail, and for seven services that run their own MCP server: Linear, Notion, Atlassian (Jira, Confluence, Trello), Granola, Canva, Sentry and Todoist.

  • Asked in your own chat on your computer, there is nothing to click first: the service's own sign-in page opens in your browser at once, and that page is where you decide. For one of the seven MCP services, Foxl first adds that service's own MCP server to the Custom tab (or switches on the one you already have for it), and its page is where you choose what Foxl can use. Once you finish, the card says Connected (service) with Disconnect, and Foxl goes on with the task, using the service's tools in the same chat. If you refuse on the service's page, a server Foxl added for it is taken away again; if you do not finish signing in, the server stays on the Tools page with Sign in, and the next request picks it up from there. If the page cannot open by itself, the card says so and shows Connect.
  • Asked from a phone or app.foxl.ai, the card has Connect too for Linear, Notion, Atlassian, Granola, Sentry and Todoist, and for an MCP server whose sign-in expired. The service's sign-in page opens on the phone (in the app's sign-in sheet, or a new tab in a phone's browser); once you finish there, your phone passes the result to Foxl on your computer, which completes the connection, and the task goes on. This needs this version of Foxl on the phone and the computer, the phone's secure connection to your computer, and your computer signed in to Foxl and online. For Microsoft 365, Slack, Gmail, Canva and a server that refuses a sign-in from a phone, the phone's card says Finish on your computer, and Foxl on your computer shows the same request: click its notification, or Connect on its card, and the sign-in page opens there. Not now on the phone stops waiting.
  • A request from a channel thread, a schedule or a trigger waits for Connect on your computer: no sign-in page opens by itself for a run you did not start.
  • Disconnect on the card removes the account, as Disconnect under Settings > Connect > Integrations does, or for one of the MCP services signs its server out, as Sign out on its Tools row does. It works from the phone too.
  • Asana, HubSpot, Figma and GitHub get no card: their servers do not let an app register itself for the sign-in.

Mail from Gmail, Naver, Daum, Kakao, iCloud and Yahoo

Ask Foxl to read your Gmail, Naver Mail, Daum Mail, Kakao Mail, iCloud Mail or Yahoo Mail ("show me what's in my Naver Mail", "did my train ticket arrive by email?") and it reads it over IMAP with the imap_mail tool. No account to connect in Settings first:

  • The first time, Foxl asks in the chat with a card titled (service) app password: your email address and an App password, with Where do I get this? linking to your mail service's own page for making one. They are saved on your computer, and Foxl's AI never sees the password; it is used only to read your mail from that service's mail server.
  • Reading changes nothing. It lists your folders, finds messages by date, sender or subject (or only unread ones), and reads a message's text and the names of its attachments. Reading a message does not mark it as read, and it never sends or deletes mail. It connects only to that service's own IMAP server, over TLS.
  • Cleaning up your inbox works as in Outlook (see Tidying your inbox above): the changes are made at once, with Undo on the card that follows. Archive puts a message in the folder your mail service marks as its archive; in Gmail that is All Mail, which takes the message out of the inbox. A service that marks no archive folder is offered moves to its own folders instead, and one that cannot move a message in one step, or does not say which folder is its trash, gets only flag and mark as read.
  • When the service refuses the password, Foxl tells you what to check and asks with the card again (Enter the (service) app password again) instead of trying again on its own. Every one of these services signs a mail app in with an app password, not your account password; Naver, Daum and Kakao also need two-step verification on the account and IMAP turned on in their mail settings. Gmail makes app passwords only for an account with 2-Step Verification on, and a work or school Google account may not offer them.

Mail you read this way is treated like Gmail's: as data written by its senders, not as instructions.

Channels

ToolDescription
channel_sendSend messages to connected channels (Telegram, Slack, iMessage and the others), and files to Telegram (up to 50 MB); on the other channels a file is refused. Asks first, unless you auto-approve it; a file outside your workspace or a recipient outside the channel's allowlist is refused either way

Media

ToolDescription
generate_imageGenerate or edit PNG images with gpt-image-2 through your ChatGPT Plus/Pro subscription. Pass inputImages paths to edit or compose from existing images; omit for pure text-to-image. Auto-saved as generated/generated-<YYYY-MM-DD>-<slug>.png inside your workspace (~/.foxl/workspace/ on an installed app).

generate_image uses your ChatGPT subscription, not an OpenAI API key. The tool only registers when an OAuth credential file is found at ~/.codex/auth.json, ~/.chatgpt-local/auth.json, or the path set by CODEX_HOME / CHATGPT_LOCAL_HOME. No billing beyond the ChatGPT plan you already have.

Image editing and composition

Pass one or more existing image paths as inputImages to switch from text-to-image into edit / compose mode. When you drag images into the chat, Foxl saves them with the conversation (in ~/.foxl/data/attachments, outside your workspace) and injects the absolute paths into your message, so the agent can reference them without base64 round-tripping through the model's tool-call args.

Examples the agent can drive end-to-end:

PromptWhat the agent does
"이 사진 만화풍으로 바꿔줘" (attach a photo)Calls generate_image({ prompt: "convert to watercolor anime style", inputImages: ["<path>"] })
"이 두 이미지 합쳐서 하나로" (attach 2+ photos)Calls generate_image({ prompt: "compose both subjects into one scene", inputImages: ["<a>", "<b>"] })
"blog hero: a cozy cafe at dusk, 1536x1024"Calls generate_image({ prompt: "...", size: "1536x1024" })

Up to 10 input images per call. Output PNG lives at a date-stamped filename with a slug derived from the prompt, in a generated/ subfolder to keep your workspace root clean.

AI-generated label

A picture generate_image makes says so twice. Inside the file, the saved PNG and the preview you download or share from the chat carry the IPTC "Digital Source Type" tag for "Created using Generative AI"; an image that already arrives with its maker's signed Content Credentials saying so is saved exactly as it came. In the chat, the picture carries a small AI-generated label in its corner, on its thumbnail when the steps around it are folded, and in the viewer it opens. A picture you attached, or a screenshot the agent took, has no label.

Tool Profiles

Foxl uses tool profiles to control how many tools are loaded, saving tokens in the system prompt. A tool definition costs roughly 200 tokens, so the profile is a direct trade of capability against every turn's input:

Settings > Tools > Tools/MCP on the System tab: System tools, 51 of 51 enabled with the Full profile, and the Memory group of tools with their switches.

ProfileToolsToken CostWhat it adds
Minimal13~2,600memory, workspace memory, conversation and notes search, thread reading, session status, view image, the problem report, quick replies
Default25~5,000+ file read/write/edit, exec, process, the skill key card, the plan checklist, channel send, generate image, skill import and skill save, writing style
Standard34~6,800+ code search, web fetch, terminal, the two website-memory tools (integration_save, integration_read), the sign-in card and fill (request_login, fill_login), the mail reader (imap_mail) and never-sign-in (site_policy)
Full45~9,000+ browser, browser extension, browser take-over, schedule, check-ins, triggers, sub-agents, roles (and the three computer use tools while computer use is on)

The profile picker's own labels (about 1.4k to 4k tokens) were written when the profiles held fewer tools; the table counts today's tools at about 200 tokens each.

A tool whose credential or switch is missing is not sent even when its profile includes it: generate_image needs a ChatGPT sign-in, notes_search the Notes search switch, the memory and website-memory tools Save memories, the computer use tools Settings > Computer use, request_skill_key a skill that declares a key, and event_trigger Microsoft 365, Slack, a mailbox with a saved app password, or a trigger you already have. offer_replies, report_issue, writing_style, check_ins, event_trigger, site_policy, agent_role, skill_import and skill_save work only in your own chats.

The agent runs in Full profile by default. Switch profiles on the System tab of Settings > Tools > Tools/MCP to save tokens on simpler tasks; the same tab lists every built-in and lets you switch one off. In a language other than English it describes each built-in tool in that language, and searching it still finds a tool by its English description. generate_image lives in the media category and is included in Default, Standard, and Full; Minimal omits it to preserve its token budget.

Integration tools (outlook, slack, gmail), the Connect card (request_connection) and the phone call tool (phone_call) are not counted above; they are in every profile except Minimal, the integration tools once their account is connected and phone_call on a Mac. The profile is the upper bound for built-in tools, including the ones a skill asks for: a skill cannot switch on a tool the profile leaves out. Your own custom tools and MCP tools are not filtered by the profile - a tool you wrote or added is available whichever profile you are on.

Git operations route through exec (e.g. exec git status, exec git push). There is no dedicated git tool - piping and custom flags work better from exec anyway, and exec's own approval rule covers them.

The same tools in Foxl Notes

The same tools serve Foxl Notes. On the desktop, Notes' AI Assistant is a Foxl Chat conversation beside your note, with the same tool steps as chat: it can open your files, search your code and notes, fetch a link or run a command - whatever the System tab has switched on, custom tools and MCP servers included. The Live panel's AI Assistant is the same conversation, so questions asked there and in the main window land on one thread. One switch governs both, Settings > Notes > AI features > Use Foxl Agent tools, on by default; with it off the assistant reasons about the transcript alone. It needs Foxl running on your computer. The automatic work - the post-meeting summary, the auto title, live translation and dictation clean-up - deliberately uses no tools, so nothing you were not waiting for got slower.

Custom tools

Beyond the built-ins you can add your own on the Custom tab of Settings > Tools > Tools/MCP, which also lists your MCP servers. Six kinds:

TypeWhat it is
shellRuns a shell command.
scriptEvaluates JavaScript.
fileReads or writes a file, from a path template.
httpCalls an HTTP endpoint.
mcp_localAn MCP server started as a local process (stdio).
mcp_remoteAn MCP server reached over HTTP.

The Custom tab of Settings > Tools > Tools/MCP with no custom tools yet: Import MCP servers, Export, Import and Create Tool.

A custom tool that runs a shell command, evaluates JavaScript, or writes a file is gated exactly like the built-in exec tool. That was not always true: the approval gate matches on a tool's name and treated an unrecognised name as allowed, so a custom tool wrapping a shell command was a shell with no per-call prompt - and it is the model that fills in the arguments.

A new install auto-approves every tool, so in the shipped default these calls do not prompt either. Turn that off in Settings > Safety and the per-call prompts appear for custom tools and built-ins alike; a rule you set yourself for a specific tool always wins. Read-only file tools, HTTP tools and calls to MCP tools are unaffected either way; for an MCP server, switching the tool on is the approval (the MCP servers section below explains). See Security.

A file tool's blocked-path list is applied to the path it actually opens, not to the template - so ~ is expanded first (a ~/notes.md template works), and /etc/passwd spelled //etc/passwd, reached through .., or under macOS's /private/etc is covered.

An http tool encodes the values the agent fills into its URL, so a value cannot add query parameters, cut the address short or climb out of the tool's path with ... A value in the path can still span segments, such as users/123 for https://api.example.com/{{endpoint}}. A tool with saved headers (where an API key usually goes) sends them only to the host written in its URL: when a parameter chooses the host, the call is refused with a message saying how to fix the tool. A tool with no saved headers whose host or base address comes from a parameter can reach public websites only.

Saved secrets show as dots. The Custom tab shows the saved API key, environment values and headers of an MCP or HTTP tool as dots, on your computer and through your phone or app.foxl.ai. Saving with the dots left in place keeps what is stored; type a new value to replace one. On your computer, an MCP server that is switched off still shows its environment values, so you can see what switching it on will start.

Foxl's database keeps those keys, environment values and headers only encrypted: a plain copy an earlier version saved is removed the first time Foxl reads that tool (an MCP server's entry in settings.json, below, still holds its environment values and key as you wrote them). If Foxl can no longer read them, for example after moving to a computer without your old key file, the tool says so and asks you to edit it in Tools and enter them again, instead of running without them.

Permission rules accept hyphens in a tool name. A custom tool called deploy-prod keeps its name, and every MCP tool is exposed as <server>__<tool> where the right half usually has one, so a rule written with an argument pattern like deploy-prod(rm *) matches instead of being stored under a name no tool is ever called.

MCP servers

Foxl is an MCP client. It speaks the current 2026-07-28 revision and every older one, and asks each server which revisions it supports so the newest one both sides know is used:

RevisionShape
2026-07-28Stateless - no connection handshake, no session header.
2025-11-25, 2025-03-26, 2024-11-05The older handshake.

There is nothing to configure either way. The server's row on the Custom tab shows which revision was agreed, so a server on the new stateless protocol is visibly different from one on an older one.

Import MCP servers on the Custom tab adds the servers you already set up in another app: Claude Code (~/.claude.json, the servers added with user scope), Claude Desktop (claude_desktop_config.json, macOS and Windows), Codex (~/.codex/config.toml), Cursor (~/.cursor/mcp.json), Kiro CLI (~/.kiro/settings/mcp.json, and the servers in its agent files under ~/.kiro/agents/, where an agent you installed keeps its own) and Gemini CLI (~/.gemini/settings.json). Foxl reads those files on your computer and shows a checklist; tick the servers to add. Local servers keep their command, arguments and environment, remote ones their URL and an Authorization: Bearer key. What Foxl cannot carry over is listed under the server rather than dropped: a working folder (cwd), a Cursor envFile, other headers, a bearer token Codex reads from an environment variable, the tools Kiro hides with disabledTools, and a $VARIABLE that Gemini CLI fills in from your environment. A server several Kiro agents define differently is offered once, with a note naming the other agents. A server switched off in Codex, Kiro or Gemini CLI arrives switched off. The same import is part of Settings > Advanced > Import and export, which also brings over Claude Code's or Codex's instructions and skills.

Your servers in settings.json. Foxl keeps your MCP servers in ~/.foxl/settings.json (%USERPROFILE%\.foxl\settings.json on Windows) as well, in the mcpServers format Claude Code, Cursor and Kiro use, so a block can be copied in or out and an agent can add a server by editing one file:

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": { "GITHUB_TOKEN": "..." }
    },
    "linear": {
      "type": "http",
      "url": "https://mcp.linear.app/mcp",
      "headers": { "Authorization": "Bearer ..." }
    },
    "slow-build": { "command": "node", "args": ["build.mjs"], "disabled": true, "toolTimeoutSec": 120 }
  }
}
  • A server you add, change or import on the Custom tab is written to the file. Foxl reads an edit of the file within a few seconds, so the agent's next message can use it, and the Custom tab shows it when you come back to the window. Everything else in the file, and any key Foxl does not use (Kiro's autoApprove, say), is kept.
  • A server the file adds is saved switched off, and so is one whose command, arguments, environment or URL the file changes. Its row says it was added or changed in settings.json and shows the command or URL it would start; it starts when you switch it on from the Tools page on this computer. If the file changes it again while the page is open, the switch (and the Play button) asks you to look again first. If the file goes back to the command or URL you had switched on, the server is switched on again. Switching a server off ("disabled": true), a description and toolTimeoutSec (seconds) apply directly.
  • Taking an entry out of the file removes that server once the entry has stayed out for 15 seconds, so a cut and paste, or a quick checkout of another version of the file, removes nothing. A server removed this way comes back as it was (switched on, still signed in) if its entry returns under the same name with the same command or URL within a day. Renaming a key renames the server when its command or URL stays the same; with a new one it is a new server, saved switched off.
  • Deleting the file, or the whole mcpServers block, removes nothing: Foxl writes your servers back. So does an edit that leaves out every server at once and puts something else there (an agent writing the whole file to add one server); the Custom tab says so. To remove them all, write "mcpServers": {}.
  • A file that is not valid JSON is neither read nor written: the Custom tab says which line the error is on, and Foxl leaves the file alone until it reads again. A file you made read-only is read as usual, but Foxl does not write to it, and the Custom tab says so. A single entry Foxl cannot use is listed with the reason and left as you wrote it.
  • The file holds environment values and keys as you write them, like the files it copies from. Foxl creates it readable only by you. ${VAR} references are not expanded, and the Custom tab names an entry that uses one.

Signing in to a remote server. A remote MCP server that asks you to sign in shows Sign in on its row. One click opens the server's sign-in page in your browser; once you approve there, the row connects and lists the server's tools, with no key to paste. Foxl renews the sign-in on its own, and Sign out removes it from this computer (it does not revoke the grant at the server). When a sign-in stops working during a task (the server refused to renew it), the step that needed it shows a Sign in to (server) again card in the chat, which opens the server's sign-in page the way the Connect card in Connecting a service from the chat does; once you approve there, the step runs again. A new chat still reaches a server that is signed out: Foxl offers it one sign-in step in place of its tools, so asking for something that needs the server brings up the same card, and the server's tools are added to that chat once you are signed in. If signing in fails, the row says which step failed and shows the server's own message. It works with servers that let an app register itself during sign-in, including a server that describes its sign-in the older way (the MCP 2025-03-26 revision's), such as Atlassian's, which offers Sign in too instead of an error. The sign-in is kept on this computer, is not sent to the phone or app.foxl.ai, and is started from Foxl on the computer itself. For the services in Connecting a service from the chat, the chat's Connect card adds the server and starts this sign-in for you.

Tool call timeout. A call to an MCP tool waits 30 seconds by default. A server whose tools are slow by design (a build, a crawl, a report) can be given up to 600 seconds (10 minutes) in its row's Tool call timeout field; Codex's tool_timeout_sec is carried over on import, and a Codex server without one keeps Codex's own 60-second default.

Images reach the model. A picture an MCP tool returns, such as a screenshot from Playwright MCP, is sent to the model as an image it can see and shows in the tool step, like view_image. On a ChatGPT sign-in it goes in the message after the tool's result, the way a picture you attach does.

Resources. A server that says it offers resources (documents, records or files it lets an app read) gets one more tool, <server>__resources. Its list action returns the ones the server lists, a page at a time, with the URI templates the server accepts (such as tickets://{id}); read returns one by its URI: text as text, up to 100,000 characters per answer, with each answer saying where to continue so a long document is read in parts; a PDF as its text (the same reader file_read uses, on macOS and on Linux with pdftotext); a picture as an image the model sees; and any other file saved in the chat's files (mcp-downloads/<server>/ in the workspace), with its path, so you and the agent's other tools can open it. When one of the server's tools answers with a link to a resource, the agent opens it with the same tool, also when list does not show that resource. A server that offers no resources, or whose only listed resources are the screens an MCP App shows inside its host (ui://), adds no tool, and switching the server off removes this one with the rest. A server on your computer can answer with up to 64 MB at a time; a larger answer ends that call with a message saying so, and the server starts again on its next use.

Prompts. A server that lists prompts (message templates for tasks it knows, such as summarizing a ticket) gets one more tool, <server>__prompts. Its list action returns each prompt's name, description and arguments; get fills one in with its arguments and returns its messages, which the agent uses when they fit what you asked. The server's words never outrank yours. A server that lists no prompts adds no tool.

Turning a tool on is the approval. An mcp_local row is a program on your computer, and once the row is switched on Foxl starts it without asking - when you save the row, re-check it, open it in the inspector, or the agent uses one of its tools. You switch an MCP tool on in Foxl on this computer, or from your phone (the Foxl app on your phone, a phone's browser or app.foxl.ai, while this computer is connected). On the phone the row then says what runs (the command, or the address it connects to), the names of its settings with their values hidden, and the tools Foxl can now use, with Switch off. A server that settings.json or an import added shows that same list before it starts, and a server imported from the phone waits switched off for it. A server added or changed from any other client, or by an edit of settings.json, is saved switched off, with a note saying so, and the agent does not see its tools until you switch it on. With Settings > Safety > Only this computer can widen what Foxl may use on, a server saved from the phone is saved switched off too, until you switch it on in Foxl on this computer. An edit that leaves the command, arguments, environment and URL alone keeps a switched-on server running. An mcp_remote row is a URL - nothing is started on your computer, and the same rule decides who can switch it on.

Three things worth knowing:

  • A local server keeps running between calls. An mcp_local server is started once and reused for later calls, so a server that keeps state in its process keeps it: with Playwright MCP, the page browser_navigate opened is the page browser_take_screenshot captures. Your own chats keep one server running between calls; a channel thread (Telegram, Slack, iMessage and the others) or a scheduled run gets its own server, which stops when that run ends, so a message that arrives through a channel never sees a page your chat opened. If such a run needs a server your chat holds idle, your chat's server is restarted, and its next call starts fresh. Playwright MCP started without --isolated keeps one browser profile on disk (with its logins), and only one process can hold it: while a channel or scheduled run is using it, a call from your chat or from another run answers "Browser is already in use", and so does a run's call made while a call from your chat is still running. Add --isolated to its arguments if channels or schedules use it too. Your chats' server stops after 15 minutes without a call, and any server stops when you switch its row off, change its command, arguments or environment, or delete it, and when Foxl quits. On macOS and Linux it also stops when Foxl's server crashes or is force-quit, including a server (or a wrapper script around one) that was still starting up. With Keep running when closed on, the background service keeps running after you quit, so your chats' server stops after those 15 minutes instead. If it crashes, the next call starts it again.
  • A long tool list is read in full. Servers may hand their catalog over in pages; Foxl walks every page rather than reading the first one and treating it as the whole list.
  • A slow tool is not called twice. When a tool took longer to answer than the app was willing to wait, the app used to assume its guess about the protocol was stale, reconnect, and send the same request again - so a tool that sends mail sent it twice while the agent saw one call and one error. It now retries only when nothing can have reached the server, or when the request is a read that cannot have an effect.

Approvals

Which calls ask first is set in Settings > Safety. The full rules are in Security; in short:

  • Auto-approve all tools is on for a new install, so scheduled runs, runs from your phone and channel messages never wait on a prompt nobody is there to answer. The switch's own description says what that costs: anything the agent reads can lead it to run a shell command without asking. Turn it off and shell commands, file writes and other risky tools ask first. While it is off, the message box shows a small Asks first label; click it to turn auto-approve back on or to open Safety settings.
  • Built-in rules (read-only) lists the rules Foxl ships. Built-in blocks still apply while Auto-approve is on; built-in prompts are skipped. In a language other than English, hover a rule for its explanation in that language.
  • Two kinds of step ask every time, even with auto-approve on: a mail or a message that carries a card number, a Korean resident registration number or a US Social Security number (the card names where it goes and the number masked), and a step in the browser tools that sends money, moves it between accounts or buys or sells shares or crypto (the card names the amount and the site). Nothing happens until you answer, and Foxl never goes ahead after a countdown. Typing such a number into a page goes ahead at once unless Ask before sending a card or ID number is on in Settings > Safety. In chats you start in Foxl on your computer, the first kind's Don't ask again covers one thing only: the same card or Social Security number (by its last four digits), or a resident registration number (by its kind), sent to the same recipients. A transfer and a trade never offer it. See Steps that always ask.
  • An ordinary purchase goes ahead, and one you cannot take back asks first. A click or an Enter in the browser tools that orders, pays or books ("Place order", "Pay", "Confirm booking", a priced "Reserve") runs with no card of its own, and so does a subscription, a plan change, a refund or a cancellation; the chat then shows what was bought. A purchase shows its card first when the page says it cannot be undone, the chat opened another site or read outside text first (a site it reached only through a link on a page is not counted yet), it comes from someone else's channel thread or a run nobody is watching, or it is over a limit you set in your own words ("up to $80"; see the browser's safety measures). So do a subscription and a step Foxl cannot tie to one button on a checkout; a cancellation and a refund show it only in those runs and after such reading, and a step on a page Foxl could not read only in those runs. A purchase that a shell command sends (curl, wget) shows its card every time, with no Always allow. The switches under Settings > Safety > Purchases, all off by default, bring the card back every time: Ask before purchases, Also ask when Foxl cannot tell which button a step presses and Ask before subscriptions, plan changes, refunds and cancellations. Allow covers that one step: no card offers Always allow purchases. Only the Foxl window on your computer can turn one of these switches off.
  • By where a run comes from sets Full access, Ask first or Read only for your chats, schedules and the heartbeat, channels (Telegram, Slack, iMessage and the others), and the Notes assistant. All four start on Full access. Check-ins and the brief, and runs started by incoming mail or messages, follow the schedules row until you choose otherwise, and still ask before sending, paying or a step that could carry what they read off your computer (details).
  • Run shell commands in a sandbox (macOS and Linux, off by default, with Allow network) limits what exec and the agent's terminals can reach.
  • A prompt can be answered in Foxl on the computer, or in the Foxl app on your phone or on app.foxl.ai while it is connected to that computer. On a Mac, the notification for a waiting prompt has a Deny button; to allow, open Foxl and answer there.
  • Not now waits. In your own chat, Not now on the phone's approval card, or no answer within a minute, leaves the step Waiting instead of refusing it: it did not run, and the agent carries on with what does not need it. The step stays in its chat (and in the phone's "waiting for approval" count) for 12 hours, also across a restart. Approve or Allow later runs exactly that step, with the same arguments, and the chat continues; a different step asks again. When the 12 hours pass, the chat says the step expired and nothing ran.
  • A schedule's or a check-in's step waits the same way, in that run (open it from the Schedules page or from the run's post in the From Foxl chat), also when nobody is at Foxl to ask. Approve later makes exactly that step once, after the run has ended, and the run says what came of it. That turn makes nothing else: ask there for anything more the run needed.
  • Computer use, a step that asks before it pays, books or moves money, a sign-in, the heartbeat watch, the Tools page and channel runs never wait: there Not now refuses, as before. (A Sign in to card that asks for a sign-in you have not saved is different: in your own chat its Not now waits; see Sign-ins and saved keys.)
  • When Foxl asks in your chat while you are away from the computer, your phone gets a notification that names only the kind of step ("Foxl needs your OK to send an email"), under Questions and approvals in the app's notification settings. The check-in names the steps still waiting in the From Foxl chat ("Still waiting for your OK: run a command in storefront").
  • Hooks (below) are listed at the bottom of the same pane.

Hooks

Hooks are your own commands that Foxl runs when you send a message, when a chat starts, before and after a long chat is compacted and around tool calls, written in the Claude Code hooks format so an existing hooks block can be copied in. Put them in ~/.foxl/hooks.json (%USERPROFILE%\.foxl\hooks.json on Windows):

{
  "hooks": {
    "PreToolUse": [
      { "matcher": "Bash", "hooks": [ { "type": "command", "command": "~/.foxl/block-rm.sh", "timeout": 30 } ] }
    ]
  }
}
  • PreToolUse runs before a tool call, with the event as JSON on stdin (tool_name, tool_input, tool_use_id, session_id, cwd). Exit code 2 blocks the call, and what the command printed to stderr is the reason the agent reads; a JSON permissionDecision of "deny" on stdout blocks too, and "ask" shows the usual approval prompt for that call, as an ask rule would, even with auto-approve on. Any other non-zero exit is logged and the call goes on.
  • PostToolUse runs after a call with the result as tool_response. Exit code 2 adds its stderr to the result the agent reads; the tool has already run.
  • Stop runs after each finished turn of a chat or a channel reply, with last_assistant_message, for notification and logging. It does not run after a subagent, a schedule or the heartbeat. Unlike Claude Code, exit code 2 does not make the agent continue.
  • UserPromptSubmit runs when you send a message, before the model sees it, with your text as prompt on stdin. What it prints (or a JSON hookSpecificOutput.additionalContext) is added to that message for the model, and is not shown in the chat. Exit code 2, a JSON "decision": "block" or {"continue": false} blocks the message: the model never gets it, the conversation does not keep it, and the chat shows the hook's stderr, reason or stopReason, followed by your text unless the hook sets suppressOriginalPrompt. It runs for your chats on this computer, also when you type from your phone or app.foxl.ai, and for your own messages in a connected channel; not for other people writing to you there, also when that channel lets them use your full agent, and not in the Notes assistant or Foxl Code. In a group chat, the reply to a blocked message says only that a hook blocked it. A message you type while the agent is working runs the hook too: one it lets through reaches the agent at its next step, and one it blocks is sent on its own when the turn ends, which shows the block. Matchers have no effect on this event, as in Claude Code.
  • SessionStart runs when a chat starts, with source saying how, as in Claude Code: "startup" for a new chat's first message; "resume" for the first message in a chat after Foxl or the computer restarted, and after the version arrows put another version of the chat on screen; "clear" for a chat started with /new or /reset, or one whose messages were cleared; "fork" after you edit a message into a new version of the chat; and "compact" right after Foxl compacted a long conversation. The matcher picks the sources, so "matcher": "compact" runs only after compaction. What it prints is added in front of that message, or after a compaction to the summary that replaced the older messages, so the model reads it on its next step. It never blocks.
  • PreCompact runs right before Foxl compacts a long conversation, with trigger set to "auto" and custom_instructions set to null. Foxl compacts on its own and has no /compact, so a group whose matcher names only "manual" never runs. What the hook prints (or a JSON hookSpecificOutput.additionalContext) is added to the instructions for the summary, so you can say what it must keep. Exit code 2 or a JSON "decision": "block" skips that compaction and the conversation goes on uncompacted, as in Claude Code. When the model has already refused the conversation as too long, the block is not honoured: Foxl compacts anyway, so the turn is not lost, where Claude Code would fail the request. For other people's messages in a connected channel the hook still runs, but what it prints is not used.
  • PostCompact runs right after a compaction, with trigger set to "auto" and compact_summary set to the summary that replaced the older messages, for logging or follow-up work. It cannot block and never reaches the model. As in Claude Code, what it prints (or its stderr, when it exits with another code) is shown to you, under the compaction's divider in the chat. A group whose matcher names only "manual" never runs.
  • What these add is limited to ten thousand characters per hook; anything longer is cut, and the model is told it was cut. JSON longer than 64 KB is not read, and adds nothing. When one of them takes more than a second, the chat says it is running a hook, and Stop ends it.
  • Matchers work as in Claude Code: *, empty or omitted matches every tool, a plain name or a | list matches exactly, anything else is a regular expression. They are tested against the Foxl tool name (exec, file_read, ...) and, where there is one, the Claude Code name (Bash, Read, Grep, WebFetch, Write, Edit), so "matcher": "Bash" matches exec. tool_name on stdin is the Foxl name, and tool_input carries the Claude Code spelling of a field beside the Foxl one (file_path beside path), so a hook that reads tool_input.file_path works.
  • Other events and handler types are not run; Settings > Safety > Hooks lists what Foxl loaded and what it does not run. A file that is not valid JSON runs no hooks at all, and says so there. Foxl looks at the file at most once a second, so a change applies within a second, with no restart. With no hooks file, a tool call costs nothing extra.
  • "async": true runs a hook in the background, as in Claude Code: Foxl does not wait for it and its output has no effect. A PreToolUse updatedInput is not applied, so a hook that returns one blocks the call instead of letting the original input run.
  • A handler's "if" filter (such as "if": "Bash(rm *)" or "if": "Edit(*.ts)|Write(*.ts)") decides when it runs, as in Claude Code, and where Foxl cannot tell it runs the handler, as Claude Code does: a Bash pattern is matched against every command on the line (looking through VAR= prefixes, quoting and program paths), a file pattern against the file's path, and a command that builds its own text ($(...), a backtick, $VAR) always runs it. A filter Foxl cannot read runs the handler on every call its matcher names, and Settings > Safety > Hooks says so; on Stop, UserPromptSubmit, SessionStart, PreCompact and PostCompact a handler with "if" never runs, as in Claude Code. {"continue": false} on stdout blocks a PreToolUse call, with its stopReason as the reason the agent reads; after a PostToolUse call it is added to the result.
  • A hook runs as you, with your environment minus Foxl's own session tokens, so treat the file like any script you would run yourself. It runs in the chat's folder when the chat has one (the folder chip in the chat header), and cwd on stdin and the CLAUDE_PROJECT_DIR environment variable name it. The default timeout is 600 seconds, and 30 seconds for UserPromptSubmit, as in Claude Code.
  • How a hook starts follows Claude Code. With "args" it is exec form: command is started directly with args as its arguments, no shell, and ${CLAUDE_PROJECT_DIR} in them is replaced; on Windows command must be a real program such as node (a .cmd or .bat shim cannot start that way). Without "args" the command runs in sh -c on macOS and Linux, and in the Windows command prompt on Windows, as before. "shell": "bash" runs it in Git Bash on Windows, which is where Claude Code runs a hook there by default, so add it to a hook copied from Claude Code on Windows; "shell": "powershell" runs it in PowerShell. "onFailure": "block" blocks the call when the hook cannot start, times out, exits with a code other than 0 or 2, or prints JSON that does not parse. A handler that cannot start as written (an unknown shell, args that are not a list, a program not on PATH) does not run, and Settings > Safety > Hooks lists it; one whose program or shell this computer lacks and that says "onFailure": "block" blocks every call it matches instead, and is listed too.

Skills

Beyond built-in tools, Foxl supports skills - installable capability packages that extend what the agent can do. See Skills for the full catalog.

On this page