Model or dataset
sanbuphy/nanoAgent avatar
sanbuphy/nanoAgent

sanbuphy/nanoAgent: a ~100-line Python agent you can read in one sitting

If you can read ~100 lines of Python, you understand agents.

751 stars288 forksPythonMIT

At a glance

What is it?
nanoAgent is a teaching-scale implementation of an OpenAI function-calling agent that can run bash, read files and write files. The README claims roughly 100 lines; the repository also ships two larger variants, agent-plus.py and agent-claudecode.py, which the README does not describe.
Who is it for?
nanoAgent is for engineers who want to read an agent loop end to end before trusting a framework, and it is a poor fit for anyone who needs sandboxing, permission prompts or provider independence, because the README documents none of those. The repository also contains agent-plus.py and agent-claudecode.py, which the README never explains, so read those two files before assuming agent.py is the whole project.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem nanoAgent solves: an agent loop small enough to audit

Most agent frameworks ask you to accept a large dependency before you can see what the loop actually does. nanoAgent takes the opposite position. The README states the project is "a minimal implementation of an AI agent using OpenAI's function calling" and that the agent can execute bash commands, read files, and write files. The stated audience is anyone who can read about 100 lines of Python, which is why the README opens with a Thoreau line about seeing rather than looking.

The scope is deliberately narrow. There is no planner, no memory store, no retriever, no tool registry beyond three functions, and no multi-agent coordination. The value on offer is legibility: you can hold the entire control flow in your head, then decide which parts of a real framework you actually need. The README points readers who want the modern tool-discovery story toward a companion repository, nanoMCP, rather than growing this one.

That narrowness is also the boundary. If your task needs persistent state between runs, human approval before a shell command fires, or a model other than one reached through the OpenAI-compatible chat completions API, this project does not address it. The README does not document rollback, undo, or any confirmation step before a tool runs.

How the agent loop works: model, tool calls, results, repeat

The README describes the flow in five numbered steps: receive a task from the user, decide which tools to use, execute the tools, return results to the model, and repeat until the task is complete. The mechanism is OpenAI function calling. Tools are declared as a list of objects with a type of function and a function schema, and the model responds either with tool calls or with a final text answer.

The loop the README shows is short. It iterates up to max_iterations, calls client.chat.completions.create with the model, the accumulated messages and the tools list, and returns the message content as soon as there are no tool_calls. Otherwise it executes each requested function, looks it up in an available_functions mapping by name, and appends a message with role tool and the result. That appended tool message is what lets the model see what happened and decide the next step.

The README notes recent hardening: when a tool call contains malformed JSON arguments or names a tool that does not exist, the loop does not crash. Those cases are returned to the model as explicit tool errors, so the model can correct itself on the next iteration. This matters more than it sounds, because a single malformed argument used to be enough to end the run. The cap on iterations is the only termination guard the README mentions; the README does not describe a timeout, a cost ceiling, or a token budget.

Installing nanoAgent and running a first task

Installation is a single pip command against the requirements file. That file lists exactly one dependency, openai, so there is no build step and no compiled extension.

bash
pip install -r requirements.txt

Next, set the environment variables the README documents. Only the API key is required; the base URL and the model name are marked optional, and the model defaults to gpt-4o-mini in the examples. On macOS or Linux:

bash
export OPENAI_API_KEY='your-key-here'
export OPENAI_BASE_URL='https://api.openai.com/v1'  # optional
export OPENAI_MODEL='gpt-4o-mini'  # optional

Windows users get PowerShell and CMD variants in the README, using $env: and set respectively. Once the key is exported, the quick start is a single command with the task as a quoted argument. The README gives three examples, including this one:

bash
python agent.py "list all python files in current directory"

What you should see is the agent deciding to call execute_bash, the command output coming back as a tool message, and a final natural-language answer. The README also shows "create a file called hello.txt with 'Hello World'" and "read the contents of README.md" as first tasks, which exercise write_file and read_file. Because the loop runs in your current working directory, start it somewhere you are willing to let a shell command run.

execute_bash is the whole feature and the whole risk

The three tools are not equal in consequence. read_file and write_file touch the paths they are given. execute_bash, described in the README as "Run any bash command", does not. There is no allowlist, no path jail, no dry-run mode and no confirmation prompt documented anywhere in the README.

The practical result is that the model's judgement is the only thing standing between a plausible-sounding task and an arbitrary command on your machine. A task phrased loosely can lead the model to compose a command you did not intend, and the loop will run it and feed the output back. The malformed-JSON hardening described above keeps the loop alive; it does not make tool execution safer.

