Pattern · Procedure

Skills as Procedural Memory

Remember what worked as a reusable procedure rather than as a fact, and gate the write on evidence that it actually worked.

Intent

Store an agent's competence, not just its knowledge. When the agent works out how to do something, keep the procedure itself — a script, a function, a checklist — so the next attempt starts from a working solution rather than from a description of one.

The page makes two kinds of claim. Skill libraries — procedures the agent or a person writes down, advertised by name and description, with bodies loaded on demand — are reported practice, and common across this atlas. The outcome-verified write gate is argued, and rests on two systems: Voyager writes an executable skill only after the environment confirms it worked, and Acontext holds a partial version of the gate.

The problem

Most agent memory remembers propositions: the user prefers dark mode, the deploy failed at step three, the schema has a tenant_id column. Propositional memory answers "what is true?"

It answers "how do I do this?" badly. An agent that solved a fiddly multi-step task last week can retrieve a summary of having solved it and still have to rediscover every detail. Worse, a summary of a procedure is exactly the kind of memory that looks right and is subtly wrong — the steps are there, the ordering constraint that made it work is not.

Procedures also have a property propositions lack, and it is the whole opportunity: you can run them. "Is this fact true?" requires judgment. "Does this procedure work?" can be answered by executing it and checking the result.

The pattern

Store the executable artifact. Index it by a generated description of what it does. Gate the write on verified execution.

task -> agent produces a procedure (code, script, sequence)
     -> execute
     -> verify against observable outcome, not model self-report
     -> on success: generate a natural-language description
                    embed the DESCRIPTION, store the PROCEDURE
     -> on failure: feed the failure back as reasoning input; write nothing
retrieval: embed the task -> search descriptions -> return procedures
           -> earlier procedures become primitives for new ones
Diagram — nothing enters the skill library until an outcome verifies it; a failed attempt is critiqued and retried, and the store stays empty
Diagram source
%% caption: nothing enters the skill library until an outcome verifies it; a failed attempt is critiqued and retried, and the store stays empty
flowchart TD
    T["Task"] --> Gen["Agent writes procedure"]
    Lib["Skill library"] --> Gen
    Gen --> Exec["Execute"]
    Exec --> Ver{"Verified by outcome?"}
    Ver -- "no" --> Crit["Critique -> retry (nothing stored)"]
    Crit --> Gen
    Ver -- "yes" --> Desc["Generate description"]
    Desc --> Lib

Three invariants make it work:

  1. The retrieval key is not the payload. Embed a description of intent; return the artifact. Source code embeds poorly.
  2. Verification precedes storage. The gate is an observed outcome, not the model's confidence.
  3. Failures inform, they do not persist — at least not in the same store, and not as callable procedures.

Why it works

It converts memory from recall into capability. A propositional store gets larger as the agent works; a skill library gets more capable, because retrieved procedures become building blocks for new ones.

And it sidesteps the hardest problem in the rest of this atlas. Every pattern here about trust — rejected-value tombstones, trust-state machines, evidence before belief — exists because propositional truth is expensive to establish. Procedural truth is cheap to establish where actions have observable effects: run it and look.

Tradeoffs

  • Verification is only as good as the check. Succeeding once in one state is not evidence of generality, and a skill stored after a single lucky execution is a false memory with a confident-looking provenance.
  • Executing stored artifacts is a trust boundary. A skill library is durable, agent-authored, retrieved-by-similarity code. Outside a sandbox, in any setting where inputs are not trusted, this is an obvious attack surface.
  • Libraries need pruning, and pruning needs a utility signal. Without one — reuse count, success rate on reuse, composition depth — the library accumulates near-duplicate one-offs.
  • Retrieving the wrong procedure is worse than retrieving the wrong fact. An irrelevant fact is noise the model can ignore; an irrelevant callable invites the model to call it. Score thresholds matter more here than elsewhere.
  • Supersession needs lineage. Replacing a skill with a better version is a correction, and correction without a lineage record leaves you unable to answer why behaviour changed.
  • Not every domain has a checkable outcome. The pattern degrades toward ordinary memory wherever success is a matter of judgment.

