# A deep dive into fx

> fx is Vercel Labs' coding agent, a small Zig binary. Run it in the terminal, call it from scripts, or embed the same agent in an app.

Author: [Flavio Copes](https://flaviocopes.com/about/) | Published: 2026-09-21 | Topics: [AI](https://flaviocopes.com/tags/ai/) | Canonical: https://flaviocopes.com/fx/

fx is a coding agent from [Vercel Labs](https://fx.sh/about). It is a native binary, written in Zig, and the project is Apache-2.0.

You run it in a terminal, you call it from a script, or you embed the same core in your own app. There is no hosted fx service and no public HTTP API. The binary is the product.

I wrote this against fx 0.0.10, released on 14 September 2026. The project still marks itself experimental, and the binary for that release is about 6.17 MiB, which is also what the homepage says.

![The fx.sh homepage, with the 0.0.10 installer and the experimental label](https://flaviocopes.com/images/fx/homepage.png)

The output scrolls like a shell. fx does not take over the terminal with a full-screen interface, so the scrollback you already have stays readable.

## Install it

fx publishes builds for macOS and Linux, on x86_64 and arm64. There is no Windows build of the CLI.

On a Mac, this installs the latest release into `~/.local/bin`:

```bash
curl -fsSL https://fx.sh/setup.sh | bash
```

On this Mac that printed `installed fx 0.0.10` and put the binary at `/Users/flaviocopes/.local/bin/fx`.

![The installer finishing, with fx 0.0.10 in ~/.local/bin](https://flaviocopes.com/images/fx/install.png)

The script detects the platform, downloads a release archive over HTTPS, unpacks it, and copies the binary. If `~/.local/bin` is not on your `PATH`, it appends a line to `~/.zshrc`. I use fish on this machine, and on fish it edits `~/.config/fish/config.fish` instead.

If you want to read the script before it runs, save it first:

```bash
curl -fsSL https://fx.sh/setup.sh -o setup.sh
less setup.sh
bash setup.sh
```

The installer does not check a signature or a published checksum. The GitHub release for 0.0.10 does ship a `.sha256` file next to each archive, so an audited install can fetch that archive and verify it yourself. Pin the version when a script should not float to whatever was published this morning:

```bash
curl -fsSL https://fx.sh/setup.sh | bash -s -- 0.0.10
```

Set `FX_INSTALL_DIR` if you want the binary somewhere other than `~/.local/bin`.

On Linux the same installer works, including on Omarchy. It picks the arm64 or x86_64 archive for the machine you are on. There is no separate Omarchy package to add.

Then check that the binary is the one you think it is:

```bash
fx --version
fx doctor
```

`fx doctor` reports the workspace, config, auth, and local session state. It does not start an agent turn.

I ran it from my home directory before signing in. Auth was missing, the resolved model was `moonshotai/kimi-k3`, and it warned that `~` is not a git repo.

![fx doctor before signing in, with auth missing and kimi-k3 selected](https://flaviocopes.com/images/fx/doctor-before-login.png)

Upgrade later with `fx upgrade`. Add `--channel stable` or `--channel dev` to remember a channel. Automatic upgrade checks are on by default. `FX_AUTO_UPGRADE=0` skips them for one process. Those checks fetch release metadata. They do not send a machine id.

To build it yourself you need Zig 0.16 or newer:

```bash
git clone https://github.com/vercel-labs/fx.git
cd fx
zig build -Doptimize=ReleaseSafe
./zig-out/bin/fx --version
```

`gh` is only required if you want `fx pr --create` or `fx issue --create` to publish through GitHub. The agent itself does not need it.

You can also open [fx.sh/try](https://fx.sh/try) and run 0.0.10 in the browser. That demo is the CLI compiled to WebAssembly, with a throwaway workspace. It needs JavaScript Promise Integration, which means a current Chrome or Safari 27 or newer. Your files stay where they are until you install the binary.

## Sign in

fx talks to one provider at a time. The default is [Vercel AI Gateway](https://vercel.com/docs/ai-gateway).

```bash
fx login
```

That opens a Vercel OAuth flow and stores the session in `~/.fx/auth.json`. The browser page tells you when you can close the tab. In a headless shell, set `FX_NO_OPEN_BROWSER=1` and it prints the URL instead.

![The Vercel page after fx login succeeds](https://flaviocopes.com/images/fx/login-authorized.png)

I ran `fx doctor` again from `~`. It had loaded `~/.fx/settings.json`, showed the Vercel team from that login, and resolved `openai/gpt-5.2`. The git warning was still there, because that directory is not a repository.

![fx doctor after signing in with Vercel](https://flaviocopes.com/images/fx/doctor-after-login.png)

If you already have a Gateway API key, `fx setup` asks you to paste it. On macOS the key goes into Keychain. On Linux it goes into `~/.fx/api-key` with mode `0600`. For CI, put the key in the job's secret store and expose it as `AI_GATEWAY_API_KEY`. Do not write it into the workflow file, and do not put it in `.fx.json`.

On Gateway, fx picks the first credential it can find, in this order:

1. `VERCEL_OIDC_TOKEN`, when a Vercel runtime sets it
2. `AI_GATEWAY_API_KEY` in the current process
3. the saved `fx login` session
4. the key stored by `fx setup`

If you pick a source inside `/provider` and that source is missing, fx does not silently fall through to the next one.

A Gateway login can belong to more than one Vercel team. `fx teams` picks the team, and that team decides which models you see and which credit balance `fx credits` reports.

Two other providers are built in. Both use a subscription you already pay for, and neither uses the Gateway key:

```bash
fx login codex
fx login grok
```

`fx login codex` prints a sign-in URL, waits for the browser, then says `Signed in with Codex.`

![fx login codex, after the browser authorization finishes](https://flaviocopes.com/images/fx/login-codex.png)

`fx provider codex` or `fx provider grok` switches the active provider, and starts the browser login if you have no saved session yet. I wrote a full [Codex](https://flaviocopes.com/codex/) guide and a [Grok Bot](https://flaviocopes.com/grok-bot/) guide. Those products are separate from this login. Here, Codex means an eligible ChatGPT subscription used as the model source, and Grok means an eligible Grok subscription.

`fx logout` revokes the Vercel session. `fx logout grok` revokes the Grok token. `fx logout codex` only removes the session from this machine. To drop fx from a ChatGPT account, remove it under that account's connected apps. Logging out of Vercel does not delete a key you saved with `fx setup`.

`fx status` shows which model and credential are active, which Vercel team Gateway is using, and the permission mode for this workspace. When something looks wrong, I would start there.

## A first session

The directory you launch from is the primary workspace. fx will read and edit files there, subject to the permission rules below.

```bash
cd /Users/flaviocopes/www/flaviocopes.com
fx
```

The title bar shows the version and the folder. The line under the prompt is the permission mode and the current model. This one came up on `gpt-6-astra`, in `auto` mode, after I had switched the provider to Codex.

![An fx session opened in the flaviocopes.com repo, on gpt-6-astra](https://flaviocopes.com/images/fx/session-gpt-6-astra.png)

Then a request that names real files:

```text
Read src/pages/[slug].astro and tell me how a blog post URL is built.
Do not change any files.
```

fx streams the reply and prints the tools it runs as it goes. You can type a follow-up and press enter while a turn is still running.

A few keys are worth learning before the first long session:

| Action | Key |
| --- | --- |
| Newline in the draft | shift+enter, alt+enter, or `\` then enter |
| Interrupt the turn | escape twice, within one second |
| Clear the draft | ctrl+c |
| Full transcript | ctrl+o |
| Model picker, draft kept | ctrl+p |

Type `/` for the command list, `@` to find a file, and `$` to find a skill. `/status` shows the model, workspace, permissions, and session. `/new` starts a fresh session. With an empty draft, ctrl+c interrupts the turn, and a second press exits fx.

As of 0.0.9, `!` in the composer is ordinary prompt text. A command still goes through the agent and the permission check.

## One request from a script

`fx ask` runs a single prompt and exits. The answer is Markdown on stdout. Progress stays on stderr, so you can pipe the answer.

```bash
fx ask "Summarize the uncommitted changes in this repo"
```

`--json` is the form I would use from a script. One JSON object comes back, with the text, the model, a session id, token counts, and the tool calls:

```bash
fx ask --json "List the failing test files, if any" | jq -r .final_output
```

The fields you will actually branch on are `final_output`, `exit_code`, `session_id`, `usage`, and `tool_calls`. `resolved_provider` is the Gateway provider that served the last request, or null when the route was not reported. Token totals here are the main agent only. Subagent and review calls are left out. `fx usage` is the local record of spend.

Attach a screenshot the same way you would in the shell:

```bash
fx ask --image ./ui.png "Describe what this screen is asking the user to do"
```

`--model` and `--effort` apply to that run and do not change your saved defaults. `--no-save` skips creating a session. `--resume last` continues the latest session for this workspace.

`fx ask` does not sit and wait for an approval prompt. In `auto` mode, a call that fails review is held and the agent is told why. `--prompt-permissions` turns prompts back on when you are at a real terminal. If stdin is a pipe, a call that needs a person fails instead of blocking. An interrupted run exits 130.

`--full-access` turns the permission checks off for that process. I would not put that flag in a script that can see this repo's env files.

`fx pr` and `fx issue` draft a pull request or an issue from the current git repo. `--create` publishes it through `gh`. They accept `--auto` for the same automatic review as the shell.

## Pick a model

The catalog belongs to the provider you selected. On Gateway, before you have saved anything, the compiled default is `moonshotai/kimi-k3`. The browser demo shows that same default.

```bash
fx models
```

Inside the shell, `/models` opens the list and `/model <id>` selects one. The choice is stored per provider in `~/.fx/settings.json`, so switching to Codex and back restores the Gateway model you had.

With Codex signed in, this is the list I got on 21 September 2026. Five models, each marked with a 272K context: `gpt-6-astra`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, and `gpt-5.5`. The footer said the catalog was authenticated with a subscription. That list belongs to the Codex provider, so a Gateway login shows a different one.

![The Codex model list inside fx](https://flaviocopes.com/images/fx/models-codex.png)

Picking `gpt-5.6-sol` prints `Switched to gpt-5.6-sol`. The status line then showed `auto`, the model, and `medium`, with a bolt after the effort.

![The fx prompt after switching to gpt-5.6-sol](https://flaviocopes.com/images/fx/session-gpt-5-6-sol.png)

A project cannot set your model. `.fx.json` has no `model` field, which keeps a cloned repo from swapping the model out from under you.

For one process:

```bash
FX_MODEL=moonshotai/kimi-k3 fx
```

or:

```bash
fx ask --model moonshotai/kimi-k3 --effort high "Review the diff"
```

`effort` accepts `auto`, `none`, `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`, when the model supports them. `/fast` toggles fast mode for models that have it. Overriding the model for one run drops fast mode unless you also pass `--fast`.

Gateway can serve one model id from more than one inference provider. `provider_order` is a list of up to eight provider slugs, tried in order. `provider_strict` limits the request to that list.

```bash
fx ask --model anthropic/claude-sonnet-5 \
  --provider-order bedrock,anthropic \
  "Review this change"
```

Those two keys are allowed in `.fx.json`, unlike the model id. The slug spelling is the Gateway's spelling, and case matters (`vertexAnthropic` keeps the capital A). Routing applies to Gateway only.

## Permissions

fx starts in `auto`. Reading files inside the workspace is normally allowed. Edits, shell commands, and paths outside the workspace go through the policy.

| Mode | What happens |
| --- | --- |
| `ask` | You get a prompt for an unresolved sensitive call |
| `auto` | Rules apply, then a reviewer model judges what is left. This is the default |
| `full-access` | Permission checks are off |

Switch inside the shell with `/permissions ask`, `/permissions auto`, or `/permissions full-access`. `/permissions reset` goes back to `ask` and drops grants collected in this session.

In `ask`, the prompt has three answers. Yes runs this call once. "Yes, and don't ask again" runs it and remembers that scope until the session ends. No blocks it. That grant is not written to disk, and `fx resume` does not bring it back.

In `auto`, the reviewer is a second model call, billed like any other call on that provider. On Gateway the default reviewer is `moonshotai/kimi-k3`. You can point it at another Gateway chat model with `review_model` in `~/.fx/settings.json`, or `FX_REVIEW_MODEL` for one process. `typesafeai/jev` sends the review to TypeSafe's Jev evaluation model. On Codex the reviewer is fixed at `gpt-5.4-mini`. On Grok the reviewer is the session model. If the review cannot run, fx holds the action.

A narrow rule is cheaper than a review, because the rule settles the call before a second request goes out. Rules live in `~/.fx/settings.json`, not in the repo. The last match wins, so put the broad rule first:

```json
{
  "permission": {
    "bash": {
      "git *": "allow",
      "git push *": "deny"
    },
    "edit": {
      "*": "deny",
      "docs/*": "allow"
    }
  }
}
```

That allows git, then denies `git push`. Edits are denied except under `docs/`. Workspace rules override user-global rules.

`/allowlist` edits the same rules from the shell. Prefer `local` rules, tied to one repo, over a `user` rule that applies everywhere.

`fx --full-access` is the process-only switch. The saved mode stays whatever you had. The old name `yolo` still works as a flag and as a settings value. Saved JSON still writes `"yolo"` for that mode. The interface says "full access".

## Tools, files, and the shell

Finding files is `glob_files` and `grep_files`. Reading is `read_file`. Writing is `write_file` and `edit_file`. Commands are `shell`. The web is `web_search` and `web_fetch`. Images go through `vision` when the selected model cannot take them natively, and that fallback calls `google/gemini-2.5-flash`. Skills, subagents, and MCP each have their own tools, covered below.

If the task needs a logged-in page, use an agent that can drive a browser. fx can search the web and fetch a URL, and that is the whole web tool set.

A long command does not have to dump its whole log into the prompt. fx keeps a short preview and the byte count, plus a handle the model can read with `read_tool_result`. The default cap is 65536 bytes from one result, raised with `max_tool_result_bytes` (the floor is 1024).

`shell` can leave a process running. The same tool then has `interact` to read output or send input, and `stop` to end it. That is how a dev server stays up across turns. A subagent, covered later, is another fx session.

`max_agent_steps` caps the tool loop. `0`, the default, means no cap. A repo can set that in `.fx.json`, along with the tool-result cap, `context`, and the Gateway routing keys. Those are the only five fields a project file is allowed to set.

Extra directories are `--add-dir`, or `fx workspace add`. You can attach up to 16. They extend tool access. Skills, sessions, and `AGENTS.md` still come only from the primary workspace.

## AGENTS.md and skills

fx reads [`AGENTS.md`](https://flaviocopes.com/agents-md/) as project instructions. It looks at `~/.fx/AGENTS.md`, then `AGENTS.md` files from the launch directory down into the primary workspace. When a tool targets `apps/web/src/`, a nested `apps/web/AGENTS.md` applies on top of the root file, and the narrower file wins on a conflict. A direct request from you still beats both.

fx treats tool output as evidence, so a file the agent just read cannot override `AGENTS.md`. Keep tokens out of that file, because it is sent with the model request.

Set `"context": false` in `.fx.json` or in your settings to stop loading project instructions. Each instruction file is also size-capped, and a truncated file is reported as truncated.

A skill is a directory with a `SKILL.md` inside. fx sees the name and description at startup. The body is loaded only when you or the agent invoke that skill, which is how a long instruction stays out of every prompt.

It searches the primary workspace upward, stopping before your home directory, in `skills/`, `.agents/skills/`, `.codex/skills/`, `.claude/skills/`, `.opencode/skills/`, and `.claw/skills/`. Then it searches the same names under your home directory, plus `~/.fx/skills/`. Extra workspace directories are not searched.

This is the file it expects:

```md
---
name: review-post
description: Use this when a draft post needs a pass for broken commands.
---

# Review a post

Read the post, run the commands it shows, and report what failed.
```

`name` is required. Extra frontmatter is ignored, so a skill written for another agent still loads. Invoke it with `$` in the composer, or `/skills`.

`/skills install vercel-labs/agent-skills --skill find-skills` copies a skill into `~/.fx/skills/`. `/skills create` and `/skills remove` manage that same directory.

For an agent that needs the docs in one place, [fx.sh/llms.txt](https://fx.sh/llms.txt) is the index and [fx.sh/llms-full.txt](https://fx.sh/llms-full.txt) is every page in one file.

## MCP

fx is an [MCP](https://flaviocopes.com/what-is-mcp/) client. Servers you add are available in the shell, in `fx ask`, in ACP, and to subagents.

A private profile lives at `~/.fx/mcp.json`. Add a local stdio server:

```bash
fx mcp add local-tools npx -y @modelcontextprotocol/server-everything
```

Or a remote Streamable HTTP server:

```bash
fx mcp add --transport http prisma https://mcp.prisma.io/mcp
```

A literal `Authorization` header in that JSON is rejected, so the secret never sits in the profile as plain text. Use `bearer_token_env` or `header_env` and keep the value in the environment, or use `oauth` for an authorization-code login with PKCE. On macOS those OAuth tokens go to Keychain. `/mcp auth <name> --open` starts that login.

A repo can also ship `.mcp.json`, using the `mcpServers` shape other agents already use. Those servers stay disconnected until you trust them. Trust is stored in your private settings, under the workspace path, not in the committed file. Before you approve, fx does not start the process, call the URL, or read the env vars the file names.

```text
fx mcp trust approve prisma
fx mcp trust reject prisma
```

In the shell and in `fx ask`, your profile entry wins if a project server has the same name. Tool schemas are not all dumped into the prompt. `capability_search` finds a tool, and the schema loads if it fits the budget.

Server output is untrusted text. Keep `~/.fx/mcp.json` out of git, because the file can hold env values.

## Subagents

You delegate by asking, in the same conversation:

```text
Have a subagent review the parser tests and report missing cases. Do not edit files.
```

The model calls the `subagent` tool. `run` is a one-off child that finishes and returns. `message` creates a named child, or continues one you already named, so a later turn can say "check the new tests against your earlier findings."

The child inherits the parent's model, reasoning effort, and permission limits. Delegation does not grant a wider allowlist. Children share the workspace, so two of them editing the same file will step on each other. Give them different directories.

A named child keeps its own conversation. You can send it a follow-up while it is still on a tool. The final result comes back to the parent session.

## Sessions

Interactive `fx` starts a new session and stores it under `~/.fx/sessions/`.

```bash
fx sessions
fx resume last
fx -r
```

After I opened fx once in this repo and sent no prompt, `fx sessions` listed one saved session, with 0 turns.

![fx sessions listing one saved session for this repo](https://flaviocopes.com/images/fx/sessions.png)

`-r` opens a picker. `-c` resumes the latest session for this workspace without scanning every session. `fx ask --resume last` continues that conversation without opening the shell.

If a turn was interrupted, `/continue` resumes a paused response in the shell. From a script:

```bash
fx ask --resume last --continue-recovery
```

`fx session recover <id>` copies a damaged session and leaves the original alone. `fx doctor` prints the recovery command when it knows how to fix what it found.

When a request reaches 80% of the model's usable input, fx summarizes older context and continues the same turn in a fresh window. Recent tool exchanges stay. The full transcript stays in the saved session. `/compact` does that summary now and then waits for your next prompt. If compaction fails, the previous context stays.

## Editors, through ACP

`fx acp` speaks the Agent Client Protocol on stdin and stdout. An editor that supports ACP launches the binary:

```json
{
  "command": "/Users/flaviocopes/.local/bin/fx",
  "args": ["acp"]
}
```

The client's working directory is the workspace. Run one server process per workspace. Finish `fx login` before the editor starts the process, because ACP uses the saved credentials.

The server supports protocol version 1: create, load, resume, list, prompt, cancel, and set the model or mode. `ask` prompts for unresolved calls. `code` runs the automatic reviewer. A session grant still dies with the session.

Stdout is the protocol stream. Pass `--log-file` with an absolute path for diagnostics, or they will corrupt the JSON-RPC. Each message is capped at 8 MiB.

ACP can take text, images, and file resources. Audio is not accepted. It will use MCP servers the client passes in, plus project servers you have already trusted. It does not inherit `~/.fx/mcp.json`.

## Embed the agent

The CLI is one host. [`libfx`](https://www.npmjs.com/package/libfx) is the same core for your own process. The docs for this API match libfx 0.0.10. Pin that version if you need the examples below to match:

```bash
npm install libfx@0.0.10
```

You need Node 20 or newer. The package has no runtime dependencies. Native addons ship for macOS and Linux, on x64 and arm64. Linux wants glibc 2.34 or newer. Node on Windows has no native addon, so it falls back to WebAssembly.

One agent is one in-memory conversation:

```js
import { createFxAgent } from 'libfx'

const agent = await createFxAgent({
  apiKey: process.env.AI_GATEWAY_API_KEY,
})

try {
  const turn = agent.prompt('Explain how a database index speeds up a query.')
  for await (const event of turn) {
    if (event.type === 'text_delta') process.stdout.write(event.delta)
  }
  console.log(await turn.result)
} finally {
  await agent.close()
}
```

Read the stream before you await `turn.result`. If nothing consumes the events, the turn can stall. Only one prompt runs at a time. Breaking out of the loop cancels it, and so does `turn.cancel()` or an `AbortSignal`.

The embedded agent does not get the CLI's file tools, shell, or permission prompts. You pass tools in JavaScript, and your `execute` function is the permission check:

```js
const agent = await createFxAgent({
  apiKey: process.env.AI_GATEWAY_API_KEY,
  instructions: 'Answer questions about the handbooks. Use lookup when you need a title.',
  tools: [{
    name: 'lookup',
    description: 'Look up a handbook by slug.',
    inputSchema: {
      type: 'object',
      properties: {
        slug: { type: 'string' },
      },
      required: ['slug'],
    },
    async execute(input) {
      const books = {
        javascript: 'The JavaScript Handbook',
        node: 'The Node.js Handbook',
      }
      return books[input.slug] || 'No handbook with that slug'
    },
  }],
})
```

`instructions` is the whole system context, capped at 64 KiB. If you omit it, the request goes out with no system message, because libfx does not insert a base prompt of its own.

`checkpoint()` returns opaque bytes once the agent is idle. You store them. Credentials, tools, and instructions are not inside the checkpoint, so you pass them again when you restore into a new agent.

`createFxTerminal()` is a separate API for embedding the interactive UI, including storage and login adapters. The terminal path runs on WebAssembly and needs JSPI even when the agent itself is using the native addon.

There is a short browser demo of this split at [fx.sh/try](https://fx.sh/try). For a real app, the Node, browser, Next.js, and Nuxt examples are in the [embedding docs](https://fx.sh/docs/lib/examples).

## A local model

The released path is Gateway, Codex, or Grok. A preview, documented separately, lets you point the CLI at any server that speaks OpenAI-style Chat Completions. Ollama, vLLM, and OpenRouter are the examples in that guide.

The docs tell you not to assume the binary you installed already contains it. If `fx status --json` has no `provider_endpoint` after you add a connection, your build does not have the preview yet. Connection definitions go in `~/.fx/settings.json`, never in `.fx.json`, and the key stays in an environment variable named by `auth.env`.

For a local Ollama server the shape is:

```json
{
  "provider": "local",
  "providers": {
    "local": {
      "protocol": "openai-chat-completions",
      "base_url": "http://localhost:11434/v1",
      "auth": { "type": "none" },
      "model_metadata": {
        "qwen2.5:1.5b": {
          "context_window": 32768,
          "max_output_tokens": 2048,
          "supports_tool_use": true
        }
      }
    }
  },
  "models": {
    "local": "qwen2.5:1.5b"
  }
}
```

Leave `/chat/completions` off `base_url`, because fx appends that path itself. Loopback HTTP is allowed. Anything else needs HTTPS. Without `context_window`, automatic compaction has no threshold to work from. Native image input is not part of this adapter, even if you set `supports_vision`.

`gateway`, `codex`, and `grok` are reserved names. You select the connection with `fx provider local` or with `FX_PROVIDER=local` for one process.

## Usage, cost, and what stays on the machine

```bash
fx usage --period 7d
fx credits
```

`fx usage` reads a local log for 24h, 7d, or 30d. It is this machine, not the whole Vercel team. Gateway billing and the team dashboard are the other half. Codex and Grok requests are billed by those subscriptions, and `fx credits` will tell you credits do not apply there.

Reviews and the vision fallback are extra requests. Web search can add cost on the generation that called it.

fx does not upload the workspace, git history, or session files on its own. A prompt still contains whatever the turn loaded: the conversation, the applicable `AGENTS.md`, skill text, images, and tool output. `web_fetch`, web search, and a remote MCP server send whatever you asked them to send.

Session files stay under `~/.fx/`. Continuing a session sends that context again. `fx ask --no-save` is the one-off that leaves no session file.

`/trace` builds a diagnostic report on this machine. fx does not send a separate analytics event with it. Read the report before you paste it anywhere. It can contain prompts, paths, and commands.

AI Gateway's own policy, as fx documents it, is that prompts and outputs are not retained after the request, while metadata such as model, token counts, latency, and cost is kept for billing. A Pro or Enterprise team can turn on Zero Data Retention, which also limits routing to providers that support it. fx uses whatever that team or API key is configured for.

Leave `~/.fx` out of the repository. Settings, transcripts, MCP config, and recordings live there.

## How I would use it

I installed fx 0.0.10 and signed in, first with Vercel and then with Codex, and daily editing is still Cursor, one task at a time, with the diff in front of me. [Cursor Projects](https://flaviocopes.com/cursor-projects/) is the long-lived version of that, and I already know why it does not fit the way I work. I would keep the editor for that work.

On this site I would run `fx ask` against a draft post, in `ask` mode or with rules that allow `git status` and `npx astro build` and deny `git push`. The prompt would be narrow. Read this file, run the commands in the fenced blocks, report which ones failed. `--json` lets a script keep `final_output` and ignore the transcript. I would not pass `--full-access` on the machine that holds the newsletter and course credentials.

I would also try `libfx` the day I want an agent inside a small Node script whose tools I wrote myself. The handbook lookup above is the shape. The host decides what `execute` is allowed to touch. I would keep a Gateway key out of the browser tools on this site. Those pages run entirely in the browser, and a model key does not belong there.

I would skip fx when the job needs a real browser, when I am on Windows and need the native CLI, or when I want a full IDE session. The 0.0.x releases are still moving quickly, and the installer will not verify a checksum for you.
