Introduction
In earlier experiments, we explored a simple but powerful idea:
An agent can generate code, run it, observe failures, and iteratively fix itself.
That approach worked well for single-file applications across Python, Go, and TypeScript.
But real systems are not single files.
They are:
- structured\
- layered\
- multi-module\
- opinionated
This raises a deeper question:
Can agents generate complete repositories β β not just code?
In this article, we push agentic coding one step further:
π generating a Clean Architecture notes application
π as a multi-file Python project
π verified with unit tests (pytest)
The Shift: From Code to Systems
system = structure + boundaries + contracts + code
Target Architecture
project_agent_coded_python_clean_arch/
domain/
models.py0
application/
services.py
infrastructure/
db.py
api/
main.py
tests/
test_notes.py
The Agent Evolution
generate β run β validate β test β fix
Running the Agent
python agent_coder_python_clean_arch.py
The agent will:
- generate the full project structure\
- install dependencies\
- start the API\
- execute tests\
- fix issues iteratively
Generated Project
project_agent_coded_python_clean_arch/
Run Generated API
cd project_agent_coded_python_clean_arch
python api/main.py
Run Tests
cd project_agent_coded_python_clean_arch
pytest
Generated Unit Tests
from fastapi.testclient import TestClient
from api.main import app
client = TestClient(app)
def test_create_note():
response = client.post("/notes", json={"content": "test"})
assert response.status_code in (200, 201)
data = response.json()
assert "id" in data
assert data["content"] == "test"
def test_get_notes():
response = client.get("/notes")
assert response.status_code == 200
assert isinstance(response.json(), list)
Why This Matters
From: code generation
To: verified system construction
Appendix A β β FULL AGENT CODE
import os
import subprocess
import time
import json
import sys
from openai import OpenAI
# ============================================================
# CONFIGURATION
# ============================================================
client = OpenAI()
WORKDIR = "project_agent_coded_python_clean_arch"
os.makedirs(WORKDIR, exist_ok=True)
GOAL = """
Build a Clean Architecture notes REST API in Python.
Structure:
- domain/models.py
- application/services.py
- infrastructure/db.py
- api/main.py
- tests/test_notes.py
Requirements:
- Use FastAPI
- Use SQLite
- POST /notes
- GET /notes
- Include pytest tests
- Must run with: python api/main.py
"""
# ============================================================
# CODE GENERATION
# ============================================================
def generate_repo(goal, error=None):
"""
Generate a full multi-file repository using the LLM.
The model must return a JSON object mapping file paths β file contents.
Args:
goal (str): High-level system description
error (str | None): Feedback from previous attempt
Returns:
str: Raw JSON string (must be parsed)
"""
prompt = f"""
You are an autonomous coding agent.
Goal:
{goal}
Return ONLY valid JSON mapping file paths to contents.
Rules:
- No markdown
- All files must be included
- Tests must use pytest
- Code must run without modification
Previous error:
{error}
"""
response = client.responses.create(
model="gpt-4.1-mini",
input=prompt
)
return response.output_text
# ============================================================
# FILE SYSTEM OPERATIONS
# ============================================================
def write_files(file_map):
"""
Write generated files to disk.
Creates directories as needed.
Args:
file_map (dict): { path: content }
"""
for path, content in file_map.items():
full_path = os.path.join(WORKDIR, path)
os.makedirs(os.path.dirname(full_path), exist_ok=True)
with open(full_path, "w") as f:
f.write(content)
# ============================================================
# RUNTIME EXECUTION
# ============================================================
def run_app():
"""
Start the generated API.
Returns:
(success, process, error)
Success means the server started and did not crash immediately.
"""
process = subprocess.Popen(
[sys.executable, "api/main.py"],
cwd=WORKDIR,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
# Give the server time to start
time.sleep(3)
# If still running β success
if process.poll() is None:
return True, process, ""
# Otherwise, capture failure
stdout, stderr = process.communicate()
return False, None, stderr
def stop_app(process):
"""
Stop the running API process.
"""
if process:
process.terminate()
# ============================================================
# VALIDATION (PRIMARY = PYTEST)
# ============================================================
def run_tests():
"""
Execute pytest inside the generated project.
This is the PRIMARY validation mechanism.
Returns:
(bool, str):
- success flag
- error output (if any)
"""
result = subprocess.run(
[sys.executable, "-m", "pytest"],
cwd=WORKDIR,
capture_output=True,
text=True
)
if result.returncode == 0:
return True, ""
return False, result.stdout + result.stderr
# ============================================================
# DEPENDENCY HEALING
# ============================================================
def install_missing(error):
"""
Attempt to auto-install missing dependencies.
The agent inspects error messages and installs packages dynamically.
Returns:
bool: whether a fix attempt was made
"""
if not error:
return False
if "No module named" in error:
pkg = error.split("'")[1]
subprocess.run([sys.executable, "-m", "pip", "install", pkg])
return True
if "pytest" in error:
subprocess.run([sys.executable, "-m", "pip", "install", "pytest"])
return True
return False
# ============================================================
# ENVIRONMENT PREPARATION
# ============================================================
def clean_port():
"""
Kill any process using port 8000.
Prevents conflicts between agent iterations.
"""
subprocess.run(
"lsof -ti :8000 | xargs kill -9",
shell=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
# ============================================================
# AGENT EXECUTION LOOP
# ============================================================
"""
============================================================
AUTONOMOUS AGENT LOOP
This loop implements a full self-healing coding cycle:
1. Generate repository from goal
2. Write files to disk
3. Run the generated API
4. Validate using pytest
5. Feed errors back into the model
6. Repeat until success
IMPORTANT DESIGN DECISIONS:
- pytest is the PRIMARY validation mechanism
- HTTP validation (Appendix B) is optional and NOT used here
- The agent stops ONLY when tests pass
============================================================
"""
clean_port()
error = None
for attempt in range(5):
print(f"\n--- Attempt {attempt+1} ---")
# --------------------------------------------------------
# STEP 1: GENERATE CODE
# --------------------------------------------------------
raw = generate_repo(GOAL, error)
try:
file_map = json.loads(raw)
except Exception:
error = "Invalid JSON output"
continue
# --------------------------------------------------------
# STEP 2: WRITE FILES
# --------------------------------------------------------
write_files(file_map)
# --------------------------------------------------------
# STEP 3: RUN APPLICATION
# --------------------------------------------------------
success, process, err = run_app()
if not success:
# Try to fix missing dependencies
if install_missing(err):
error = err
continue
error = err
continue
# --------------------------------------------------------
# STEP 4: VALIDATE USING PYTEST
# --------------------------------------------------------
test_ok, test_error = run_tests()
# Stop API before continuing
stop_app(process)
if test_ok:
print("\nSUCCESS: All tests passed. System is valid.")
break
# --------------------------------------------------------
# STEP 5: SELF-HEALING LOOP
# --------------------------------------------------------
if install_missing(test_error):
error = test_error
continue
# Feed test failures back into next generation
error = test_error
Appendix B β β Optional API Validation
import requests
def validate_api():
try:
r = requests.get("http://localhost:8000/notes")
if r.status_code != 200:
return False, r.text
return True, ""
except Exception as e:
return False, str(e)
Conclusion
This is no longer code generation.
This is autonomous system construction with verification.
Full Modular Agent Code Example
https://github.com/mmmattos/agentic-coding-python-clean-arch

Top comments (0)