Python Agent Harness Clone

A tiny, free‑tier clone of Strands Agents Harness‑SDK

Welcome to another official UVF IT build guide! In the next 45 minutes you’ll spin up a minimal Python‑only agent harness that mimics the core of Strands Agents Harness‑SDK – no paid APIs, just the standard library and SQLite.

We’ll scaffold a Flask app, define a simple agent model, expose a tiny REST API, run it locally, and verify it works – perfect for beginners eager to experiment with AI‑agent patterns.

Before you start…

Minimal Harness Clone Architecture
LOCAL RUNTIME reads/writes HTTP requests Flask Agent Harness Python + SQLite SQLite DB Browser / curl client
1

Phase 1: Scaffold the project

Create a fresh virtual environment so our dependencies stay isolated from any other Python work you have. Then install Flask (the lightweight web framework) and SQLAlchemy (the ORM that will talk to SQLite). This gives us a tiny but functional stack to host our agent harness.

We also set up a basic folder layout: a top‑level app.py for the Flask entry point and a models.py that will later hold our data definitions. All files live in the same directory for simplicity.

python -m venv venv
# Activate the environment
# Windows:
#   venv\Scripts\activate
# macOS/Linux:
source venv/bin/activate

# Upgrade pip and install required packages
pip install --upgrade pip
pip install Flask SQLAlchemy

# Create project skeleton
mkdir harness_clone && cd harness_clone
touch app.py models.py
2

Phase 2: Define the agent model (data)

Our clone only needs to remember an identifier for each agent and a JSON‑encoded snapshot of its internal state. SQLAlchemy makes this trivial: we declare a Python class that maps to a SQLite table, and SQLAlchemy handles the CRUD operations for us.

The state column uses the JSON type when available (SQLite supports it via sqlite_json in newer versions) but falls back to a plain Text field, ensuring the code runs everywhere.

models.py

from sqlalchemy import Column, Integer, String, Text, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
import json

Base = declarative_base()

class Agent(Base):
    __tablename__ = 'agents'
    id = Column(Integer, primary_key=True, autoincrement=True)
    identifier = Column(String, unique=True, nullable=False)
    # Store JSON as text; SQLAlchemy will give us a string we can json.loads()
    state = Column(Text, nullable=False, default='{}')

    def get_state(self):
        return json.loads(self.state)

    def set_state(self, data):
        self.state = json.dumps(data)

# Helper to create a SQLite DB in the current folder
engine = create_engine('sqlite:///agents.db')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
3

Phase 3: Core API & simple UI

In this step we expose a tiny REST API that lets you create and list agents. The /agents endpoint accepts a JSON payload with a name and optional state, stores it in a local SQLite file, and returns the new record's ID. We also add a very simple HTML page at the root URL that pulls the list of agents from the database and renders them as plain text, so you can see the data without any front‑end framework.

app.py

import json, sqlite3
from flask import Flask, request, g, jsonify, render_template_string
app = Flask(__name__)
DB = 'agents.db'

def get_db():
    db = getattr(g, '_database', None)
    if db is None:
        db = g._database = sqlite3.connect(DB)
        db.execute('CREATE TABLE IF NOT EXISTS agents (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, state TEXT)')
    return db

@app.teardown_appcontext
def close_connection(exc):
    db = getattr(g, '_database', None)
    if db is not None:
        db.close()

@app.route('/agents', methods=['GET', 'POST'])
def agents():
    db = get_db()
    if request.method == 'POST':
        data = request.get_json() or {}
        name = data.get('name', 'unnamed')
        state = json.dumps(data.get('state', {}))
        cur = db.execute('INSERT INTO agents (name, state) VALUES (?,?)', (name, state))
        db.commit()
        return jsonify({'id': cur.lastrowid, 'name': name, 'state': json.loads(state)})
    rows = db.execute('SELECT id, name, state FROM agents').fetchall()
    agents = [{'id': r[0], 'name': r[1], 'state': json.loads(r[2])} for r in rows]
    return jsonify(agents)

@app.route('/')
def index():
    db = get_db()
    rows = db.execute('SELECT id, name, state FROM agents').fetchall()
    items = []
    for r in rows:
        state = json.loads(r[2])
        items.append(f"<li>{r[0]}: {r[1]} – {json.dumps(state)}</li>")
    html = "<h1>Agents</h1><ul>" + "".join(items) + "</ul>"
    return render_template_string(html)

if __name__ == '__main__':
    app.run(debug=True)
4

Phase 4: Run locally

Now we start the Flask development server. The first request will automatically create the SQLite database file (agents.db) if it doesn't exist, so you don't need any manual setup. Running in debug mode gives you live reloads while you experiment.

export FLASK_APP=app.py
export FLASK_ENV=development
flask run
5

Phase 5: Verify & extend

With the server running, use curl to POST a new agent and watch the JSON response contain an id. Then open a browser at http://127.0.0.1:5000/ to see the simple HTML list showing the agent you just created. Feel free to add more fields to the agents table or replace the HTML with a richer UI as you grow the clone.

curl -X POST http://127.0.0.1:5000/agents \
  -H "Content-Type: application/json" \
  -d '{"name":"demo","state":{"msg":"hello"}}'

Verifying the Stack

CheckCommand / Why it matters
Virtual environment activated and Flask installedpip list | grep Flask
Server starts without errorsflask run (should show * Running on http://127.0.0.1:5000/)
POST request returns JSON with an idcurl -X POST http://127.0.0.1:5000/agents -H "Content-Type: application/json" -d '{"name":"demo","state":{"msg":"hello"}}' (response contains \"id\":1)
Browser at http://127.0.0.1:5000/ shows the new agentOpen URL and see "1: demo – {\"msg\":\"hello\"}"

You did it!

Your minimal harness is up and running. The real Strands SDK adds model‑driven pipelines, remote execution, and rich UI – you now have the skeleton to explore those features on your own.