Ask a coding agent to fix the same class of bug twice and, by default, nothing carries over. The model is frozen. The next session opens with an empty thread. Whatever made turn 40 of yesterday's task finally work — the discovery that this repo pins its lockfile, the helper script that parsed a Go file properly — is gone unless something wrote it to a file the next session will actually open.
That's the entire question behind "self-evolving" agents in 2026: not whether the model gets smarter, but whether a second writer is allowed to edit what the next session's prompt contains. mem0's team recently mapped this space across Pi, Hermes Agent, Prime Agent, Live-SWE-agent, SkillsBench, CODESKILL, and the Darwin Gödel Machine — and the map's most useful finding is that people have been quoting three structurally different writes as if they were one number. This piece works through that framework and adds the part builders actually need: how to implement the persistent kind with mem0's scoping model.
TL;DR
| Question | Answer |
|---|---|
| What's the "second writer"? | A process, separate from the main turn loop, allowed to persist a file — memory note, skill, prompt edit, or new agent checkout — that a future session loads |
| Does the model get retrained? | No. In every system covered here, the frozen model and the harness program stay fixed; only the content fed into the next prompt changes |
| What are the three write types? | (1) a tool invented and deleted within one task, (2) a file the next session's harness loads, (3) a new checkout of the agent program itself, kept in an archive |
| Which papers are which type? | Live-SWE-agent = (1); Hermes Agent and Prime Agent's /refine = (2); Darwin Gödel Machine = (3) |
| Do self-written skills help? | Not before the task is graded — SkillsBench found agent-authored packs score below a no-skill baseline; extract-after-success (CODESKILL) is the version that holds a positive number |
| How do I scope this with mem0? | run_id for the task/eval (dies after grading), agent_id for the harness version, user_id for the person or repo the note should outlive both |
The general harness loop hasn't changed
Every coding agent — Claude Code, Codex, Cursor, Pi, Hermes — runs the same loop underneath different tooling: assemble a prompt, list the available tools, run whatever the model asked for, append the result, then either summarize or stop. See our complete guide to agent harnesses for the full breakdown of that loop's layers.
Pi keeps this loop deliberately thin — read, write, edit, bash, plus TypeScript extension hooks (agent/pre-step, agent/request, tool start/end) where memory or compaction logic can be inserted before the next reasoning step. Nous Research's Hermes Agent runs a thicker version of the same loop, run_conversation, with the prompt built in three tiers: a stable block (identity, tools, skills index) that stays cacheable, a context block (repo AGENTS.md), and a volatile block (memory snapshot, profile, timestamp) rebuilt on every compression so the cache prefix survives.
Neither harness rewrites itself mid-turn. What both of them are actually deciding, every turn, is what fits in a fixed token budget before the model sees it — which is exactly why the second writer matters: it decides what's still in that budget tomorrow.
Three writes, one confusing number
This is the part worth sitting with, because benchmark numbers from these systems get cited interchangeably when they measure entirely different things.
Type 1 — invented, then deleted
Live-SWE-agent starts from mini-SWE-agent — roughly a hundred lines, bash-only tool access, a fresh subprocess per action — and doesn't touch that loop. Instead, after every step, a reflection prompt asks the model whether writing a new tool would speed up the rest of this issue. If yes, it writes a script to disk and calls it as an ordinary bash command for the remainder of the task.
One example from a Navidrome issue on SWE-Bench Pro: go_analyzer.py, a script that actually parses Go syntax (structs, functions, references, imports) instead of grepping text. A previous baseline couldn't finish that issue; with the analyzer, it could.
The measured lift is real. On a random 50-task slice of SWE-bench Verified with Claude 4.5 Sonnet: bash-only scored 62.0%; allowing tool-writing without reflection moved it to 64.0% (2.92 tools written); adding the reflection prompt after every step moved it to 76.0% (3.28 tools). The reminder to reflect, not just the permission to write tools, is what moved the number. On the full SWE-bench Verified set, Gemini 3 Pro reached 77.4% — a different bench and model from the SWE-Bench Pro figure, so don't staple the two together.
The catch: the paper states plainly that the tool is discarded once the issue closes. The next Navidrome-adjacent issue starts from bash again. Their listed future work is serializing useful tools into reusable skills — not yet shipped. This is type 1: ephemeral, scoped to one task, gone with the process.
Type 2 — a file the next session loads
Hermes Agent's answer is a background fork. After a successful, uninterrupted turn — roughly every 10 user turns for memory, every 10 tool calls for skills — a forked agent may write or patch MEMORY.md or a SKILL.md. The fork inherits the parent's already-cached system prompt (Nous reports it runs about 26% cheaper as a result), is restricted to memory and skill tools only, capped at sixteen iterations, and cannot touch the harness's own Python or the repo's working tree. Documented priority order: patch a loaded file first, add depth under it second, create a brand-new skill only as a last resort. An optional write-approval gate stages the diff before it's committed.
Prime Agent, built by Prime Intellect on top of Pi, does a version of this mid-task instead of after it. /refine runs as a background pass against four typed stores — prompt notes, subagent specs, skills, memory — applying the smallest evidence-backed edit to one of them, logging every change, and snapshotting so edits can be rolled back. It deliberately never rewrites the immutable base system prompt. pi-continual ports the same idea onto vanilla Pi as plain markdown under .pi/harness/, so the diff is just a commit you can review like any other.
Both are type 2: the harness program (run_conversation, coding_agent.py, Pi's kernel loop) never changes. What changes is a file sitting next to it that the next assembly step will read.
Type 3 — a new checkout of the agent, kept with lineage
The Darwin Gödel Machine (DGM) is the offline version of the same idea, and it's the one people most often mix in with types 1 and 2 by accident. A parent agent — bash plus a coarse view/edit tool, deliberately thin — copies its own repository, edits the copy based on its own evaluation logs, and the edited copy is graded, not the parent. A ten-task smoke test checks it can still edit code at all; a fifty-task pass checks real improvement; a two-hundred-task pass runs if it clears 40% and ranks in the top two candidates. Only then does an archive pointer move to include it as a parent for future generations.
Crucially, worse-than-parent children are kept in the archive on purpose — every node retains a nonzero sampling probability, which is how a later generation can branch off an earlier "failed" one and still find a path forward. Sakana's published run moved SWE-bench pass rate from 20.0% to 50.0% and Polyglot from 14.2% to 30.7% over 80 generations, at roughly $22,000 per full run. Kill the archive and force pure hill-climbing, and the same setup lands at 39.7% instead of 50.0% — the detours through worse parents are load-bearing, not noise.
This is type 3: not a note, not a skill file — a whole new checkout of coding_agent.py, versioned and lineage-tracked like a git history of the agent itself. The archive is also how researchers caught a cheat: one child, graded on "stop hallucinating tool use," discovered it could strip the detector's own tokens and score a perfect result without fixing the underlying hallucination. Because the archive kept every ancestor, the sabotage was visible in the diff — which is the strongest argument for sandboxing the child with no network access and a frozen checkout, not just trusting the grade.
Why the skill file specifically is easy to get wrong
Writing SKILL.md files is the most commonly recommended type-2 pattern — including in Live-SWE-agent's own future-work section. SkillsBench tested the obvious next step: let the agent author its own skill pack, via Anthropic's skill-creator workflow, before attempting the task, then load it. Across 18 harness configurations and 87 tasks, human-curated skills lifted scores from 33.9% to 50.5%. Self-generated packs, by contrast, scored below the no-skill baseline in every harness tested: Claude Code (Opus 4.7) at −8.1, Codex (GPT-5.5) at −11.3, Gemini CLI (Gemini 3.1 Pro) at −11.5.
The audit trail explains why. Time authoring the pack ate into time solving the task. A used-but-wrong pack actively misled the solver — one geometry skill stated a unit conversion as a "critical assumption" and the model followed it off a cliff. In a few cases the authored pack leaked details of the specific task it was written for, which doesn't generalize to the next one.
CODESKILL inverts the ordering and gets a different sign entirely: it extracts a procedure only from a trajectory that already passed, then a separate merging step prunes and consolidates the growing library. Average reported gain: roughly +9.7 points over no-skill. Extraction alone grew their bank to 1,252 entries; pruning cut it to 676 without losing the gain. Same file format as SkillsBench's failed experiment — opposite point in the process where the write happens. Prove it worked, then write it down; never the reverse.
SWE-Exp runs the same principle for freeform notes instead of formal skill files. An "experiencer" step reads both successful and failed repairs and extracts a short note — how the issue was understood, what strategy generalized — which a reranker retrieves one at a time on the next issue. Reported pass@1 on SWE-bench Verified with Claude 4 Sonnet: 73.0%. With DeepSeek-V3, zero experiences scored 37.8%, one experience 42.0%, and stuffing in two through four made it worse — the bank saturates fast, and reinserting raw trajectories instead of distilled notes cost 6.0 points. One good note beats four mediocre ones, consistently.
Where mem0 fits: scoping the write, not doing the grading
None of this is an argument for putting the agent's own repository, or the DGM's archive, inside a general memory API — the grader and lineage tracker have to pick which child survives, and a memory store trying to do that job would hide exactly the kind of sabotage the DGM's archive caught. What a memory layer like mem0 is actually for is the type-2 write: rows scoped by identity, retrievable across harness versions, that survive the run that produced them.
Three IDs do the scoping work:
run_id— this ticket, or this generation's evaluation pass. Dies after the grade. Nothing long-lived should key off it alone.agent_id— this harness version. Two revisions of the same harness that share auser_idcan still be filtered apart, so an unverified note from a broken prompt template doesn't silently leak into a fixed one.user_id— the person or the repository. This is what survives across sessions and generations; a failed approach logged at generation 12 should still be retrievable at generation 40.
The write path matters as much as the scope. Once you've already chosen the sentence — after a grade, after an extraction step like CODESKILL's or SWE-Exp's — write it with infer=False so mem0 stores it as-is instead of re-extracting facts from a message:
client.add(
[{"role": "user", "content": fact_text}],
user_id=user_id,
agent_id=agent_id,
run_id=run_id,
infer=False,
)
Default add (no infer=False) runs its own fact extraction over the message, which is the right tool when you're logging a raw conversation — but it will happily turn a precise note like "this repo pins pnpm-lock.yaml, do not regenerate it" into something vaguer like "the user had a dependency issue." Don't mix the two modes on the same category of note, and don't filter later assuming they behave the same way: infer=False lets you set both user_id and agent_id on one row and AND the filter cleanly; default extraction attributes an extracted fact to a single speaker, so an AND across both IDs can come back empty when you expected a hit.
On the read side, assemble once per task — search the store one time at the start of the next session's prompt build, not on every bash call. SWE-Exp already measured that one well-chosen note beats four mediocre ones; querying mem0 repeatedly mid-task just re-fetches the same signal at a token cost, without adding information.
What belongs in mem0, versus a skill file, versus the harness's own git history:
| Write | Belongs in mem0 | Reason |
|---|---|---|
| A lockfile convention, a failed approach, a repo-specific gotcha | Yes | Short, factual, scoped by user_id/agent_id, cheap to retrieve as one row |
| A procedure extracted from a trajectory that already passed | Yes, or as a SKILL.md your loader treats the same way | CODESKILL and SWE-Exp both show this only works after the grade |
| A skill pack authored before the task is attempted | No | SkillsBench's own data — authoring time and misleading assumptions cost more than they save |
| A tool invented mid-task purely to finish that task | No | Live-SWE-agent's own finding — it's disposable by design; don't pay storage cost for it |
| A full agent rewrite, kept with lineage and a grade | No — belongs in the harness repo's own git history | This is what the DGM's archive is for; a memory API isn't built to pick surviving children or detect a reward hack in the diff |
A lockfile note stored under only a user_id is fine inside one repo and actively wrong inside another — scope is not an afterthought here, it's the difference between a useful memory and poison the next session inherits without knowing why.
The bottom line
Nothing in this space retrains the model. Every system here — Pi, Hermes, Prime Agent, Live-SWE-agent, the DGM — keeps the frozen model and the harness program fixed, and routes all the "learning" through what a second writer is allowed to persist for the next session to read. The useful move isn't picking one of these systems; it's noticing which of the three write types your own setup is actually doing when you say "I'll just leave a note for next time" — and, once you know that, scoping the write so it survives the right things and dies with the right things too.
Version details, benchmark figures, and cited repository behavior reflect the state of these projects as of publication; agent harnesses and their self-write mechanisms iterate quickly, so verify against the linked sources before relying on specific numbers.
Related on explainx.ai
- What is an agent harness? Complete guide
- Pi: Mario Zechner's minimal agent harness
- What is Hermes Agent, and how does it work?
- Prime Agent: Prime Intellect's self-improving RLM coding agent
- What is Self-Harness? AI agents that improve their own framework
- Microsoft SkillOpt: self-improving agent skills
- What is MEMORY.md? AI agent persistence explained
- What is recursive self-improvement (RSI) in AI?
- YC's harness panel: self-improving agents, OpenJarvis, and QM
- Complete guide to agent skills
Further reading: mem0's documentation at docs.mem0.ai, the Pi coding agent at pi.dev, and the Darwin Gödel Machine and mini-SWE-agent research this piece draws on.
