FYAI Runner
The FYAI runner (fyai-runner) is a standalone program you run on a machine you control. It connects that machine to one execution environment and carries out the tool calls agents make through it: running kubectl or git, reading files, driving a browser, calling services on your private network, running Claude Code against a local checkout, or calling tools on local MCP servers.
You'll also see it called the Local Execution Agent (LEA) in the app, for example in the chat warning banner.
Key properties
| Property | Detail |
|---|---|
| Connection | Outbound only. The runner opens a WebSocket to FYAI over HTTPS. No inbound ports, port forwarding or public IP needed, so it works behind NAT and VPNs. |
| Identity | A registration token from the environment's page. The runner works out which environment it belongs to from the token. |
| Runs as | You. It inherits your user's PATH, ~/.kube/config, SSH keys and browser profile. No admin rights needed (except the optional Windows --system install). |
| Distribution | A single executable downloaded from the environment's page. It isn't on PyPI or a package manager. |
| Updates | Updates itself in the background (see Updates). |
| Instances | One runner process per machine, and one runner connection per environment. |
Supported platforms
| Platform | Download |
|---|---|
| Linux x86_64 | fyai-runner-linux-x86_64 |
| macOS, Apple Silicon | fyai-runner-macos-arm64 |
| Windows x86_64 | fyai-runner-windows-x86_64.exe |
The environment page also has a macOS (Intel) tab and a Linux aarch64 link. Current releases don't include builds for those platforms, so those downloads may fail or give you an older version.
What the runner can do
When it connects, the runner checks what's installed and announces only the tools that work on that machine.
| Tool | Available when | What it does |
|---|---|---|
shell | Always | Runs any shell command. Unrestricted execution, so it's off unless you allow it. No stdin or terminal, so password prompts fail rather than hang. The whole process tree is killed on timeout (default 300 s). |
kubectl, helm, git, docker, terraform | That binary is on PATH | Runs only that program, without a shell: no pipes, redirection or chaining, and arguments are passed literally. |
file_read, file_write | Always | Read a file, or write/append to one. Limited to the environment's allowed paths. |
http_local | Always | HTTP request to a localhost or private-network service. Requests to FYAI's own hosts and to cloud metadata endpoints are blocked. |
browser | Playwright is available (turn on Install browser tools on the environment) | Headless Chromium with a persistent profile. Supports multi-step sessions (new_session → navigate, click, fill, get_text, screenshot, evaluate_js and more → close_session). |
claude_code, claude_sessions, claude_status | The Claude Code CLI is installed | Runs Claude Code non-interactively in a local directory and returns the result and a resumable session_id. See Claude Code tools. |
server__tool | You configured mcp_servers | Tools from local MCP servers, relayed through the runner. See Relay local MCP servers. |
Run fyai-runner discover on the machine to see what it would announce.
Who decides what runs
The execution environment's settings on the platform are the authority. The platform checks every call against the environment's allow-list and approval requirements before sending it, and on connect it pushes that policy to the runner, which replaces the allowed_tools and file_allowed_paths in the runner's local config file. The runner also refuses any call outside the allow-list it received, so a call that somehow reached it still wouldn't run.
What stays under local control on the machine:
- which MCP servers are relayed, and which of their tools (
allow_tools,deny_tools) - Claude Code limits: permitted permission modes, directories, budget, timeouts
- the browser's domain allow-list and profile directory
- concurrency, output size and update settings
require_approval_for in the local config is a hint only and has no effect. Set approvals on the environment instead. See Control what an environment's tools can do.
shellIf the environment's Tool Access is set to Expose all runner tools (wholesale), the runner exposes every tool it has, including unrestricted shell, file_write and every relayed MCP tool, whatever your local config says. Use an explicit allow-list on any machine that matters.
Claude Code tools
If the Claude Code CLI is installed, agents can hand it real work on a local checkout instead of moving files around one call at a time.
| Tool | Use |
|---|---|
claude_code | Run a prompt in a directory (cwd). Returns the result and a session_id; pass the session_id back to continue the same conversation with full context. |
claude_sessions | list, get or forget sessions this runner started. |
claude_status | Check Claude Code is usable here and what this runner permits. It reports whether auth works, not whose account it is. |
Claude runs as you, with your Claude Code login, model access, CLAUDE.md, MCP servers and skills. The runner looks for the CLI in claude.binary, then FYAI_CLAUDE_BINARY, then PATH, then common install locations.
Limits are set in the claude: block of the runner's config file, not by the platform:
| Key | Default | Meaning |
|---|---|---|
allowed_permission_modes | [default, plan, acceptEdits] | Modes an agent may request. bypassPermissions is refused unless you add it. |
default_permission_mode | default | Used when the call doesn't ask for one. default reads and answers but declines writes and commands. |
allowed_cwds | [] | Directories runs may use. Empty means fall back to the environment's file paths. |
default_cwd | none | Used when a call omits cwd. |
max_budget_usd | 5.0 | Per-call spend ceiling. |
default_timeout_s / max_timeout_s | 270 / 3600 | Per-run time limits. |
allow_config_injection | false | Whether agents may pass settings, mcp_config or agents, which can run arbitrary code. |
The full list is in the runner reference. Refused requests are reported in the result, naming the setting that would allow them.
A tool call made from chat waits at most 300 seconds. If the platform gives up first, the agent gets a timeout with no result and the run is cancelled, losing its session_id. The 270-second default leaves headroom. For long jobs, have the agent make several calls that resume the same session.
Running as a service
fyai-runner install sets the runner up as a per-user background service that starts at login, restarts after a crash and reconnects after a reboot without asking for the token again.
| OS | Mechanism | Logs |
|---|---|---|
| Linux | systemd --user unit fyai-runner.service | journalctl --user -u fyai-runner.service, and ~/.fyai/logs/runner.log |
| macOS | LaunchAgent co.nz.fyai.runner | ~/.fyai/logs/runner.log |
| Windows | Scheduled Task FYAI Runner (runs at logon) | ~/.fyai/logs/runner.log |
On Linux, run sudo loginctl enable-linger $USER once if the runner should keep running after you log out and start at boot. On a Windows server with nobody logged on, use install --system (see the reference).
Updates
A downloaded runner checks for a newer release when it starts and then every 6 hours. When there is one, it downloads it, checks its SHA256, finishes in-flight tool calls (waiting up to 120 seconds), swaps in the new binary and restarts. You can also download a fresh copy from the environment page at any time.
Token storage
The registration token you pass with --token is saved so restarts don't need it: in the OS secret store (Keychain, Credential Manager or Secret Service) when one is available, otherwise in ~/.fyai/credentials with owner-only permissions. fyai-runner forget deletes it.
When the runner stops by itself
The runner retries lost connections with increasing back-off. It stops instead of retrying when:
- the platform rejects the token (expired, rotated more than 24 hours ago, or revoked), or
- the environment has been deleted.
Generate a new token on the environment page and start the runner again with --token.