Skip to main content

Plain Agent

A small agent that calls OpenAI compatible LLM APIs.

This project starts with a streaming agent loop:

Interactive terminal
  -> reads your prompt
  -> streams assistant text as it arrives
  -> detects tool calls from the model
  -> runs workspace tools when requested
  -> sends tool results back to the model
  -> repeats until the assistant gives a final answer

Install

Plain Agent is available on PyPI and can be installed with pipx:

pipx install plain-agent

If pipx is not installed, follow the official installation guide.

For local development, this project uses uv to track the Python environment. If uv is not installed, follow the official installation guide.

uv sync

On Linux, install Bubblewrap to enable the run_command tool:

# Debian / Ubuntu
sudo apt install bubblewrap

# Fedora / RHEL
sudo dnf install bubblewrap

# Arch Linux
sudo pacman -S bubblewrap

Plain Agent verifies that Bubblewrap is usable at startup. If it is missing or the kernel does not permit the required user and network namespaces, command execution is disabled and the file tools remain available. There is no unsandboxed command fallback. To keep the sandbox launcher outside the workspace trust boundary, Plain Agent checks only /usr/bin/bwrap and /bin/bwrap; it does not resolve Bubblewrap through PATH.

Configuration

Create a local .env file or export environment variables in your shell. See .env.example for more examples.

For DeepSeek:

export DEEPSEEK_API_KEY="your-api-key"
export LLM_PROVIDER="deepseek"
export LLM_MODEL="deepseek-v4-flash"

For OpenAI:

export OPENAI_API_KEY="your-api-key"
export LLM_PROVIDER="openai"
export LLM_MODEL="gpt-5.4-mini"

You can still set LLM_BASE_URL when you want to override the provider default, such as pointing at a local OpenAI compatible server like Ollama.

Context compaction runs automatically when the estimated conversation history reaches 200k tokens. Set LLM_COMPACTION_AUTO_MAX_TOKENS to change that threshold, or set it to 0 to disable automatic compaction. You can also run /compact in the terminal to compact manually.

Web search

The Exa-backed web_search tool is enabled by default and every query requires explicit approval before Plain Agent connects to mcp.exa.ai. Search results include links and bounded relevant excerpts. No Exa API key is required.

To disable web search:

export PLAIN_AGENT_ENABLE_NETWORK="false"

This setting controls only the built-in search tool. The run_command sandbox remains offline.

Run

uv run plain-agent

Command sandbox (Linux)

Every run_command request requires user approval and still runs through Bubblewrap after it is approved. The approval prompt shows the requested mode and an unambiguous shell-quoted representation of the exact argument vector. Backslashes and non-printable characters are escaped so command arguments cannot rewrite the terminal prompt. Approval is a user decision; Bubblewrap is the independent OS enforcement boundary.

Commands are passed as an argument array and never receive an implicit shell. For example, ["rg", "TODO", "."] runs directly, while shell syntax must be explicit as ["bash", "-lc", "printf '%s\\n' *.py"].

Two modes are available:

  • read-only is the default and mounts the workspace read-only.
  • workspace-write permits persistent workspace changes, except protected paths.

Both modes have networking disabled, including host loopback. The sandbox starts with an empty filesystem view and exposes only the workspace, required read-only system runtimes, a minimal set of /etc files, and temporary in-memory /tmp, /run, and HOME directories. The environment is cleared; only a filtered PATH, locale, terminal, and color settings are retained. API keys and arbitrary parent variables are not inherited by commands.

In workspace-write, existing .git and .venv directories are rebound read-only. .agents, .codex, and .sandbox are hidden. .env plus recognized private-key and certificate files are masked in both modes, as are existing pathname Unix sockets. In-process file tools continue to use their existing workspace permission checks and are not run through Bubblewrap.

Additional toolchains can be exposed read-only with an OS-path-separated list of absolute, existing paths:

export PLAIN_AGENT_SANDBOX_ADDITIONAL_READ_ROOTS="/opt/toolchain:/home/me/.local/share/special-runtime"

Each extra root expands the confidentiality boundary: sandboxed commands can read everything below it. Paths are canonicalized and deduplicated before use. Avoid exposing home directories or credential stores.

The command sandbox is deliberately offline. Package downloads, remote Git operations, and calls to local network services fail. Linux is the only supported command-sandbox platform in this milestone; macOS and Windows keep run_command disabled. Seccomp syscall filtering is planned as the next Linux hardening step after the filesystem and network policy is stable.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

plain_agent-0.1.7.tar.gz (52.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

plain_agent-0.1.7-py3-none-any.whl (45.2 kB view details)

Uploaded Python 3

File details

Details for the file plain_agent-0.1.7.tar.gz.

File metadata

  • Download URL: plain_agent-0.1.7.tar.gz
  • Upload date:
  • Size: 52.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for plain_agent-0.1.7.tar.gz
Algorithm Hash digest
SHA256 95e34c329b54cdcbb25faa58c85818864607daa6880987b7cbb04534909e0c14
MD5 6a3d528c36e9b3a432bc006b2bf8df3c
BLAKE2b-256 ecc8b7fab567167c4eac727e055af2cbed27d64c2adfffeb2257f2b42492447b

See more details on using hashes here.

File details

Details for the file plain_agent-0.1.7-py3-none-any.whl.

File metadata

  • Download URL: plain_agent-0.1.7-py3-none-any.whl
  • Upload date:
  • Size: 45.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for plain_agent-0.1.7-py3-none-any.whl
Algorithm Hash digest
SHA256 ce053525f6849f8127f15b2821748e961bfb542b2b20455f4afc347751b2c0f4
MD5 1b83421a73434d63f10c2d25b5f6a0bc
BLAKE2b-256 f1cc2d89288a026e423d617b758dd6a130fc2fb5744978c6b1211027f439bb60

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page