Do not use this to store prose "procedures" that nothing executes. Without the verification gate, this is just tagged notes, and it inherits none of the property that makes it worth doing.

Cost to adopt

Build: a store for runnable procedures, a description index to retrieve them by, and an execution gate that only writes on verified success.

Forces elsewhere: you need a sandbox and a real success signal. Without one, this degrades into storing plausible-looking code that nothing has ever run — which is worse than not storing it, because it looks authoritative.

Ongoing: skills go stale as the environment changes, and nothing invalidates them automatically. Progressive disclosure keeps their context cost bounded but adds a loading mechanism.

Skip it if you have no execution environment to verify against.

Seen in the atlas

Voyager is the clearest implementation. Its SkillManager stores JavaScript functions written by the agent, indexed by an LLM-generated description; the write happens only inside if info["success"]:, where success comes from a critic that inspects environment state. Retrieved skills are injected as callable functions, so the library composes. It also shows the failure modes: unbounded concatenation of every skill into the JavaScript preamble sent to the environment on every step (the model prompt is capped at five retrieved skills), retrieval with no score threshold, versions written to disk with no lineage, no failure memory, and one hardcoded exclusion standing in for a memory-worthiness policy.

Hermes Agent applies the same idea without the gate. Skills are Markdown files the agent creates and edits through skill_manage, with provenance and usage tracked separately; only names and descriptions occupy prompt space and bodies load on demand — a better context strategy than Voyager's — but nothing verifies a skill before it becomes durable.

Atomic Agent takes the opposite position from Voyager and states it as a rule: its procedures are derived alongside a parent lesson from the same consolidator cluster, and cross-phase invariant 20 holds that the runtime never auto-executes them — they are "advisory text the agent reads and either follows or consciously deviates from." Voyager buys empirical verification by making skills executable and accepts the trust boundary that follows; Atomic Agent gives up verification to avoid it. Both are defensible, and the choice is the pattern's central tradeoff.

Acontext carries the gate over prose skills. Its tasks table constrains status IN ('success', 'failed', 'running', 'pending') as a database CHECK, the task-update path queues a learning task only on a terminal status, and test_running_does_not_append, test_pending_does_not_append and test_no_status_does_not_append assert the gate holds. Two things make it partial: a failed task triggers distillation as well as a success does, so the gate is on the task having ended rather than on its having worked, and the skill written is a Markdown SKILL.md, so nothing re-executes it to check that it still does.

ScienceClaw, an OpenClaw derivative outside the corpus and read without a pinned report, demonstrates the scale end: its README states that "the agent writes new SKILL.md files at runtime without any redeployment." Runtime skill authoring is what the pattern looks like when the library is the product, and it is where pruning stops being optional — the utility signals below are the answers this atlas has to that question.

MemOS mounts skill memory as one cube type among several, and agentmemory keeps procedural records alongside semantic ones; in both, procedure is one kind in a broader taxonomy rather than a design centre, and neither gates on execution.

OpenViking unifies memory, resources, and skills in one filesystem hierarchy — skills are retrievable through the same tiered mechanism as everything else.

Verel approaches the same territory from the opposite direction: it clusters failures into induced candidate rules and requires promotion gates before they become trusted. Read together with Voyager, the two halves of the missing system are visible — Voyager verifies successes and discards failures; Verel mines failures and gates promotion.

SESA answers the pruning question with a trained reward, and shows what it costs. Its skill bank writes a card only from a failure — the exact inversion of Voyager's gate — and then measures every card it hands out: retrieved_count, helpful_count and hurt_count, all three written by the same rollout reward that trains the model. A card whose net score has gone negative after at least three retrievals is deleted, not demoted. The reason it works is a precondition worth stating plainly: SESA is a training loop, so the outcome is a scored answer rather than a guess about whether the user was pleased. A library without that signal cannot borrow the mechanism, only the wish for it.

