Skip to main content

neo

neo is a lightweight, autonomous terminal coding agent written in Python. Describe a task in plain language — neo plans the work, executes it with sandboxed tools, verifies the result, and streams everything live in your terminal.

you:  neo -p "add rate limiting to the API"
neo:  planning… wrote .neo/plans/rate-limit.md
      ✓ read src/api.py (212 lines)
      ✓ edited src/api.py (+38 −4) · ruff clean · pyright: 0 new errors
      ✓ bash: pytest -x -q → 41 passed
      done in 34s · 12 steps · $0.021

Lightweight means: one pip install, no daemon, no browser, no IDE extension, no account. Plain terminal, plain JSON config, stdlib-first dependencies.

Capabilities

Area What you get
Agent loop plan → act → verify; parallel tool calls, retries with backoff, doom-loop guard, transcript repair, auto-compaction
Tools (18) read write edit apply_patch glob grep list_dir bash (+pty) webfetch websearch todo_write todo_read task question skill plan_enter plan_exit undo
Sandbox every bash call can run in bubblewrap: user/IPC/PID/net namespaces, read-only root, hidden secrets, domain-filtered network
Providers 228 in the catalog (OpenAI / Anthropic / Gemini protocols); any OpenAI-compatible endpoint works with just a base_url
Plan mode changes are drafted to .neo/plans/, edits locked to the plan until you approve via plan_exit
Safety net permission rules (allow/ask/deny), git snapshots before risky batches, undo, session forks, worktrees
Code intelligence LSP diagnostics (pyright, tsserver, gopls, rust-analyzer, eslint) + formatters run after every edit
Extensibility MCP servers, Python plugins with hooks, .neo/commands/*.md slash commands, .neo/tools/*.py custom tools, skills

Install

pip install neo-agnt

Requires Python 3.10+. For a sandboxed bash tool on Linux, install bubblewrap (and socat for filtered networking):

# debian / ubuntu
sudo apt install bubblewrap socat

Set an API key — environment variable, auth.json, or neo.json (first match wins):

export ANTHROPIC_API_KEY="sk-..."
# ~/.config/neo/auth.json  (created with 0600 permissions)
{ "anthropic": "sk-..." }

Quickstart

neo                                          # interactive TUI
neo -p "fix the failing test in test_loop"   # headless, print reply and exit
neo -p "..." --allow-all                     # headless, skip permission prompts
neo --resume                                 # continue the last session
neo init                                     # scaffold .neo/ (AGENTS.md, skills, commands, agents)
neo models                                   # list providers and models
neo config                                   # show resolved configuration
neo snapshot | neo restore | neo fork        # git snapshots and session forks

Inside the TUI, / opens the command palette, @ completes file paths, Ctrl+C cancels the running turn, and typing while the agent works queues your message for the next turn.

Configuration

neo.json — global at ~/.config/neo/neo.json, per-project at ./neo.json or ./.neo/neo.json (project overrides global):

{
  "model": "anthropic/claude-sonnet-4-6",
  "small_model": "anthropic/claude-haiku-4-5",
  "max_steps": 40,
  "theme": "neo-dark",
  "verify_commands": ["ruff check .", "pytest -x -q"],
  "permissions": {
    "bash": { "git *": "allow", "rm -rf *": "deny", "*": "ask" },
    "edit": { "*": "ask" },
    "webfetch": { "*": "allow" }
  },
  "providers": {
    "my-proxy": { "base_url": "https://proxy.internal/v1", "api_key_env": "PROXY_KEY" }
  },
  "sandbox": { "mode": "auto", "network": "filtered" },
  "mcp": {
    "servers": {
      "fs": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/data"] }
    }
  }
}

Permission rules are {tool: {pattern: allow|ask|deny}}, last match wins. neo config prints the fully resolved configuration.

Sandbox

On Linux, bash runs inside bubblewrap — the same primitive OpenAI Codex and Anthropic's sandbox runtime build on. The model sees a normal shell; underneath it gets namespaces, a read-only root, and filtered egress.

{
  "sandbox": {
    "mode": "auto",
    "network": "filtered",
    "allowedDomains": ["github.com", "*.github.com", "pypi.org", "*.pypi.org"],
    "deniedDomains": [],
    "allowWrite": ["."],
    "denyRead": ["~/.ssh", "~/.aws", "~/.gnupg"],
    "denyWrite": [".env"],
    "passEnv": ["PATH", "HOME", "LANG"],
    "allowSecrets": [],
    "privateTmp": true
  }
}
  • mode: auto (warn once, run unsandboxed if bubblewrap is missing), strict (fail loudly instead of running unsandboxed), off.
  • network: none (fully offline), filtered (isolated net namespace + domain-allowlist proxy), full.
  • Environment is cleared; only passEnv survives, and secret-looking variables are stripped unless listed in allowSecrets.

Every bash result is tagged — [sandbox] active (network=filtered) — so you always know what isolation was in effect.

Plan mode

For non-trivial work, neo drafts a plan first and locks edits to it:

you:  /plan add oauth login
neo:  wrote .neo/plans/oauth-login.md — 5 steps, 3 files
      [plan_enter] edits restricted to the plan. review, then approve.
you:  looks good, proceed
neo:  [plan_exit] approved — executing as build turn…
      ✓ edited src/auth.py …  ✓ bash: pytest → 58 passed

Plans live in .neo/plans/ as Markdown. Nothing outside the plan is touched until you approve.

Safety net

neo snapshot                  # snapshot the worktree (git tree-hash handle)
neo snapshot --list           # list snapshots
neo restore <id> --dry-run    # preview what a restore would change
neo restore <id>              # restore files from a snapshot
neo fork                      # fork the session (copy-on-write)

Snapshots are also taken automatically before risky tool batches, and the undo tool (approval-gated) rolls back the last mutation.

MCP

Add any MCP server in neo.json; its tools appear as server_tool, its prompts become slash commands:

{ "mcp": { "servers": {
  "github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"] },
  "remote": { "url": "https://mcp.internal/v1", "headers": { "Authorization": "Bearer ${MCP_TOKEN}" } }
} } }

Each server is isolated — one failing server never takes down the rest.

Plugins

Python plugins live in ~/.neo/plugins/ or <project>/.neo/plugins/. A plugin is a module exposing hooks:

# ~/.neo/plugins/notify.py
def on_tool_after(event):
    if event.tool == "bash" and event.result.is_error:
        desktop_notify("neo", f"bash failed: {event.result.output[:120]}")

hooks = {"tool.execute.after": on_tool_after}

Available hooks: tool.execute.before/after, permission.ask, chat.params, command.execute.before, session.end. Plugins can also register their own tools.

Custom commands and tools

<!-- .neo/commands/review.md -->
---
description: review the current diff
agent: reviewer
---
Review `!git diff --stat` and leave findings on @src/.

$1/$ARGUMENTS interpolate arguments, !cmd runs shell upfront, @path injects file contents. Python tools go in .neo/tools/*.py and are loaded automatically.

Project layout

src/neo/
  agent/        autonomous loop, permissions, sessions, plans, compaction
  tools/        18 built-in tools (files, shell+sandbox, web, todos, subagents…)
  providers/    streaming clients + 228-entry provider catalog (JSON)
  sandbox/      bubblewrap argv builder, capability detection, filtering proxy
  mcp/          MCP clients (stdio, StreamableHTTP), tool/prompt discovery
  lsp/  format/ language servers + formatters wired into every edit
  vcs/          git snapshots, selective restore, forks, worktrees
  plugins/      plugin loader and hook dispatch
  commands/     .neo/commands/*.md slash-command engine
  custom_tools/ .neo/tools/*.py loader
  agents/  plan/  agent roster, per-agent toolsets, plan-mode enforcement
  tui/          Textual interface: palette, dialogs, themes, session list
  auth.py       ~/.config/neo/auth.json key store (0600)

Tests

python -m pytest          # 339 passed, 4 skipped

License

MIT. See LICENSE.

Release files for neo-agnt 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for neo-agnt 0.1.0
File Size Uploaded
neo_agnt-0.1.0.tar.gz 178.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for neo-agnt 0.1.0
File Interpreter ABI Platform
neo_agnt-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 350.9 kB

Release files / neo_agnt-0.1.0.tar.gz

Download URL neo_agnt-0.1.0.tar.gz
Size 178.3 kB
Tags Source
SHA-256 checksum
How to use checksums
4cd514e32d4db15155c43677d7a5d1d31d1ee460ce931c7ea19ade535734a99b
BLAKE2b-256 checksum
How to use checksums
1db459ae886c5c6ac4a9eb33a0d07ac049b2ad7f9a5080210d0673031cc22077
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / neo_agnt-0.1.0-py3-none-any.whl

Download URL neo_agnt-0.1.0-py3-none-any.whl
Size 172.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3b100f6d3f13d6b440e4c6c1193f173d5156f5240a570e35003babb971435c8b
BLAKE2b-256 checksum
How to use checksums
7a406b9310aabf2d0d8abc0014d48225e548476caffe91c1d019cfd6e8c2c775
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release history Release notifications | RSS feed

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page