Why Your AI Agent Forgets Everything Overnight — From Prompt to Loop Engineering A developer outlines the evolution from prompt engineering to loop engineering, presenting a 50-line Python agent that persists memory across sessions using OpenAI's API. The agent stores state and memory in JSON files, enabling it to resume tasks after interruptions, addressing the common issue of AI agents forgetting overnight. The Pain: You spent an afternoon tuning your agent. Next morning, it stares at you blankly — as if yesterday never happened. What You'll Learn: The 4-stage evolution Prompt → Context → Harness → Loop , and a runnable 50-line Loop Agent that persists memory. pip install openai openai ≥ 1.0.0 Goal : Copy-paste the code, run it, and see a Loop Agent that doesn't forget. At 2 AM, you finally got that multi-step workflow working. The agent followed your carefully designed prompt — data fetching, cleaning, analysis, charting. You close your laptop, satisfied. Next morning, you open the conversation full of hope — and the agent looks at you blankly, as if none of it ever happened. You check the logs. No errors. No exceptions. The agent regenerated everything — it just "forgot" where it stopped yesterday. This isn't a joke. It's the nightmare every serious Agent developer experiences. The root cause isn't "the model isn't smart enough." It's a more fundamental fact: your agent was never designed to survive the night. To understand this, let's use a simple evolution framework: | Stage | What You Do | Fatal Flaw | |---|---|---| Prompt Engineering | Write task description, examples, format into prompt | Any unexpected input crashes output | Context Engineering | Stuff history + intermediate results into context window | Token cost grows linearly, hits window limit | Harness Engineering | Add tool calling, structured output, error capture | Framework built, but agent is still "one-shot" | Loop Engineering | Build closed loop: state + memory + feedback + retry + persistence | True engineering — agent starts to "live" | Loop Engineering isn't a rejection of Prompt Engineering — it's a transcendence. Prompt still matters. But it's the engine, and you can't drive an engine like a car. Here's the complete, copy-pasteable, runnable Loop Agent. Run it first, then understand it line by line. python import json, os, time from pathlib import Path from datetime import datetime from openai import OpenAI client = OpenAI reads OPENAI API KEY from env STATE FILE = Path "./agent state.json" MEMORY FILE = Path "./agent memory.json" MAX RETRIES = 3 def load memory - dict: if MEMORY FILE.exists : return json.loads MEMORY FILE.read text return {"facts": {}, "errors": } def save memory mem: dict : MEMORY FILE.write text json.dumps mem, indent=2, ensure ascii=False def load state - dict: if STATE FILE.exists : return json.loads STATE FILE.read text return {"state": "idle", "step": 0} def save state state: str, step: int : STATE FILE.write text json.dumps { "state": state, "step": step, "updated at": datetime.now .isoformat }, indent=2, ensure ascii=False def execute task: str, memory: dict, error ctx: str = "" - str: system = f"You are a task-execution agent. Known facts: {json.dumps memory.get 'facts', {} , ensure ascii=False }" if error ctx: system += f"\nLast error: {error ctx}\nPlease fix." resp = client.chat.completions.create model="gpt-4o-mini", messages= {"role": "system", "content": system}, {"role": "user", "content": task} return resp.choices 0 .message.content def check output: str, keywords: list str - tuple bool, str : missing = kw for kw in keywords if kw not in output if missing: return False, f"Missing: {missing}" if len output < 20: return False, "Output too short" return True, "" def run task: str, keywords: list str : memory = load memory save state "running", 0 for i in range 1, MAX RETRIES + 1 : error = memory "errors" -1 "reason" if memory "errors" else "" output = execute task, memory, error ok, reason = check output, keywords if ok: save state "done", i memory "facts" task :30 = output :100 save memory memory return f"OK on attempt {i}:\n{output}" else: save state "retrying", i memory "errors" .append {"task": task, "reason": reason, "attempt": i} save memory memory print f"Retry {i} failed: {reason}" time.sleep 1 save state "failed", MAX RETRIES return f"All {MAX RETRIES} attempts failed" if name == " main ": result = run task="List 3 Python web frameworks and their features", keywords= "Flask", "Django", "FastAPI" print result Copy this to loop agent.py and run it. 1. Install pip install openai 2. Set API key export OPENAI API KEY="sk-..." 3. First run python loop agent.py Expected output: OK on attempt 1: The 3 mainstream Python web frameworks: 1. Flask : lightweight micro-framework... 2. Django : full-stack, batteries included... 3. FastAPI : modern async, auto OpenAPI docs... Now verify persistence — close the terminal, reopen, run again: 4. Check state file cat agent state.json Expected: { "state": "done", "step": 1, "updated at": "2026-07-01T12:00:00.000000" } 5. Check memory file cat agent memory.json Expected: the facts dict contains your task and the output. 6. Run again — agent loads memory automatically python loop agent.py The agent reads facts from agent memory.json and passes them as known context. That's the "remembers overnight" mechanism. | Component | Code Location | Description | |---|---|---| | Memory Store | load memory / save memory | Persist memory to JSON | | State Machine | load state / save state | Persist state to JSON | | Executor | execute | Call OpenAI API | | Checker | check | Verify keywords present | | Task Scheduler | run | Retry loop + state transitions | | Guardrails | MAX RETRIES = 3 | Retry limit | Error 1: ModuleNotFoundError: No module named 'openai' pip install openai Error 2: openai.AuthenticationError: 401 You didn't set the API key, or it's invalid. export OPENAI API KEY="sk-..." Error 3: Agent output missing Flask/Django/FastAPI This is normal LLMs don't always follow instructions perfectly. That's exactly the Loop Agent's value — the Checker detects missing keywords, rejects the output, and auto-retries. You'll see: Retry 1 failed: Missing: 'Flask', 'Django', 'FastAPI' Retry 2 failed: Missing: 'Django' OK on attempt 3: ... Error 4: API timeout or rate limit gpt-4o-mini is very cheap ~$0.00015/call . If rate-limited, increase time.sleep 1 or check your OpenAI dashboard. Now you have a complete runnable Loop Agent. It uses plain JSON files for persistence — which is exactly what lets you touch every component by hand. Extend it: Loop Engineering isn't a package you install. It's a shift in architecture thinking. Starting from these 50 lines, you're standing at the threshold of stage 4. Next article : How Much Memory Does Your Agent Need? — Memory Store Selection Guide About the author: Wu Ji 无记 — AI & digitalization practitioner focused on Agent engineering, Loop Engineering, and digital transformation. Practical, hands-on tutorials — follow along and it just works.