Two failures sit beside it and both generalise. The eviction leaves no record — _evict_negatives drops the row, and _add_new_with_dedup compares new cards only against the live bank, so a similar failure regenerates the card the system just measured as harmful, back at score zero and needing three more losses to leave again. And credit is assigned uniformly: all three retrieved cards receive the outcome of one rollout, so a harmful card is rewarded whenever it rides along with two good ones. The similarity score that would support weighted attribution is computed on every retrieval and attached to each card, and no caller reads it.

Agentic Context Engine keeps the same counters outside a training loop and refuses to let them delete anything. Every skill carries used_count, helpful_count, harmful_count and neutral_count, moved by tag_skill calls from a model that judges each injected skill against the run's outcome, and the prompt governing that model tells it to use them "as one input among several … never as a hard removal trigger", because a heavily-used skill accumulates harm counts while still being net-positive. SESA acts on the signal mechanically; this one treats it as evidence for a judgement.

autoharness answers the pruning question with an opportunity-relative load rate — loads divided by requests since the skill landed, a probation window, and a view that pardons at graduation but never feeds the rate — and evicts to an .archive/ folder rather than deleting. It then repeats SESA's regeneration failure by construction: the reflector's index globs one directory level deep, a committed test asserts the archived skill is absent from it, and the promoter's create consults neither the archive nor the run account of rejected intents, so a name the lifecycle retired can be proposed again at zero use. Its write gate is lint rather than outcome: six deterministic classes over the text, with nothing executed and nothing observed about whether following the skill worked.

Neo4j Agent Memory supplies the half this pattern's gate leaves out. Its reasoning tier records traces through a context manager, so on a raised exception the error becomes the trace's outcome — meaning failures are stored by default, where a verified-execution gate by construction stores only successes. An agent that has failed the same approach four times has learned nothing if nothing wrote the failures down. Outcomes carry an indexable error kind, and a retrieved step arrives with its parent trace's outcome attached, so a step from a failed attempt cannot be read as precedent.

Ollama's built-in agent was the smallest complete instance, and it treated loading a skill as a privileged act — until the agent was removed from Ollama in September 2026. Its whole procedural memory was four files: discovery across four roots, a 1 MiB ceiling and front-matter validation, an <available_skills> block of names and descriptions in the prompt, and a skill tool that loads a body by exact name. Two decisions transfer.

agent/tools/skill.go returns an unconditional true from RequiresApproval, with the reason in the comment — "Model-initiated loads require approval because a skill's instructions can influence the rest of the run" — while explicit user activation goes through a synthetic tool call that bypasses the gate. Voyager and Hermes gate the write; this gates the read, which is the operation that actually changes the agent's behaviour. Its limit is that the approval prompt shows a name, so the person approving has probably not read what they are approving.

The second is the trust disclaimer, said twice to two audiences. The Go type comment reads "It never grants tool permissions; it is supplied to the model as ordinary tool-result content", and the system prompt tells the model the same thing: "Skills only provide instructions; use ordinary tools for filesystem or network access, with their normal approval rules." That costs one line and answers the question a retrieved instruction document always raises.

Against all of that, Ollama has no verification gate of any kind — no critic, no success signal, no usage tracking — because it also has no write path. A skill exists because a person wrote the file.

Forgetful stores skills as rows beside memories — kebab-case name, description, Markdown body up to 100 KB, licence, compatibility, allowed tools, tags and an importance — with import_skill and export_skill in the Agent Skills SKILL.md format and a second vector table, vec_skills, built from the description alone so a skill is found by what it is for rather than by its body. The feature is off by default (SKILLS_ENABLED=false), nothing executes a skill, and nothing records whether following one worked. The ten SKILL.md files in the repository's own skills/ directory are the other half of the pattern: they are the server's memory policy — query before create, confirm before update or obsolete, announce every save — shipped as procedures the agent loads, and the server has no way to know whether it did.

