neo
neo is a lightweight, autonomous terminal coding agent. Describe a task — 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
One install, no daemon, no browser, no IDE extension, no account.
Install
Requires Python 3.10+.
pipx install neo-agnt # recommended (isolated, neo lands on PATH)
# or
pip install neo-agnt
Update to the latest version:
pipx upgrade neo-agnt
# or
pip install --upgrade neo-agnt
Sandboxed bash needs bubblewrap on Linux:
sudo apt install bubblewrap socat
Set an API key — first match wins (env → ~/.config/neo/auth.json → neo.json):
export ANTHROPIC_API_KEY="sk-..."
Ubuntu 24.04+ blocks system-wide pip install (PEP 668) — use pipx or a
virtualenv instead of --break-system-packages.
Use
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
In the TUI: / opens the command palette, @ completes file paths,
Ctrl+C cancels the running turn, typing mid-run queues your message for
the next turn. /login stores a provider key, /logout removes it,
/model switches models within the active provider.
Configure
~/.config/neo/neo.json (global); ./neo.json or ./.neo/neo.json
(project overrides global):
{
"model": "anthropic/claude-sonnet-4-6",
"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"] }
} }
}
Permissions are {tool: {pattern: allow|ask|deny}}, last match wins. Every
command in a compound (a && b) is evaluated — one deny blocks the whole
thing. neo config prints the fully resolved configuration.
Custom OpenAI-compatible providers are easiest via /login → custom:
a wizard collects the provider id, display name, base URL, API key (literal
or {env:VAR}), and model ids with display names, then saves everything to
~/.config/neo/neo.json:
{ "providers": { "my-proxy": {
"title": "My Proxy",
"base_url": "https://proxy.internal/v1",
"protocol": "openai",
"models": ["model-a", "model-b"],
"model_names": {"model-a": "Model A"},
"default_model": "model-a",
"api_key_env": "PROXY_KEY"
} } }
/model then lists those models directly — including their display names.
Sandbox
On Linux, bash runs in bubblewrap: namespaces, read-only root, filtered
egress. Every result is tagged [sandbox] active (network=…) so you always
know what isolation was in effect.
{ "sandbox": {
"mode": "auto",
"network": "filtered",
"allowedDomains": ["github.com", "*.pypi.org"],
"denyRead": ["~/.ssh", "~/.aws"],
"denyWrite": [".env"],
"passEnv": ["PATH", "HOME", "LANG"]
} }
mode: auto (warn, run unsandboxed if bubblewrap is missing) ·
strict (fail loudly) · off.
network: none (offline) · filtered (domain-allowlist proxy) · full.
Environment is cleared except passEnv; secret-looking variables are
stripped.
Plan mode
Non-trivial work is drafted to .neo/plans/ first; edits stay locked to
the plan until you approve the plan_exit prompt. Nothing outside the plan
is touched before approval.
Safety net
neo snapshot # snapshot the worktree (git tree-hash handle)
neo restore <id> # restore files (post-snapshot files are deleted)
neo restore <id> --dry-run # preview what a restore would change
neo fork # fork the session (copy-on-write)
Snapshots are taken automatically before risky tool batches, and the undo
tool (approval-gated) rolls back the last mutation.
Extend
MCP — servers in neo.json; their tools appear as server_tool, their
prompts become slash commands. One failing server never takes down the rest.
Plugins — ~/.neo/plugins/*.py exposing hooks:
def on_tool_after(event):
if event.tool == "bash" and event.result.is_error:
notify("bash failed")
hooks = {"tool.execute.after": on_tool_after}
Hooks: tool.execute.before/after, permission.ask, chat.params,
session.end. Plugins can also register their own tools.
Commands — .neo/commands/*.md with optional frontmatter; $1…$n
and $ARGUMENTS interpolate arguments.
Tools — .neo/tools/*.py loaded automatically.
Internals
| Area | Notes |
|---|---|
| Loop | plan → act → verify; parallel tool calls, backoff retries, 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 |
| Providers | 228 in the catalog (OpenAI / Anthropic / Gemini protocols); any OpenAI-compatible base_url works |
| Code intel | LSP diagnostics (pyright, tsserver, gopls, rust-analyzer, eslint) + formatters after every edit |
src/neo/
agent/ 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, detection, filtering proxy
mcp/ clients (stdio, StreamableHTTP), tool/prompt discovery
lsp/ format/ language servers + formatters wired into every edit
vcs/ snapshots, selective restore, forks, worktrees
plugins/ plugin loader and hook dispatch
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 # 452 passed, 4 skipped
License
MIT. See LICENSE.
Release files for neo-agnt 0.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| neo_agnt-0.1.4.tar.gz | 246.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| neo_agnt-0.1.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 467.0 kB
Release files / neo_agnt-0.1.4.tar.gz
| Download URL | neo_agnt-0.1.4.tar.gz |
|---|---|
| Size | 246.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9657c9f3f121d4f2346350ffd0dca346f25ccdd1fdc01ab56e6fb43f8a4fc8d7
|
|
BLAKE2b-256 checksum How to use checksums |
da727529aaf42988e69bdc6a5f140a69b6b2cfdef25bd1c3b0325034a81612d3
|
| 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.4-py3-none-any.whl
| Download URL | neo_agnt-0.1.4-py3-none-any.whl |
|---|---|
| Size | 220.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1b651332cc88436fe65df5870af8caf3324b037942594d7cc6c600fa0cf58cbd
|
|
BLAKE2b-256 checksum How to use checksums |
07b946be587a125f466dbf5b19151b387eb2edc91c6054d80b85a464f542f7b7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|