autocode is out — a coding agent that fits in a single Python file, ships with exactly one tool, and is allowed to edit its own source while it works. No dependencies, no framework: the least an agent needs, if it gets to build the rest.
Agent frameworks have a habit of growing. Every release adds a tool, every tool
adds a schema, every schema adds a paragraph to the system prompt, and before long
the model spends its first few thousand tokens reading instructions about
instructions. Abacus sits deliberately at the full-featured end of that: plans,
approvals, subagents. autocode is the experiment at the other end — what is the least an agent needs, if it is allowed to build the rest itself?
The answer we shipped: one Python file, one tool, the standard library, and
permission to rewrite itself.
autocode on GitHub: empero-org/autocode
One file, and it's yours #
Install once, then run autocode in a project. The first run copies runner.py
into that directory and starts it. That file is the whole agent — the loop, the
streaming client, sessions, compaction, the REPL — in about 640 lines, with no
imports outside the standard library.
It is copied, not imported, on purpose. The agent is told where its own source
lives and that it may improve it. Between steps the runner checks whetherrunner.py changed; if the new version compiles, it saves the session, keeps the
previous version in .autocode/runner.prev.py, re-execs itself and carries on
with the same task. If it doesn't compile, the model is told about the syntax
error and the working version keeps running.
So every project ends up with its own agent, shaped by the work done there.autocode --diff shows how far it has drifted from the one we shipped.autocode --reset puts it back.
One tool #
The model gets bash. Nothing else. Commands run exactly as written — no
wrappers, no rewriting, no parser second-guessing the model. The runner only does
what a shell can't do for itself: a timeout that kills the whole process group, a
closed stdin so nothing waits for a human, a working directory that persists
between calls, and long output cut to its head and tail with the full text saved
to a file the agent can page through.
Search, edit, test, git — everything a model reaches for is already a command
away.
Tools it writes itself #
When a shell isn't enough, the agent writes a tool. Any file in.autocode/tools/ that defines a SCHEMA and a run() function is picked up on
the next step. A tool that fails to import doesn't disappear: it shows up to the
model marked BROKEN, with the error attached, so the agent can fix what it
wrote. The tools are plain Python in your repository — worth committing, if they
turn out to be good.
A system prompt you can read in ten seconds #
Three lines. Who it is and where; work until the task is done and verify as you
go; your own source is editable; here is how to add a tool. Plus the project'sAGENTS.md, if there is one. That's the whole prompt. Everything else the model
knows about your project, it found out with the shell.
Long sessions, honestly #
A small agent still runs long sessions, so compaction had to be right. When the
context passes 80% of the window, the model summarizes the conversation and the
summary replaces it — except your newest message and the latest step, the last
model message with its tool results, which stay word for word. The summary
request reuses the exact prefix of a normal request, so providers with prompt
caching reuse the cache.
We found a bug in it before release, and it's worth telling. The first version
asked for the summary with tool_choice: "none". Some OpenAI-compatible servers
ignore that field, so a model can answer "summarize this" with a tool call and a
one-line preamble — and that preamble became the entire new context. Against a
scripted fake server, a session's request and its failing test output were
replaced by "Let me look at the test file first."
Now a reply that isn't a summary is rejected and retried as a plain transcript
with no tools to call, a failed compaction never blocks the session, and the full
transcript is archived before anything is replaced. There's a test for exactly
that case. Not a feature. A fix we'd rather tell you about than have you find.
Any endpoint #
The first run opens a short setup. It marks the backends it can already use — a
key in your environment, a local server that's running — lists the server's
models, runs a one-line test call and saves the config. OpenAI, OpenRouter,
DeepSeek, Groq, a Qwythos on Ollama or llama.cpp: if it speaks/chat/completions, autocode runs on it.
Thinking is read from whichever field your server uses - reasoning_content, reasoning, OpenRouter's reasoning_details, or <think> tags left in the
answer and shown in the terminal next to the reply, with markdown, highlighted
code and LaTeX drawn as Unicode. The renderer is standard library too.
What it doesn't do #
autocode gives a model a shell and no approval step. That is the point of it, and
it is also the reason to run it somewhere you can afford to be surprised: a
container, a VM, a repository you can reset. It needs bash, so Linux and macOS.
And an agent that rewrites itself can rewrite itself badly — that's whatrunner.prev.py and --reset are for. If you want every change shown as a diff
before it lands, that's Abacus.
We built autocode to answer a narrow question: how little an agent can start with
and still do real work. It turned out to be one file, one tool, and a model that
is allowed to make the rest.
pip install empero-autocode
cd your-project
autocode
Get it on GitHub: empero-org/autocode ·
PyPI: empero-autocode
*autocode is open source, Apache-2.0. Point it at a Qwythos on your own machine
and see what it turns itself into.*