CLI agent

dreamcode

A terminal coding agent that reads your code, edits it, and runs your tests. It is powered by this site's free API, has no dependencies, and is small enough to read in one sitting.

Install
curl -L https://dreamprompting.com/dreamcode.tar.gz | tar xz
cd dreamcode

export DREAMPROMPTING_API_KEY=dp-your-key-here
python3 -m dreamcode "add retry logic to the upload handler"

Or pip install -e . from that directory to get a dreamcode command on your path. Run it with no task for an interactive session. A free key comes from your account page.

What a run looks like

This is a real run against a bug where a discount function treated 10 percent as 1000 percent, with the routing detail left in so you can see failover happening mid-task:

$ dreamcode "test_discount_is_a_percentage is failing. Find the bug, fix it, run the tests."

  [1] nvidia/llama-3.3-70b-instruct · 603 ctx · 1,699 tok total
  search 'test_discount_is_a_percentage'
    1 match(es) in 2 file(s)
  [2] cohere/command-r-08-2024 · 648 ctx · 2,758 tok total
  read_file test_cart.py:1-15
  [3] cohere/command-r-08-2024 · 783 ctx · 4,052 tok total
  search 'apply_discount'
  [4] nvidia/llama-3.3-70b-instruct · 866 ctx · 6,198 tok total
  read_file cart.py:14-18
  [5] nvidia/llama-3.3-70b-instruct · 929 ctx · 8,482 tok total
  edit_file cart.py
    Edited cart.py (-1 +1 lines)
  [6] nvidia/llama-3.3-70b-instruct · 969 ctx · 10,810 tok total
  run python3 -m pytest
    exit 0

The discount was applied as a raw multiplier rather than a percentage.
Changed `amount * percent` to `amount * percent / 100` in cart.py.
Tests pass.

  7 call(s) · 13,020 in · 348 out · $0.00

Three different providers served those seven calls as free tiers hit their limits and recovered. The agent never saw a failure, and the whole task stayed under 1,400 tokens of context.

Flags

FlagWhat it does
-C, --workspace DIRThe only directory the agent may touch. Defaults to the current one.
-y, --yesDo not ask before edits or shell commands.
--no-runRemove the shell tool entirely. The agent cannot run anything.
--model IDPin a model, or leave it on auto for failover.
--max-steps NTool-calling steps per task. Defaults to 30.
-q, --quietHide the per-turn routing line.

Why the tools look the way they do

Every design decision in dreamcode comes from one constraint: the gateway accepts 32,000 input tokens, and a coding conversation is mostly file contents. An agent that reads whole files to look around runs out of room in about three turns and then starts forgetting the thing it was asked to do.

So the tools return the smallest thing that answers the question. search gives matching lines with line numbers rather than files, which turns "where is this defined" into a few hundred tokens instead of several thousand. read_file takes a line range and caps at 400 lines, so the model reads the function rather than the module. Directory listings are capped, and shell output is elided from the middle rather than the end, so both the command and the error that killed it survive.

The loop trims too. As the conversation approaches the budget it blanks the content of the oldest tool results, oldest first, while keeping every message in place. That last part matters more than it sounds: dropping an assistant message that carries tool calls, or the tool result answering it, leaves an unpaired tool_call_id that several providers reject outright. The conversation keeps its shape even when it loses its detail.

The security model, and what an audit of it found

File access is jailed to the workspace. Paths are resolved first and checked afterwards, so .. traversal, absolute paths, home-directory paths and symlinks pointing outside are all refused. That ordering is deliberate: checking before resolution is the standard way this kind of jail leaks.

Edits and shell commands require approval, and the prompt shows a diff of exactly what will change before you answer. Approval fails closed: if there is no terminal to ask, the answer is no.

An adversarial audit of that sandbox found six issues, all now fixed and covered by regression tests. They are worth listing because most of them are mistakes any agent of this shape can make:

FindingWhy it mattered
Could write .git/hooks/pre-commitInside the workspace, so the jail allowed it. Runs on your next commit.
Could rewrite .git/configRetargets origin, so the next push goes somewhere else.
Could plant a binary in venv/binShadows the interpreter you are about to run.
Model could set the shell timeoutArguments were forwarded without checking the declared schema.
Unbounded file readsA 60MB file loaded straight into memory.
Search read every file wholeSame exhaustion, reached a different way.

The common thread in the first three is that a path jail answers "is this inside the workspace" when the question that matters is "is this a file that will later be executed". Writes into .git, venv, node_modules and .github are now refused outright, regardless of what the model asks for or what you approve.

Two things the audit did not fix, because they cannot be fixed at this layer. Prompt injection is real. A README, a code comment or a vendored dependency can contain text that instructs the agent, and the model cannot reliably tell that from your request. The approval prompt is what stands between an injected instruction and a command running on your machine, which is the argument for leaving it on. And an approved command can do anything you can do. A shell is a shell. The --no-run flag exists for when that is not a trade you want to make.

One habit worth adopting: pass the key through DREAMPROMPTING_API_KEY rather than the --api-key flag, since command-line arguments are visible to other processes on the same machine through ps.

Questions people actually ask

What does dreamcode need to run?
Python 3.9 or newer and a free API key. There are no third-party dependencies at all, because the gateway is plain HTTP and JSON and both are in the standard library.
How is this different from aider?
aider is more capable and far more mature, and you should use it if it suits you. dreamcode is small enough to read in one sitting, which makes it useful as a reference for how a tool-calling loop actually works, and it is built specifically around a 32,000 token ceiling rather than assuming a large context window.
Can it run arbitrary shell commands?
Yes, and it asks first by default, showing the exact command before you approve it. The --no-run flag removes the shell tool entirely so the agent cannot run anything, and --yes removes the prompt, which is worth reserving for a workspace you are willing to lose.
Can it escape the directory I point it at?
Not through the file tools. Paths are resolved first and then checked against the workspace root, so relative traversal, absolute paths, home-directory paths and symlinks pointing outside are all refused. The shell tool is a different matter: a command you approve can do anything your user account can do.
What did the security audit find?
Six issues, all fixed. Three were writes that would become code execution: a git hook, .git/config, and a planted binary in venv/bin were all inside the workspace and therefore allowed. One let the model pass its own timeout to the shell tool because arguments were forwarded without checking them against the declared schema. Two were memory exhaustion from reading very large files. The path jail itself held against every escape attempted.
Does it edit my tests to make them pass?
It did once during testing, which is why there are now two guards. The prompt forbids editing a test to make it pass, and the approval prompt flags any edit to a file that looks like a test so you see it before it happens. Neither is a guarantee, so review diffs that touch tests.
How does it stay under the 32k context limit?
By never reading more than it needs. Search returns matching lines rather than whole files, reads take a line range and cap at 400 lines, and shell output is elided from the middle so both the command and its failure survive. When the conversation approaches the budget the loop blanks the oldest tool results while keeping every message in place, because dropping an assistant turn carrying tool calls leaves an unpaired id that several providers reject.

Prefer your own agent?

Cline, aider, Continue, OpenCode, Codex CLI and Zed all connect to the same free endpoint.