Hivemind (Activeloop) answers the pruning question without a training reward, and then throws the answer away. Its write gate is the weak kind — a model curator reading ten recent sessions, told to keep a pattern only if it recurs across three exchanges and is not already covered, with nothing executed. The interesting half is after the write. A PreToolUse on an org skill arms a three-message judgment window; the user's next prompt spawns a worker that rebuilds the transcript around the invocation, appends the reaction, and asks a judge one question phrased against sycophancy — "Ignore whether the user seemed happy or polite — a praised-but-wrong answer is a FAILURE" — with an unparseable or errored verdict returning success, so the judge can miss a failure and never invent one. That is a reuse-quality signal derived from ordinary human reaction rather than a scored rollout, and it is the piece a library outside a training loop can borrow. The edit it produces is bounded the way this page's supersession tradeoff asks for: at most three anchored operations, a protected region the fast pass may not touch, and a new version appended rather than an overwrite.

Two failures sit beside it. The new version is published to the whole organisation under a comment reading "No approval gate by design: detect → improve → publish, directly", and auto-pull writes every author's skills onto every signed-in machine at the next session start — so one person's bad turn rewrites a colleague's procedure before anyone has read the diff. And the loop never closes: its meta log declares proposed | applied | reverted, writes only proposed, and reads the field nowhere, so the dedup prevents re-proposing an identical edit and nothing distinguishes an improvement from a regression. Declaring the states and not writing them is how a library keeps editing in a direction no one has checked.

SkillCorpus is the pattern at the other end of the supply chain: not an agent writing skills, but a pipeline admitting other people's — ~821,000 crawled files filtered by structural thresholds, an LLM judge over utility, robustness and safety, and a cross-source near-duplicate merge. Its transferable move is where the decisions live. Both judges write their verdict keyed on the SHA-256 of the body they judged — quality_judgments(content_hash PRIMARY KEY) and dedup_judgments(pair_key) over a sorted hash pair — and the build re-derives every exclusion from those caches before it exports. A skill excluded for a cmd_injection flag is excluded again the next time the same body is crawled, by the same verdict, and the judge is never re-asked. That is the thing SESA's eviction above is missing stated as a schema decision rather than a wish: an exclusion keyed on the value survives regeneration, and one keyed on the row does not. This library shows both, because the row-level markers here are clobbered by a re-ingest and only the hash-keyed caches hold.

It also ships the test this page asks for. test_an_unrelated_query_gets_nothing_from_the_local_source builds twelve file-handling skills, asserts the weather query returns an empty block, and asserts in the next line that the same directory still answers "fill an acroform" — the third bullet below, with the control that stops it passing vacuously. What it has none of is a verification gate or a usage signal: no skill is executed, nothing observes whether following one worked, and the record type it was adapted from had counters and lineage fields that were deliberately dropped.

Agent Memory Distillation stores procedure at three granularities and retrieves each at a different moment: a workflow insight and subtask examples before the first turn, and a per-function example only when that function's call returns an error (bfcl/common/memory/injection.py:338-400). It is also the counterexample on the success gate this pattern depends on. On BFCL the gate is a --score-file argument whose default is empty, so every teacher trajectory that did not force-quit becomes memory (bfcl/common/scripts/teacher_build_memory_multi_turn.sh:21), while its ToolSandbox builder keeps only scenarios at full milestone similarity.

Browsentic puts the gate on admission rather than on success, and puts it in front of a person. A mapping run walks one host with read actions only and hands in a typed report; the daemon renders it into a staging folder the skill loader skips, and the note joins the prompt only after a person reads the exact Markdown and presses Activate (src/daemon/agent/site-map-store.ts:84-98, :227-261; src/daemon/agent/skills.ts:87). Retrieval is a domain predicate on the active tab's host, so a site's notes cost nothing anywhere else. Two failures sit beside it. The prompt introduces generated and hand-written notes under one preamble calling them "the user's own words, not page content" (src/daemon/agent/prompt.ts:40), so the review becomes a promotion of page text to user voice. And its second procedural kind, a recorded demonstration turned into named steps by a one-shot agent call, becomes usable with no review at all (src/lib/bridge/recording-store.ts:105-141) — the same shape Cua has, where the person who demonstrates never sees the generated text.

