Skip to content
Agentic Control Plane

fx Permissions Reference — session/request_permission, Not Hooks

David Crowe David Crowe · · Updated · 7 min read
fx permissions acp-protocol reference
Share X HN LinkedIn

Run agents? ACP lets you see, control, and price every tool call they make — allow/ask/deny policy, per-session cost, and a full audit log for Claude Code, Cursor, Codex, and OpenClaw, in one command:

curl -sf https://agenticcontrolplane.com/install.sh | bash

Getting started →  ·  see your first governed call →  ·  free up to 5 agents  ·  prefer fully on-device? add --local

Just want the answer?

fx has no hook or plugin API to install into. Point your Agent Client Protocol client at a proxy instead of running fx acp directly:

npm install -g @agenticcontrolplane/fx
acp-fx -- fx acp

Native control model: fx permissions, explained. Not the product this site is named for: ACP vs. ACP.

fx is Vercel Labs’ minimal coding agent, written in Zig and announced August 18, 2026 — and it comes with an acronym collision worth clearing up before anything else. fx speaks the Agent Client Protocol, Zed’s editor-integration protocol, also abbreviated ACP. It has nothing to do with the Agentic Control Plane this site is named for, beyond sharing three letters. This reference is about the real seam: the JSON-RPC message fx’s protocol server sends for every approval-gated tool call, and the middleware that stands on it.

No hook, no plugin API — externally

fx’s source contains an internal hook harness with a pre_tool_use event that can block or rewrite a call before it runs. Nothing external attaches to it — no settings key, no subprocess execution, no documented interface. It’s a compiled-in extension point today, not a surface a policy layer, plugin, or config file can register against.

The real seam: fx acp and session/request_permission

fx can run as an Agent Client Protocol server (fx acp). Every approval-gated call fx wants to make gets sent to the connected client as a session/request_permission JSON-RPC request, carrying the full tool arguments. The client answers allow or deny, and fx honors it; any error, cancellation, or malformed answer resolves to deny. Only one such request is ever pending at a time — fx’s own request/await cycle never has more than one in flight, so nothing on the receiving end needs correlation bookkeeping.

One wire detail worth knowing before writing anything against this: the original tool name never reaches the message. The toolCall payload carries a human-readable title (for example, “Run: rm -rf /tmp/scratch”) and a coarse kind — read, edit, delete, move, execute, search, other — not fx’s internal tool identifier. Any rule matching against this seam has to work on title substrings and kind, not an internal tool-name enum fx doesn’t expose over the wire.

acp-fx: a proxy, not a plugin

Because fx has no plugin API, the integration for it isn’t one — it’s protocol middleware: a zero-dependency stdio proxy sitting between a real Agent Client Protocol client (Zed, or any ACP driver) and the fx acp subprocess. Every message passes through untouched except session/request_permission, which the proxy intercepts, checks against POST /govern/tool-use, and resolves:

Decision Attended --unattended
allow reply allow_once directly same
deny reply reject_once directly same
ask forward the original request to the real client — a human decides reply reject_once — an unattended agent can’t self-approve
gateway unreachable / timeout forward to the client; fail open with a loud [ACP] ⚠ UNGOVERNED line on stderr reply reject_once; fail closed
no credential found same as unreachable same

One deliberate constraint: the reply is always allow_once or reject_once — never allow_always, even when the policy check itself says allow. Every later call for the same tool goes through the same check again, instead of fx caching a blanket approval on the proxy’s say-so.

Display-layer output scanning — not a second enforcement point

fx’s session/update notifications carry a tool’s result text out to the client as it happens. acp-fx also posts that text to POST /govern/tool-output and can block or redact what actually reaches the client’s display. State this plainly: it’s display-layer only. fx has already sent the raw result to its own model before that notification goes out — blocking or redacting here changes what the human sees in their editor, not what the model already acted on. Treat it as a transcript filter, not a second gate on what the agent knows. An outage during this check passes the content through silently; the loud fail-open/fail-closed posture described above belongs to the pre-execution check, which is the one that actually controls whether something runs.

Install and point your client at it

npm install -g @agenticcontrolplane/fx
acp-fx -- fx acp        # point your ACP client here instead of `fx acp`

fx isn’t among the harnesses the main installer wires up automatically — it doesn’t appear in install.sh at all. Get it with its own README’s command instead. It requires Node 22+ and a workspace credential in ~/.acp/credentials (or ACP_API_KEY/ACP_BEARER_TOKEN).

Failure posture, restated

The table above is the whole story: one bounded transport-failure retry (never a retry on an HTTP status code), then — attended — fail open, loud, with the connected client still getting the original request to decide on its own; unattended — reject_once, no exception, because there’s nobody there to be the fallback.

Known limitations

  • fx’s own auto-mode model reviewer — a hardcoded model that can approve a sensitive call when no rule matches it — is a separate, native fx feature. acp-fx only ever sees a call once fx has already decided it needs a permission check, so it doesn’t observe or record what the reviewer approved upstream of that point.
  • No model spend is metered here either: fx has no proxy path this middleware rides, so what lands in the activity log is the tool-call decision — allow_once/reject_once, title, kind, latency, reason — not per-call token cost.
  • FX_PERMISSION_MODE=yolo bypasses fx’s permission system entirely before any of the above runs. acp-fx strips that variable from the spawned child’s environment so a stray shell export can’t silently disable the checks it exists to make — but it can’t stop yolo set some other way inside fx’s own process.

Frequently asked questions

Does fx support hooks or a plugin API?

Not externally. The source contains an internal pre_tool_use hook that can block or rewrite a call, but nothing outside the binary can attach to it — no settings key, no subprocess execution, no documented surface. It’s compiled-in only.

What is session/request_permission?

The JSON-RPC request fx’s Agent Client Protocol server sends to its connected client for every approval-gated tool call, when fx is run as fx acp. The client answers allow or deny; any error, cancellation, or malformed answer resolves to deny.

How do I point ACP at fx?

npm install -g @agenticcontrolplane/fx, then run acp-fx – fx acp instead of fx acp directly, and point your Agent Client Protocol client (Zed, or any ACP driver) at acp-fx.

Is fx's ACP the same thing as the Agentic Control Plane?

No — an acronym collision, nothing more. fx speaks the Agent Client Protocol, Zed’s editor-integration protocol. See /acp-vs-acp for the disambiguation.

Where to read more

Share X HN LinkedIn
Get the next data drop
What agents actually cost, new tool-surface captures, and the occasional incident post-mortem — sent when we publish something worth your inbox, not on a schedule. Unsubscribe anytime.
Share: Twitter LinkedIn
Related posts

← back to blog