There is a second, quieter failure mode. The loop terminates when the model stops requesting tools or when max_iterations is reached. The README does not say what happens at the cap: whether the agent returns partial work, an error, or nothing useful. If you hit it, inspect the messages list rather than the final string. For anything beyond a scratch directory, the honest reading is that this project is a study aid, not a runtime you point at a production host.

The two files the README does not mention

The repository root contains agent.py alongside agent-plus.py and agent-claudecode.py, plus a tests directory. The README describes only agent.py and its roughly 100 lines. It does not explain what agent-plus.py adds or how agent-claudecode.py differs, and no release notes are available to fill the gap.

The filename agent-claudecode.py suggests a variant aimed at Claude Code rather than the OpenAI chat completions path, but that is inference from the name, not something the documentation states. Treat both files as unverified until you read them. This is the sharpest documentation gap in the project: a reader who takes the README at face value will not know that two other entry points exist, and a reader who finds them will get no guidance on which to use.

A tests directory is present, which is a reasonable signal that the loop has some regression coverage, but the README does not describe how to run those tests or what they assert. Do not assume the tests cover the tool-execution paths just because the directory exists.

nanoAgent compared with a full agent framework

The natural alternative is a general-purpose agent framework such as LangChain or one of the graph-oriented runtimes built on top of it. The difference is not features; it is where the complexity lives. A framework gives you a tool abstraction, memory backends, callbacks, tracing and multi-step orchestration, and in exchange you inherit its abstractions, its version churn and a debugging surface that spans several packages.

nanoAgent inverts that trade. You get one file, one dependency and one loop, and you write anything else yourself. If your agent needs to remember yesterday's conversation, you add that. If it needs to call an internal API, you add a function to the tools list and to available_functions. The README's pointer to nanoMCP is the project's own suggestion of where to go next: if you want modern tool discovery rather than hand-declared schemas, that is a different repository.

The honest comparison is that a framework will get a demo running faster and this will get you understanding faster. For a team that already runs a framework in production, swapping in nanoAgent would mean re-implementing observability, retries and permissions that the framework already provides.

Maintenance, licence and upgrade cost

The repository is not archived, and the last push was on 2026-03-13. That is roughly six months before the current date, so there is no basis for calling it actively developed; the accurate statement is simply when the last push happened. There are no retrieved releases, so there is no versioned upgrade path to follow. Upgrades mean pulling the current agent.py and reading the diff.

That is a low cost in absolute terms because the surface is small, but it is not zero: the README notes recent hardening around malformed tool-call arguments, which is exactly the kind of change that alters behaviour without altering the interface. If you vendor agent.py into your own tree, you own that diff.

The licence is MIT, stated in the README and shipped as a LICENSE file. MIT is permissive and imposes essentially no conditions beyond preserving the notice, but this is a description of the licence text, not legal advice; read LICENSE yourself if the distinction matters to your organisation. The single openai dependency is the thing to watch over time, since the loop is written directly against the chat completions API and its function-calling shape.

Editorial conclusion

nanoAgent is for engineers who want to read an agent loop end to end before trusting a framework, and it is a poor fit for anyone who needs sandboxing, permission prompts or provider independence, because the README documents none of those. The repository also contains agent-plus.py and agent-claudecode.py, which the README never explains, so read those two files before assuming agent.py is the whole project. Verify first that your OPENAI_MODEL supports function calling and that you are willing to let execute_bash run arbitrary commands on the machine where you start it.

Frequently asked questions

What is nanoAgent and who is it for?

It is a minimal AI agent built on OpenAI function calling that can execute bash commands, read files and write files. The README frames it for people who can read about 100 lines of Python and want to see the whole loop.

How do I install nanoAgent?

Run pip install -r requirements.txt, then export OPENAI_API_KEY. OPENAI_BASE_URL and OPENAI_MODEL are optional and the examples use gpt-4o-mini.

Which tools does nanoAgent give the model?

Three: execute_bash, read_file and write_file. The README describes execute_bash as running any bash command, with no allowlist or confirmation step documented.

Is nanoAgent safe to run on my own machine?

The README documents no sandbox, path restriction or approval prompt, and execute_bash runs arbitrary commands in your current directory. Run it somewhere you are willing to let a shell command execute.

What are agent-plus.py and agent-claudecode.py in the nanoAgent repository?

The README does not explain them. Both files sit in the repository root next to agent.py, and the README only describes agent.py, so read the files directly if you need to know.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. sanbuphy/nanoAgent on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/sanbuphy-nanoagent.svg)](https://hysenlabs.com/projects/sanbuphy-nanoagent)