ripwire-rs shows the staleness cost from the supply side. Its seventeen skills are adapted from ripwire's and embedded into the binary at build time, and they tell an agent to record a trade-off with --quality-ack, scope it with --scope, and expect notes beside --for output. The port's binary implements none of the three. A procedure carried across a rewrite describes the old implementation until something checks it against the new one; here nothing does, and an agent that follows the skill believes it recorded an acceptance the ledger never received.

MuscleMemory carries the outcome gate to coding agents and adds the generality check this page asks for. A session becomes a skill only when a test run passes after the last edit, and the skill reaches a prompt only after a person approves it and two later sessions, never the source, execute its required capabilities and action shapes and re-run its own test after their last change (packages/musclememory/service.py:723-845, retrieval.py:211-233). One failed check flags the revision for good. It also keeps the failures Voyager discards: failed runs with the same action sequence are diffed against the success by argument shape and become avoid notes (service.py:441-489). Two things weaken the gate. "Passed" is the exit status the client captured for a command recognised as a test runner by name (artifacts.py:18-77). And the hooks flag a skill only when the session was handed it and its own test ran last and failed (service.py:1232-1289), so a skill whose test is the whole suite is blamed for any later failure of the suite.

Screenpipe settles who may edit a skill with a hash rather than a flag. AgentSkillStore::create records created_by: screenpipe-agent and the file's SHA-256 in a manifest at the store root, where an imported skill folder cannot place one; a skill reads as agent-owned only while its file hashes to that value, and patch demands the current hash (crates/screenpipe-engine/src/agent_skills.rs:164-313). A person who edits a skill by hand therefore takes it from the agent with no setting to change, and manual_changes_revoke_agent_write_provenance asserts it. The admission side is weaker: creating a skill needs confirmed: true, a field the agent fills in its own tool call (:518).

Harness² stores skills as part of whole adopted harnesses and serves them to the editor rather than the executor. After each task a per-domain library receives the adopted tree — skills, scripts, subagents, plugins and always-on files — with the reflector's lesson, and every later task's editing sessions get the whole directory copied into context (harness2/core/library.py:106-152, harness2/core/context.py:160-169). A component reaches execution only when an editor copies it into the new harness, and validation rejects a skill whose script did not come with it (harness2/core/tree.py:324-333). There is no outcome gate: adoption is a blind model choice over deliverables, made without any selector session at k = 1, and a lesson is admitted when its three fields are non-empty (harness2/core/selection.py:360-399, :494-501).

Cindy holds a one-off approach back until it recurs. The nightly routine puts a skill draft first seen in an owner conversation into a candidate list that no prompt loads, promotes it only when a later night cites a new occurrence as evidence or a person presses promote, and drops it for good when a person declines (apps/desktop/src/main/maker-ipc/botNightlyLearning.ts:532-575, :634-647). The gate is recurrence, not execution: a promoted skill has been seen twice and never run against an outcome, and the teammate's own save_teammate_skill tool writes skills directly when the owner asks.

Tests to require

  • Store a skill, then execute the retrieved copy in a fresh context and assert it still succeeds — generality, not just recorded success.
  • Assert that a failed attempt produces no durable procedural memory.
  • Retrieve against an unrelated task and assert no skill is returned above threshold.
  • Supersede a skill and assert the prior version remains retrievable with a lineage link.
  • Compose: build a skill that calls a stored skill, then modify the callee and assert the caller's behaviour change is detected.
  • Assert the injected skill context stays inside a token budget as the library grows.
  • Execute a deliberately malicious stored procedure in the sandbox and assert containment.
  • Track reuse and assert that never-reused skills are surfaced for pruning.