Back to news

Code

Custom Agents in 50 Lines of Code.

You do not need a framework to build a useful agent. A minimal agent needs only a loop, a model, tools, and memory. Here is how to build one from scratch.

AI Kick Start editorial image for Custom Agents in 50 Lines of Code.

Decision

Start narrow

Use the article to decide the smallest useful workflow worth testing before expanding the system.

Risk to watch

Hype drift

Avoid turning a practical adoption step into a broad transformation promise nobody can verify.

Proof to collect

Business signal

Write down the owner, data boundary, review point, and measurable outcome before the first build.

TL;DR

TL;DR: Frameworks like Hermes and OpenClaw can do a lot, but they bring a lot of weight with them. When you only need an agent that does one job well, you can write it in about 50 lines of Python. The trick is realising what an agent actually is: a loop that calls a model, runs whatever tools the model asks for, and keeps a running memory of what happened.

Key takeaways

  • An agent is a loop: call the model, run the tools it asks for, feed the results back, repeat until it answers in plain text ([OpenAI Cookbook](https://developers.openai.com/cookbook/examples/how_to_call_functions_with_chat_models)).
  • The OpenAI API generates tool calls but never executes them. Running the function and returning the result is your responsibility ([function calling guide](https://developers.openai.com/api/docs/guides/function-calling)).
  • The `messages` list is the whole memory. Persist it to disk and the agent remembers across sessions.
  • Start small and single-purpose. Add tools, guardrails, approval gates, and planning only when the job calls for them.
  • Frameworks like Hermes and OpenClaw earn their place once you need messaging, multi-agent work, or team sharing, not before.

Analysis

There is a quiet assumption in a lot of AI projects right now: that building an "agent" means adopting a heavyweight framework first. Pick the platform, learn its abstractions, wire up its config, then maybe get to the thing you wanted to build. For plenty of teams that ordering feels backwards, and it slows the first useful result down to a crawl.

Here is the part that tends to surprise people. The thing those frameworks wrap is small. An agent that reads files, writes files, and runs a command on your behalf fits in a single Python file you can read in one sitting. No magic, no hidden machinery. Just a model, a short list of tools, and a loop.

That matters for a working business because it changes the question. Instead of "which framework do we standardise on," you can ask "what is the smallest thing that solves this job," build it in an afternoon, and only reach for a framework once you actually hit a wall. The example below is the whole pattern, start to finish, and everything that the big platforms add sits on top of it.

The Minimal Agent

# agent.py - A minimal coding agent in 50 lines
import json
from openai import OpenAI

client = OpenAI()

# Define tools
def read_file(path):
    try:
        return open(path).read()
    except:
        return f'Error reading {path}'

def write_file(path, content):
    open(path, 'w').write(content)
    return f'Wrote {path}'

def run_command(cmd):
    import subprocess
    result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
    return result.stdout[:2000] or result.stderr[:2000]

# Tool schema for the model
tools = [{
    'type': 'function',
    'function': {'name': 'read_file', 'description': 'Read a file',
                 'parameters': {'type': 'object', 'properties': {'path': {'type': 'string'}}, 'required': ['path']}}
}, {
    'type': 'function',
    'function': {'name': 'write_file', 'description': 'Write a file',
                 'parameters': {'type': 'object', 'properties': {'path': {'type': 'string'}, 'content': {'type': 'string'}},
                                'required': ['path', 'content']}}
}, {
    'type': 'function',
    'function': {'name': 'run_command', 'description': 'Run a shell command',
                 'parameters': {'type': 'object', 'properties': {'cmd': {'type': 'string'}}, 'required': ['cmd']}}
}]

# The agent loop
messages = [{'role': 'system', 'content': 'You are a coding assistant. Use tools to help.'}]
messages.append({'role': 'user', 'content': input('Task: ')})

while True:
    response = client.chat.completions.create(model='gpt-4.1', messages=messages, tools=tools)
    message = response.choices[0].message
    messages.append(message)
    
    if not message.tool_calls:
        print(message.content)
        break
    
    for call in message.tool_calls:
        fn = {'read_file': read_file, 'write_file': write_file, 'run_command': run_command}[call.function.name]
        result = fn(**json.loads(call.function.arguments))
        messages.append({'role': 'tool', 'tool_call_id': call.id, 'content': result})

How It Works

  1. Define tools: Three tools cover the basics: read a file, write a file, and run a command.
  2. Describe tools: The model can't guess what your functions do. It needs a JSON schema for each one, which is what the tools list provides. The OpenAI function calling guide is worth a read here, because the API generates the function name and arguments but never runs the function for you. That part is your job.
  3. Run the loop: Call the model with the full conversation so far. If it asks for tool calls, run them and append the results. If it answers with plain text instead, print it and stop. This call-execute-feed-back rhythm is the standard agentic loop for OpenAI chat completions.
  4. Maintain history: The messages list is the agent's memory. Every model reply and every tool result gets appended to it, so the next turn sees everything that came before.

A couple of mechanics worth naming, since they trip people up. The SDK call is client.chat.completions.create(model=..., messages=..., tools=...), and the reply lands at response.choices[0].message with a tool_calls attribute on it. Each tool call carries call.id, call.function.name, and call.function.arguments (which arrives as a JSON string, hence the json.loads). You hand the result back as a message with role set to 'tool' and the matching tool_call_id. The model used here, gpt-4.1, is a current OpenAI model built for instruction following and tool calling, with a million-token context window (GPT-4.1 docs).

Extending the Agent

You can grow this in obvious directions. Add more tools (search_code, list_directory, fetch_url, send_slack) by writing the function and adding its schema. Give it memory across sessions by saving messages to SQLite and reloading it next time. Add a guardrail that rejects any tool call matching a forbidden pattern. Put in an approval gate so it asks before it runs write_file or run_command. Or insert a planning step that thinks through the work before it touches a single tool.

None of these require throwing out the loop. They bolt onto it.

When to Use the Minimal Agent

Reach for this pattern when you need a single-purpose agent, when the overhead of a framework isn't earning its keep, when you want to actually understand how agents work under the hood, or when you're prototyping before you commit to anything bigger.

Move to a framework like Hermes or OpenClaw when the requirements grow past it: messaging integrations, a learning loop, multi-agent orchestration, or sharing agents across a team. Both are described in 2026 write-ups as the two dominant agent frameworks, though the specifics there come from secondary coverage rather than firsthand testing (The New Stack, innFactory).

The 50-line agent isn't a toy. It's the core pattern those frameworks are built around, and once you've seen it work, the bigger platforms stop looking like magic and start looking like sensible additions to a loop you already understand.

Source trail

Primary references to keep this briefing grounded

AI and automation information changes quickly. Use these official or primary references to verify the claims, pricing, product behaviour, and compliance details before committing budget or production data.

What to do next

  1. Pick the smallest useful workflow that proves the pattern.
  2. Write down the owner, data boundary, review point, and success measure.
  3. Review the result after the first real run and decide whether to scale, change, or stop.

Want help applying this? Explore AI agent design systems.

AI Kick Start is an Illawarra-based AI studio in Figtree, helping businesses across Wollongong, Shellharbour and Kiama and right across Australia put AI to work.

Explore with AI

Use the article as a decision prompt

Summarise this AI Kick Start article for an Australian business owner. Focus on the useful decision, the risks, and the first practical next step: Custom Agents in 50 Lines of Code

Turn this into a practical roadmap.

Use the guide as a starting point, then map the first workflow worth building.

Book an AI strategy call