Skip to content
Back to Knowledge Base

Fix Nx Commands Failing in an AI Agent Sandbox

When running Nx commands inside an AI agent's sandbox, you may see errors related to the Nx daemon, plugin isolation, or forked processes failing to communicate. Agent sandboxes (Seatbelt on macOS, bubblewrap on Linux) block Unix socket access by default, and Nx relies on Unix sockets for inter-process communication.

Allowlist the root Nx puts its sockets under. The entry covers creating sockets as well as connecting to them, which is what the daemon, plugin workers and forked tasks each need.

The sections below cover Claude Code, Codex, and GitHub Copilot CLI. Each gates sockets on a different setting, so use the one that matches your agent.

The daemon, forked task processes and plugin workers put their sockets beneath one stable root on macOS and Linux: /tmp/.nx, unless overridden via NX_SOCKET_DIR. When that root can't be used they move to ~/.nx, so allowlist both. Neither path varies between machines or users, which makes the rule suitable for team-wide project settings:

.claude/settings.json
{
"sandbox": {
"filesystem": {
"allowRead": ["/tmp/.nx", "~/.nx"],
"allowWrite": ["/tmp/.nx", "~/.nx"]
},
"network": {
"allowUnixSockets": ["/tmp/.nx", "~/.nx"]
}
}
}

~ expands to the home directory of whoever runs Nx, so one committed entry covers every user. Wildcards don't work in these settings, so each entry has to be a literal path.

The write grant covers /tmp/.nx rather than only its sockets descendants because the first Nx run also has to create the root. Nx copies its compiled native binding into a cache under the same root before loading it, which the grant needs to cover too.

Running nx configure-ai-agents writes these to .claude/settings.json for you: the scoped socket paths and the read/write grants. Claude Code's sandbox blocks writes to its own settings file, so run it from a regular terminal rather than through the agent.

The allowances only take effect once sandboxing itself is on, which configure-ai-agents deliberately leaves to you. Run /sandbox in Claude Code to enable it.

Codex gates Unix sockets on a different setting, and there is no way to scope them to a path. sandbox_workspace_write.writable_roots on its own leaves a bind refused. The switch that permits it is network_access, which also grants the sandbox general network access:

~/.codex/config.toml
[sandbox_workspace_write]
network_access = true
writable_roots = ["/tmp/.nx", "/home/<you>/.nx"]

writable_roots is still needed for the ~/.nx fallback, which sits outside the areas workspace-write makes writable. The entries have to be absolute, since Codex does not expand ~.

Because that grant is broad, nx configure-ai-agents does not write it for you. If you would rather not enable it, see Alternative workarounds below, which need no sandbox changes.

Copilot CLI scopes sockets by path, like Claude Code. Add the Nx socket roots to sandbox.userPolicy.filesystem.readwritePaths:

~/.copilot/settings.json
{
"sandbox": {
"enabled": true,
"userPolicy": {
"filesystem": {
"readwritePaths": ["/tmp/.nx", "~/.nx"]
}
}
}
}

Unlike Codex, Copilot CLI expands ~, so the home entry is the same string for every user.

Two things to know. The sandbox policy is read only from the user-level ~/.copilot/settings.json, so a copy committed to the workspace has no effect and nx configure-ai-agents cannot write it for you. And command sandboxing is an experimental feature that is off by default, so these settings do nothing until you enable it with --experimental and /sandbox enable.

The network settings do not help here. userPolicy.network.allowLocalNetwork leaves the socket refused, because Copilot gates socket creation on the filesystem policy rather than the network one.

Setting $NX_SOCKET_DIR replaces this list rather than joining it: the value is used exactly as given, and a configured directory Nx can't use sends it straight to the workspace with a warning instead of quietly substituting a longer path you never asked for.

Otherwise Nx uses the first of these it can establish. It creates each directory and verifies it afterwards, not before: a check that ran first would leave a window in which someone else could swap the path between the check and the use.

  1. /tmp/.nx/<uid>/sockets needs /tmp/.nx to belong to you or to root, and to be sticky if anyone else can write to it. The two directories beneath it have to be yours and mode 0700.
  2. ~/.nx/sockets needs both directories to be yours and mode 0700. There's no container check here, because nobody else can write to your home directory.
  3. <workspaceRoot>/.nx/workspace-data/d is the last resort. Its length grows with the depth of your checkout, so a deeply nested workspace can push a socket past the 95-character limit Nx enforces. Nx sets that conservative guard to sit under the operating system's own cap on socket paths.

The native binding cache doesn't follow sockets down that list. It lives at /tmp/.nx/<uid>/native-cache/<nxVersion> or nowhere. When that can't be established, Nx skips the cache and loads the binding in place from node_modules. A skipped cache costs one file copy, while a skipped socket costs you the daemon, so only sockets keep looking.

None of this applies on Windows. Named pipes aren't filesystem objects, so sockets stay directly under %TMP%, with no per-user segment and no second location.

If you prefer not to allowlist the socket root, you can disable the Nx features that require sockets. These workarounds come with tradeoffs:

Terminal window
NX_DAEMON=false nx <command>

The Nx daemon keeps a persistent process running to speed up repeated operations. Disabling it means Nx starts fresh on every invocation, resulting in slower cold starts (especially in large workspaces).

Terminal window
NX_ISOLATE_PLUGINS=false nx <command>

Plugin isolation runs each plugin in a separate forked process to prevent conflicts between multiple TypeScript compilers, module-level caches, and global state. Disabling it runs all plugins in the main process, which can cause issues in workspaces with plugins that have conflicting dependencies.

For advanced use cases, Nx provides environment variables to override where socket files are created:

VariableDescription
NX_SOCKET_DIROverrides the directory for all Nx sockets (daemon, forked process, and plugin). Replaces the default locations listed above rather than joining them. Must name a directory only your user can reach. Nx rejects the system temp directory and its own container/cache roots outright.
NX_DAEMON_SOCKET_DIRLegacy alias of NX_SOCKET_DIR. Used only when NX_SOCKET_DIR is not set. Prefer NX_SOCKET_DIR.
NX_NATIVE_FILE_CACHE_DIRECTORYOverrides the native file cache path

These are primarily useful for environments with restricted temp directory access (e.g., certain Docker or CI setups). For Claude Code's sandbox, allowlisting the default roots is simpler and more reliable. If you do override the location, allowlist the directory you point Nx at instead.

Last updated: