← All Articles
ArchitectureOperations•8 min read•Oct 22, 2026

OpenClaw Learning Loop Architecture: How Repeated Failures Become Skills That Actually Load

Capturing a lesson is the easy half. Most self-improving agent setups stop there, and the lesson sits in a file nobody reads.

On September 3 my nightly skill job did everything right. It found two recurring failure categories that had no skill covering them, wrote a proposal for each (deployment-gate-discipline and message-delivery-discipline, stamped with the date and a short hash), and handed them off for approval. Then they sat there. The approval step expected a reply over Telegram, and no Telegram approval route had been configured, so the proposals waited for someone to type /approve in a web UI or a terminal that nobody had a reason to open.

The loop worked. The handoff went nowhere.

What the Usual Guides Cover

Read the popular write-ups on making an OpenClaw agent self-improving and you get the same good skeleton. The agent logs corrections and errors to a lessons file (some versions split it into LEARNINGS.md and ERRORS.md). A scheduled review consolidates entries. Lessons that hold up get promoted into AGENTS.md or MEMORY.md, usually after a human signs off. One of them adds stable pattern keys so that two differently worded entries about the same failure count as a recurrence.

All of that is worth doing. None of it answers the question that bit me, which is what happens between "a human approved this" and "the agent that needs it behaves differently tomorrow." That gap is where this page spends its time.

Three Jobs With One Writer Each

My fleet runs the loop as separate scheduled jobs, in a fixed order every morning, and each one writes a single line to a shared work log when it finishes. The failure-replay job goes first. It looks back over recent failures, groups the ones that share a pattern, and decides which patterns deserve a signal. The skill harvester runs next, reads those signals, and either proposes a new skill or marks the signal resolved by an existing one. The daily digest runs last and tells the operator what, if anything, needs them.

2026-10-20 · skill-harvester · 0 skill proposals, 0 signal resolutions
2026-10-22 · failure-replay · 4 failure patterns found, 2 signal actions
2026-10-22 · skill-harvester · 2 skill proposals, 1 signal resolutions

Zero proposals on October 20 was a good day. A harvester that feels obliged to produce something every morning will produce duplicates, and a fleet with four skills that say the same thing in slightly different words is harder to steer than a fleet with one. The separation matters for a less obvious reason too. Each job owns its own output and nothing else, which is the one writer per fact rule applied to learning. The replay job never edits skills. The harvester never decides what counts as a failure.

Dedupe by Slug Before You Write Anything

Before the harvester proposes a skill, it checks the skills directory for a slug that already covers the category. On September 4 five signals fired that all had skills on disk already (deployment-enforcement, message-discipline, mock-data-prevention, privacy-firewall, context-bloat-prevention), because a report generator had dropped the fields marking them resolved. The harvester read each skill file, confirmed it had real content, and authored nothing. That restraint is the whole point of the check.

# harvest.py: propose only when no existing skill owns the category
def propose(signal, skills_dir):
    owner = find_skill_for(signal["category"], skills_dir)
    if owner and has_body(owner):
        return {"action": "resolve", "by": owner}        # point at it, write nothing
    slug = f"{signal['category']}-{today()}-{short_hash(signal)}"
    if slug_exists(slug):
        return {"action": "skip", "reason": "duplicate slug"}
    return {"action": "propose", "slug": slug, "status": "pending_approval"}

has_body is there because an empty skill file with the right name is worse than no file. It satisfies the dedupe check and teaches nothing.

The Approval Route Has to Exist Before the Proposal Does

Every guide says a human should approve new rules. I agree, and the human-in-the-loop tiers on this site treat a new skill as a change to how agents behave, which puts it above anything an agent may approve for itself. What the guides skip is checking that the approval channel works. My two September proposals were blocked by a missing route, and the only record of it was a line in a log that said so in plain words.

The fix I would build is small. The harvester checks the route at startup, and if it cannot reach the approver on the channel the approver actually reads, it still writes the proposal and adds one line to the morning digest saying how many proposals are pending and where to approve them. Anything pending for more than a week moves to the top of that digest. Proposals are cheap to write and expensive to forget, because the failure they describe keeps happening while they wait.

Pick the channel the operator already lives in. For mine that is a phone.

Approved Is Not Loaded

A skill file on disk changes nothing until a session reads it. In OpenClaw that happens through two paths, and both can fail quietly. The first is routing: a skill is surfaced when its trigger description matches what the session is doing, which the skill routing piece covers in detail. The second is boot context, the short block of text every session loads before it does anything, and that block is capped. My sessions print the last five entries from an errors file at startup. Five, on purpose, because every line in boot context is paid for in every session (the context window guide has the arithmetic).

The bug that taught me this was not in the learning loop at all. The fleet had a working router that sent hard problems to a stronger model, built on June 13 and confirmed working in August. The briefing file that served as one agent's actual operating instructions, 555 lines long, never mentioned it once. The agent had never known to call it. Weeks of "why does this one seem less capable on hard problems" came down to a capability nobody had wired into the place the agent reads.

The acceptance test I want for every new skill is boring: start a fresh session, give it a prompt that should trigger the skill, and check that the skill's name shows up in what the session loaded. If it does not show up, the skill is not done.

A Good Rule Carries Its Own Check

Generic lessons decay fast. "Be careful with print layouts" would have done nothing for the book interior that failed Amazon KDP review on August 30, when full-bleed chapter images ran past the physical page box and the upload came back with both image and margin errors. The rule that went into the errors file is narrow and testable: for this title, uniform 6x9 with no bleed, threshold art inset at least 0.5 inches from every trim edge, and an actual pass in KDP Previewer before anyone calls the geometry accepted.

That last clause is the part I would copy. A rule that names the check which proves it was followed can be enforced by the next agent without any memory of why it exists, and a rule that only names a feeling depends on the agent feeling the same way.

Write the date on every rule.

Where to Start

If you have nothing yet, start with the errors file and the boot hook that prints its tail, because that alone stops the same correction from being needed three times. Add the replay job once you have more than a week of logs to replay. The harvester comes last, and it should ship with its dedupe check and its approval route on the first day. Shipping it without them builds a machine that writes skills into a drawer.

The loop is only finished when a lesson from Tuesday changes what an agent does on Wednesday, and you can point at the line in the session's boot output that made it happen.

Internal Links & Further Reading

FAQ

Q: Should the harvester be allowed to approve its own skills?

No. A skill changes behavior across every session that loads it, so it belongs in the same tier as a config change to a production service. Let the harvester write proposals freely and make the approval cheap, one tap on the channel the operator already reads.

Q: How many entries should the boot hook print?

Few. Five works for my fleet. Rules that keep mattering should graduate into a skill with a proper trigger, which frees their slot in boot context for the next fresh lesson.

The Bottom Line

Keep the learning jobs separate, each owning one output. Check for an existing skill before proposing a new one. The approval route deserves the most suspicion, because a proposal that can't reach its approver fails without making a sound, so test it before the first proposal depends on it. Write rules that name the check proving they were followed.

Then open a fresh session and look for the skill in what it loaded. That is the test.

Get the free OpenClaw deployment checklist

Production-ready setup steps. Nothing you don't need.