How do you build a simple AI agent that can edit code?
To build a simple AI agent that can edit code, give a model an editing tool through its provider's API, run every tool call it asks for in your own code, send the result back, and repeat until it stops asking. That loop plus one guarded file tool is the whole agent; most of the work is in the guards.
Cite
CodeLifter Forum, "How do you build a simple AI agent that can edit code?", https://codelifter.com/forum/posts/how-do-you-build-a-simple-ai-agent-that-can-edit-code/, accessed 2026-11-12.- CodeLifter editorsStaffStaff, CodeLifter ·
What is the smallest thing that counts as an agent?
Anthropic's engineering post Building effective agents puts it in one line: agents "are typically just LLMs using tools based on environmental feedback in a loop." A tool here is a function your program offers the model, described by a name, a description and an input schema. The model never touches your disk. It returns a structured request; your code decides whether to run it. The AI agent thread explains how that differs from a chatbot.
OpenAI's function calling guide describes the same loop in five steps: send the request with tools, receive a tool call, execute it in your application, send the output back, and receive a final answer "(or more tool calls)". Anthropic's API works the same way: a response with
stop_reason: "tool_use"containstool_useblocks, and you reply withtool_resultblocks.Part Your job or the model's? In the example below Tool definition Yours Anthropic's built-in text editor schema Choosing a tool call The model's It asks to view,createorstr_replaceRunning the call Yours run_tool()Guarding the call Yours safe(), the single-match check and the backupStopping Both The model stops asking, or the 10-turn cap ends it Step by step: a file-editing agent in Python
This follows Anthropic's text editor tool documentation, read on 16 October 2026, which defines a tool type
text_editor_20250728namedstr_replace_based_edit_toolwith the commandsview,create,str_replaceandinsert. CodeLifter has not run this code; treat it as a sketch to check against the current docs.- Use Python 3.9 or later (the path check relies on
Path.is_relative_to). Install the SDK withpip install anthropicand setANTHROPIC_API_KEYin your shell, never in the file. - Make a throwaway folder called
demowith one broken file in it, and put it under git. - Save this as
agent.pynext to it:
import pathlib, shutil, anthropic ROOT = pathlib.Path("demo").resolve() TOOLS = [{"type": "text_editor_20250728", "name": "str_replace_based_edit_tool"}] client = anthropic.Anthropic() def safe(path): p = (ROOT / path).resolve() if not p.is_relative_to(ROOT): raise ValueError("path is outside the project folder") return p def run_tool(inp): p, cmd = safe(inp["path"]), inp["command"] if cmd == "view": return p.read_text() if p.is_file() else "\n".join(x.name for x in p.iterdir()) if cmd == "create": p.write_text(inp["file_text"]) return "Created" if cmd == "str_replace": text = p.read_text() n = text.count(inp["old_str"]) if n != 1: raise ValueError(f"Found {n} matches; give more context for exactly one") shutil.copy(p, f"{p}.backup") p.write_text(text.replace(inp["old_str"], inp["new_str"])) return "Edited" raise ValueError(f"Command {cmd} is not supported here") messages = [{"role": "user", "content": "Fix the syntax error in primes.py"}] for turn in range(10): reply = client.messages.create(model="claude-opus-5-5", max_tokens=2048, tools=TOOLS, messages=messages) messages.append({"role": "assistant", "content": reply.content}) if reply.stop_reason != "tool_use": break results = [] for block in reply.content: if block.type == "tool_use": try: out, err = run_tool(block.input), False except Exception as e: out, err = f"Error: {e}", True results.append({"type": "tool_result", "tool_use_id": block.id, "content": out, "is_error": err}) messages.append({"role": "user", "content": results})- Run
python agent.py, thengit diffto see exactly what changed.
The model name is the one in the docs' own examples; swap in whichever current model you have access to.
Why are the guards the important part?
Every guard above comes from a vendor recommendation, not from taste:
- Paths. The text editor page tells you to "Validate file paths to prevent directory traversal".
safe()resolves the path and refuses anything outsidedemo. Anthropic's agents post adds that the model made mistakes with relative paths after moving out of the root, so its team "changed the tool to always require absolute filepaths". - Exactly one match. The docs show an error for a
str_replacethat matches several places: "Please provide more context to make a unique match." Returning that as an error lets the model try again instead of editing the wrong line. - Backups. The page says to "Create backups before making changes". Git does this better, which is why step 2 matters.
- Errors go back to the model. Each failure is returned with
"is_error": true, so the model reads it and adjusts. - A turn cap. The agents post mentions "stopping conditions (such as a maximum number of iterations) to maintain control". Without one, a confused loop keeps spending tokens.
The same post warns that agents bring "higher costs, and the potential for compounding errors" and recommends "extensive testing in sandboxed environments". So run this in a container or a throwaway folder, never in your home directory.
What would you add next?
Human approval. Before
run_toolwrites anything, print the file name,old_strandnew_str, and askApply? [y/N]. If the answer is no, return an error result saying the edit was refused, so the model knows to stop or try something else. That one prompt turns the loop from autonomous to supervised.A test tool. A
run_teststool is the usual next step: it gives the model what the agents post calls "ground truth" from the environment. Run it with a fixed command only, not arbitrary shell input. If you want the same tools in several apps, wrap them in an MCP server instead, as in the simple MCP server thread. The CodeLifter API providers page lists fourteen model APIs and which ones accept the OpenAI request format, useful if you port the loop, and the agents directory shows how finished coding agents handle the same problems.Short version
- An agent is a model, some tools and a loop that runs the tool calls the model asks for.
- You execute every call yourself, so you decide what is allowed.
- Validate paths, require a single match for edits, keep backups and cap the turns.
- Test in a throwaway folder under git and read
git diffafter each run.
- Use Python 3.9 or later (the path check relies on
Write something first.
Give people something to work with: at least 30 words on what happened and what you tried.
That is too long. Keep it under 6,000 characters.
Write the question as the title, 15 to 140 characters, no links.
Pick a category.
Add a name (2 to 40 characters, no links).
That email address does not look right.
That was quick. Read the thread, then try again.
The form expired. Reload the page and post again.
Something went wrong with the form. Reload and try again.
Please complete the check and post again.
Limit reached for now. Try again later.
This thread is closed to new replies.
This thread no longer accepts replies.
Something went wrong with the form. Reload and try again.
Post a reply or question first (name and email), then this browser can vote, edit and accept answers.
You cannot vote on your own post.
Only the author (within 30 days) or the forum team can do that.
That email already has an account. Use your sign-in link instead.
New accounts are paused for the moment. Try again later.
That was already posted.
1 answer
- CodeLifter editorsStaffStaff, CodeLifter ·
Do you need a framework like an agent SDK to build an AI agent? No, and for a first one it can hide what is happening. Anthropic's Building effective agents post recommends "finding the simplest solution possible, and only increasing complexity when needed", which "might mean not building agentic systems at all." The loop in this thread is about forty lines of plain Python. What a helper library saves you is the bookkeeping. Anthropic's tool runner page says the SDK helper "handles the agentic loop, error wrapping, and type safety", and lists it as beta in the Python, TypeScript, C# and Go SDKs. The same page names the trade-off: when you need "human-in-the-loop approval, custom logging, or conditional execution", it points you back to the manual loop. A file-editing agent is exactly the case where you may want to approve each write, so writing the loop yourself first is a reasonable choice. Once you understand it, a helper or a full agent SDK saves code without changing the shape.