A barebone sandbox for agentic coding based on UNIX user
Project description
A⁴U²: AI Agent As Another Unix User (aka agent-as-unix-user)
A bare-bones sandbox for agentic coding based on UNIX users.
TL;DR:
uv tool install agent-as-unix-user # Install this CLI
au new # Create a new UNIX user for your AI agent
au run --env FOO=bar bash # Run bash (with an environment variable) as the agent UNIX user,
# with only access to `/home/agent`
au mount add --rw ~/example # Expose `~/example` in `/home/agent/example`
# with read&write access
cd ~/example && au run bash # `au` detects current directory corresponds to agent's
# `/home/agent/example`, so it changes to it before starting bash
au run -- claude --dangerously-skip-permissions # Run Claude in yolo mode without guilt,
# the UNIX sandbox has you covered \o/
UNIX has been designed from the ground up to allow multiple users to securely share a single machine (remember the time when a terminal was a physical thing that multiple users used to connect to a single mainframe? Yeah, me neither).
More recently, Android uses a similar technique to isolate each application by having a dedicated user for each application.
So why not do the same for agentic coding? Enter agent-as-unix-user, a simple wrapper around standard UNIX commands to easily:
- Create a dedicated UNIX user
- Give access to certain folders in read-only or read&write mode
- Undo all of this if needed ;-)
- Run commands as the UNIX user
Of course, this solution has tradeoffs, but it offers a surprisingly high bang for the buck:
Pros:
- Unlike containers and VMs, there's no need to eat gigabytes of disk or deal with manual start/stop.
- Strong isolation: you can run your agent in full yolo mode knowing it can only break its own home directory.
- Simple to understand (so simple that all actual commands are printed before being executed!)
- Simple to reason about: the agent can only modify its home and cannot read your home. From there you can easily give it access (in read-only or read-write) to some specific folders in your home.
- Can be extended using the regular UNIX ecosystem (see the recipes below).
Cons:
- Requires root access to create the agent user (this is done once; after that root is not needed to run a command as the agent)
- No network filtering out-of-the-box (but can be easily added using an HTTP proxy).
- Tricky to share the commands you installed in your home (i.e. basically everything you installed with
curl https://someapp.com/install.sh | bash). Note this is a user experience con (as it means reinstalling your tools for the agent user), but also a security pro since otherwise a malicious agent could escape the sandbox by just modifying a shared tool and waiting for you to run it...
Installation
Only Linux is supported for now (macOS might be possible though; open an issue if you are interested \o/).
pipx install agent-as-unix-user
# or with uv
uv tool install agent-as-unix-user
[!NOTE] agent-as-unix-user has the following requirements:
- Linux with ACL support
- A C compiler (for the setuid entrypoint, see below)
sudoaccess (for user/group creation and setuid setup)
Recipes
The great thing about this approach is its simplicity and its compatibility with the UNIX ecosystem.
Example 1: limit CPU & RAM
Limit the agent to use at most 16GB of RAM and one and a half cores on your machine.
systemctl set-property user-$(id -u agent).slice CPUQuota=150% MemoryMax=16G
Example 2: filter network traffic
Run an HTTP proxy locally with your filtering rules, then configure iptables:
# Redirect HTTP and HTTPS traffic from UNIX user `agent` to
# port 3128 (default port for Squid HTTP proxy)
iptables -t nat -A OUTPUT -m owner --uid-owner agent -p tcp --dport 80 -j REDIRECT --to-port 3128
iptables -t nat -A OUTPUT -m owner --uid-owner agent -p tcp --dport 443 -j REDIRECT --to-port 3128
# Allow DNS
iptables -A OUTPUT -m owner --uid-owner agent -p udp --dport 53 -j ACCEPT
# Block everything else for that user
iptables -A OUTPUT -m owner --uid-owner agent -j DROP
How it works
When you create an agent, agent-as-unix-user will:
- Create a UNIX user (e.g.
agent) and a group (su-as-agent) - Add your user to the group so you can interact with the agent's files
- Configure the agent's home directory with setgid + ACL defaults so files created by either user remain editable by both
- Compile and install a small setuid C binary (
/home/agent/su_as_agent) to execute commands as the agent.
To run a command as an agent, au run my_command itself uses /home/agent/su_as_agent, which:
- Scrubs your environment variables (only
LANGandTERMare kept). - Drops all the groups inherited from the original user.
- Sets UID and GID to become the agent user.
Transparency as a feature
Agent-as-unix-user is designed to be as transparent as possible by only using UNIX commands and displaying them as they are run.
For instance, running $ au new -a agent2 will result in the following output:
Create agent agent2 in /home/agent2 and configure group 'su-as-agent2'? [y/N]: y
$ sudo groupadd su-as-agent2
[sudo] password for touilleMan:
$ sudo useradd --shell /usr/bin/bash --no-user-group --create-home --home-dir /home/agent2 --gid su-as-agent2 agent2
$ sudo usermod --append --groups su-as-agent2 touilleMan
$ sudo chgrp su-as-agent2 /home/agent2
$ sudo chmod 2770 /home/agent2
$ sudo setfacl --modify default:group:su-as-agent2:rwx /home/agent2
$ sg su-as-agent2 -c 'tee /home/agent2/README.md'
$ sg su-as-agent2 -c 'mkdir -p /home/agent2/.config/agent-as-unix-user/su_as_agent-src'
$ sg su-as-agent2 -c 'tee /home/agent2/.config/agent-as-unix-user/su_as_agent-src/main.c'
$ sg su-as-agent2 -c 'tee /home/agent2/.config/agent-as-unix-user/su_as_agent-src/Makefile'
$ sg su-as-agent2 -c 'make -C /home/agent2/.config/agent-as-unix-user/su_as_agent-src'
make: Entering directory '/home/agent2/.config/agent-as-unix-user/su_as_agent-src'
cc -O2 -Wall -Wextra -Werror -DTARGET_UID=1003 -DTARGET_GID=1003 -o su_as_agent main.c
make: Leaving directory '/home/agent2/.config/agent-as-unix-user/su_as_agent-src'
$ sg su-as-agent2 -c 'mv --force /home/agent2/.config/agent-as-unix-user/su_as_agent-src/su_as_agent /home/agent2/su_as_agent'
$ sudo chown root:su-as-agent2 /home/agent2/su_as_agent
$ sudo chmod 4750 /home/agent2/su_as_agent
Created agent agent2
[!NOTE] Here, lines starting with
$don't indicate user input but instead display the commands thatauis about to execute.
Usage
Create a new agent
au new # creates an agent named "agent" (default)
au new --agent agentA # custom agent name
au new --yes # skip confirmation prompt
Requires root/sudo. Creates the UNIX user, group, home directory (with setgid + ACL), compiles the setuid entrypoint, and updates the config file.
Run a command as the agent
au run echo hello # run as default agent "agent"
au run --agent agentA -- code # run as a specific agent
au run --env API_KEY=xxx -- cmd # pass environment variables
Before executing, au run verifies the entrypoint binary hasn't been modified by comparing its SHA-256 hash with the stored fingerprint.
The environment is scrubbed by default — only LANG and TERM are kept, plus any variables passed explicitly via --env.
Show agent info & health
au info # info for default agent "agent"
au info --agent agentA # info for a specific agent
Displays the agent's home directory, group, entrypoint path, ACL external accesses, and runs a healthcheck that verifies:
- UNIX user and group exist
- Home directory exists with setgid bit
- Default ACLs are configured
- Entrypoint exists and is executable
- Current user is a member of the agent's group
- ACL tooling is available on the system
List agents
au list
Lists all agents present in the configuration file.
Delete an agent
au delete # delete default agent "agent"
au delete --agent agentA # delete a specific agent
au delete --delete-home # also remove the home directory
au delete --yes # skip confirmation prompt
Requires root/sudo. Removes the UNIX user, group, and optionally the home directory. Resilient to partial state — if some resources are already gone, it skips them and continues.
Global options
--config, -C PATH Config file (default: ~/.config/agent-as-unix-user.toml)
--version Show version
-h, --help Show help
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agent_as_unix_user-2.2.0.tar.gz.
File metadata
- Download URL: agent_as_unix_user-2.2.0.tar.gz
- Upload date:
- Size: 18.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4775ebdfc06b071a92a48d7f00316f1e99eeb061a820d1fbbfbfaeda5d56927d
|
|
| MD5 |
0adfb797da7a69f9252727629e58715d
|
|
| BLAKE2b-256 |
a6149d5cdd41bbbe2c38160b7333d8fd90490b88f84c5dbd24dc622a85e37939
|
Provenance
The following attestation bundles were made for agent_as_unix_user-2.2.0.tar.gz:
Publisher:
ci-cd.yml on touilleMan/agent-as-unix-user
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agent_as_unix_user-2.2.0.tar.gz -
Subject digest:
4775ebdfc06b071a92a48d7f00316f1e99eeb061a820d1fbbfbfaeda5d56927d - Sigstore transparency entry: 1591295561
- Sigstore integration time:
-
Permalink:
touilleMan/agent-as-unix-user@c049546e2e2265a97da9520799e288fd26d0fc60 -
Branch / Tag:
refs/tags/v2.2.0 - Owner: https://github.com/touilleMan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci-cd.yml@c049546e2e2265a97da9520799e288fd26d0fc60 -
Trigger Event:
push
-
Statement type:
File details
Details for the file agent_as_unix_user-2.2.0-py3-none-any.whl.
File metadata
- Download URL: agent_as_unix_user-2.2.0-py3-none-any.whl
- Upload date:
- Size: 25.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a91d16980e166c43d3d2f9ee21f881aec65e68b6b610965a3738f3456fbf85c
|
|
| MD5 |
cd22793e23789a08b2ed7b359b46cdb3
|
|
| BLAKE2b-256 |
a7a1544f236848ae67ea1d89810ecee9dfb4021a0c9126a6e649219829602e17
|
Provenance
The following attestation bundles were made for agent_as_unix_user-2.2.0-py3-none-any.whl:
Publisher:
ci-cd.yml on touilleMan/agent-as-unix-user
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agent_as_unix_user-2.2.0-py3-none-any.whl -
Subject digest:
0a91d16980e166c43d3d2f9ee21f881aec65e68b6b610965a3738f3456fbf85c - Sigstore transparency entry: 1591295609
- Sigstore integration time:
-
Permalink:
touilleMan/agent-as-unix-user@c049546e2e2265a97da9520799e288fd26d0fc60 -
Branch / Tag:
refs/tags/v2.2.0 - Owner: https://github.com/touilleMan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci-cd.yml@c049546e2e2265a97da9520799e288fd26d0fc60 -
Trigger Event:
push
-
Statement type: