Skip to main content
The learning configuration, capture behavior, and corrections-file format are experimental and may change without migration. Discuss feedback in GitHub Discussions.

What is Learning?

Learning lets reviewers deliberately teach an agent from real work. Leave a comment at review time and check Learn from this comment when the feedback should help in similar future situations. An unchecked comment revises the current run only. AgentUse turns checked feedback into concise, appropriately scoped guidance, stores it in a readable markdown file, and applies it to later runs when relevant. A learning is durable guidance, not an unconditional rule: the current task and the agent’s authored instructions still take precedence. That deliberate human choice is the default. Automatic observation of a run is advanced capability and remains available through explicit capture channels, but it is never enabled merely by writing learning: true. Everything a channel produces then passes a vet against the agent’s complete instructions before it can reach a future run, and everything that reaches a future run is stamped with the version of those instructions it was checked against.

Quick Start

A single switch applies deliberate human learnings on future runs:
During review, write the correction and check Learn from this comment. The same operation is available as --remember in the CLI. AgentUse grounds the comment in the work being reviewed, vets it against the agent’s instructions, and stores it. Unchecked comments are never added to durable memory. learning: true is sugar for { capture: true, apply: true }: it applies explicitly saved human learnings, while automatic observation remains off. Learnings accumulate in a learnings file inside the AgentUse state directory, not in your repository. agentuse learnings ./blog-writer.agentuse --path prints where; see Storage.
capture: true used to mean free-form auto-capture. As of v0.19.0 it enables no automatic observation channels. Human feedback is saved through the Learn checkbox, --remember, or manual add. See Upgrading an existing agent.

Store Without Applying

To collect explicitly selected human learnings without putting them into future prompts yet:
The Learn checkbox and --remember still save guidance. apply: false only keeps it out of future prompts until you turn application back on.

Advanced: Automatic Capture Channels

Most agents should stop at learning: true. Use capture channels only when you also want AgentUse to learn without a reviewer checking Learn on a comment.
capture: {} is the same as capture: true. This mirrors the verify schema deliberately: custom plays the role of verify.criteria (tune the built-in), agent plays the role of verify.judge (replace it), and setting both is a parse error with the same message style.

deliberate human learning

The Learn checkbox, --remember, and manual add are the standard human path. They are not automatic capture channels: the reviewer explicitly decides which comments become durable. Ordinary approval comments affect the current run only.

tool-errors (addon)

Learns a failed tool call followed by a corrected call and a confirmed success. Its value is that the verification happens in code, not in a prompt: a record is stored only when the run’s trace contains the failed call, a later successful call of the same tool, and a different input on the retry. A retry with identical input that happened to work is flakiness, not a lesson, and is not captured. The stored record carries the tool, a normalized failure signature, and both calls as evidence:
Because these records capture mechanics rather than policy, they cannot conflict with your instructions, so they skip the model-judged vet below. They dedupe by (tool, failure signature) and supersede structurally (one record per failure mode, replaced when a better recovery is observed), and they never go through the free-text merge path in tidy.

custom (scoped free-form)

The built-in evaluator, now allowed to extract from the execution itself and scoped by your guidance text. Free-form candidates carry no structural proof, so they rest entirely on the vet, which is why the channel is opt-in and its candidates never skip vetting.

agent (evaluator replacement)

An .agentuse file replaces the built-in evaluator for free-form capture, the same pattern as verify.judge. The path resolves relative to the agent file that declares it. The capture agent receives the run’s evidence and the learnings the agent already carries with their ids, and records its result by calling submit_learnings once with 0-5 candidates:
Replacing the evaluator does not buy a bypass. Its candidates still pass the common vet, provenance stamping, and lifecycle validation. Deliberate human learning stays on the separate Learn/--remember path either way; it never depends on a user-supplied capture agent behaving. A nested learning: or verify: block on the capture agent is ignored (a helper pass must not recurse into a tree of helper passes), and a capture agent that suspends on an approval gate is an error.
learning: true makes no post-run evaluator call. The built-in evaluator runs only when capture.custom is configured; use capture.agent when that automatic judgment is genuinely domain-specific.

Configuration Options

criteria was removed in v0.19.0 and is a hard parse error:
The only faithful mapping would keep free-form policy capture running automatically, which is exactly what the redesign exists to stop, so the rewrite is yours to make consciously. Setting both custom and agent is likewise a parse error: set either "custom" (built-in evaluator) or "agent" (agent file), not both.
Two keys were removed in v0.17.0 and remain rejected by name: evaluate (long deprecated) and file (a custom learnings path, now that learnings live outside your repository, see Storage). An agent file still carrying one fails loudly rather than quietly ignoring it.

Every candidate is vetted

Nothing becomes active on the strength of having been extracted. Every free-form candidate, corrections included, is checked against the agent’s complete instructions, the rules already in force, and the run’s own trace, before it can be injected into anything. Two properties are worth stating plainly:
  • Human corrections are never dropped. A reviewer’s rule that fails the vet is quarantined with the reason, not discarded. If the vet call itself fails, corrections are stored active and observation candidates are dropped. Free-form capture’s entire safety case is the vet, so it fails closed while human input fails open.
  • The vet sees the whole contract. The fixed 3,000-character truncation that used to hide every rule past the cut is gone. On any real agent that truncation is what let the evaluator “rediscover” an explicit instruction as a brand-new learning.

Quarantine

A quarantined entry is set aside, never injected, and never deleted. It stays visible with its reason in agentuse learnings <file>, the serve UI’s Learnings panel, and agentuse doctor:
The second one is a reviewer’s own note. A model-authored duplicate would have been rejected outright, with nothing lost: the rule already exists. A human wrote that one, so it is kept and shown instead. The fix is one of two things, and the reason line tells you which: correct the agent file so the rule is no longer in conflict, or discard the rule. Typed tool-errors records skip this step. They are verified structurally in code, and they describe mechanics rather than policy, so there is nothing for them to contradict.

Rules are stamped with the instructions they were checked against

Every stored learning records the hash of the agent instructions it was captured (or last re-vetted) against, alongside its channel, source session, and evidence. The hash covers your own instructions with the machine-managed graduated block excised, so a rule graduating never marks every other rule stale. When you rewrite the agent file, the hash no longer matches and the affected rules go stale:
  • Stale rules are held out of injection. A rule vetted against instructions that no longer exist does not get to keep applying unexamined.
  • The next capture or agentuse learnings tidy re-vets them against the current instructions: passes are re-stamped and start injecting again, failures are quarantined with the reason. Nothing is deleted.
  • Rules with no hash at all, anything captured before v0.19.0, are not stale. They stay injectable until the first capture or tidy backfills them.
agentuse doctor says so when it matters:

Storage

Learnings are stored in the AgentUse state directory, alongside session logs, not in your repository:
$AGENTUSE_DATA_DIR defaults to ~/.local/share/agentuse; when it is unset, $XDG_DATA_HOME/agentuse remains the standards-compatible fallback. {project-hash} is a digest of your git root, so two repositories that both contain agents/blog/write.agentuse keep separate learnings, and one agent resolves to one file whichever directory you run it from. The file itself is named after the agent’s path relative to the project root, so subdirectories are preserved. That path is not one you can type from memory, so nothing asks you to:
agentuse doctor ./blog-writer.agentuse prints it too, as does agentuse learnings ./blog-writer.agentuse --json in its file field. Every learnings file also records which agent it belongs to, on the line under its heading:

Why it is not next to your agent file

Every run rewrites this file, not only the runs that capture something: injecting a learning updates its counters. Kept in the repository, that is a permanently dirty working tree and a stream of commits carrying no decision. The file was never meant to be the durable artifact. It is a staging buffer; your agent file is the thing that gets diffed and reviewed, and graduation is how a proven learning crosses over into it.
The trade: learnings are no longer in git. There is no backup, no teammate sharing, and nothing survives a machine rebuild. The state directory holds locally generated data, like session logs. Graduation is the supported path into version control: a rule that has earned its way into your .agentuse file is committed, reviewable, and travels with the repository.Renaming or moving an agent file also starts its learnings over, because the file is keyed by the agent’s path. Rules already graduated into the agent file move with it and are unaffected.

Moving learnings from before v0.17.0

Learnings used to live beside the agent file, named after it: blog-writer.agentuse paired with blog-writer.agentuse.learnings.md. That location is no longer read, not as a fallback, not once. Move them:
Name one agent file, or pass --all to walk every .agentuse file under the project root. It copies first and asks before deleting anything. Once the copies are on disk it lists the originals and asks once whether to remove them; anything other than an explicit yes leaves them alone. Deleting files out of your repository is not something a migration should do on its own, so the destructive half is always yours to confirm. --delete-source answers yes up front (for scripts and non-interactive shells, where nothing is ever deleted without it), --keep-source answers no, and --dry-run reports what would be copied without writing anything. It refuses rather than merges when the destination already holds learnings, and it lists any *.learnings.md with no agent file of that name as orphaned, not migrated. Those are usually left behind by a rename, and this is the only place they are ever mentioned. If you skip the migration, the agent simply starts with an empty learnings store. Graduated rules are unaffected. The old files sit inert until you delete them, which is itself the point: inert means they stop churning. A run that finds learnings stranded at the old location says so once, and so do agentuse doctor and the learnings panel in the serve web UI:
This reads only whether that file exists, never what is in it, so the agent behaves identically with or without it. It keeps saying so even after the agent has captured new learnings into the new location, that is exactly when a populated panel makes a half-migrated agent look healthy.

How capture works

After a run finishes with an automatic channel configured:
  1. Gather candidates per channel. custom uses the built-in evaluator, agent runs the replacement evaluator, and tool-errors scans the run’s tool traces in code. Deliberate human learnings are saved immediately by the Learn/--remember path rather than inferred here.
  2. Vet the free-form candidates against the complete contract, the rules in force, and the trace. Passes become active, contradictions and failed human corrections are quarantined, and model-authored duplicates and ungrounded claims are rejected.
  3. Stamp provenance (channel, source session, evidence, and the instruction hash) and write to the store, enforcing max (the cap).
  4. Re-vet stored rules the contract has moved out from under: anything stale, and anything with no hash at all, is checked against the current instructions and either re-stamped or quarantined. This is what backfills a pre-v0.19.0 store the first time capture runs after an upgrade.
The result is reported in the run’s output and in the session log:

Deliberate Learning from Review Comments

At an Approval Gate, a comment normally revises the current run and nothing more. Check Learn from this comment when AgentUse should remember the feedback for similar future situations. That explicit choice is what makes the comment durable.
The same comment serves both purposes: it revises the current work, and when checked, the learning processor grounds it in the reviewed output and rewrites it as appropriately scoped guidance. For example, “this intro is too salesy” can become “For informational posts, keep intros factual rather than promotional,” not the universal rule “Never use promotional language.” Checking Learn works even when the agent has no learning configuration; the guidance is stored but reaches future runs only when learning.apply is enabled. Explicit human learnings are stored as src:manual and rank ahead of automatic observations. The CLI equivalent is:
A note you write this way is reconciled against the rules the agent already carries, exactly as a captured learning is. If it restates or contradicts one of them, it replaces that rule rather than being filed beside it, and the run names what it replaced:
This matters most on this path, because --remember is what you reach for when you are correcting an earlier note of your own. Left unreconciled, the rule and its own correction both stay in force, and the agent has to satisfy two instructions that disagree. A note can also collide with the agent file itself rather than with another rule. It is saved either way, but quarantined rather than injected, and the run says which instruction it conflicts with:

How Application Works

On next run or approval resume (when apply: true):
  1. Loads the agent’s active rules from storage, skipping quarantined and stale ones
  2. Injects the top max of them (15 by default) as a ## Relevant Learnings section
  3. Counts the injection against each rule’s injectedCount
The runtime tells the model to apply each learning only when its situation is relevant, preserve its intended scope, and never let it override the current task or authored agent instructions. A clearly relevant learning can refine a soft skill default without becoming a universal checklist item. Learnings that have graduated live in your agent file’s own ## Learned Guidance block. Graduation changes storage and reviewability, not these contextual semantics.
injectedCount counts cost, not value. It is how many runs a rule was paid for on, and it is never evidence the rule worked. The effectiveness signal is approvedRuns (runs the rule was in force for that ended in an approval with no comment), and that is what graduation is gated on. The store field was named applied: before v0.19.0 and is read as an alias; files are rewritten with injected: on the next save.

An agent keeps 15 rules, not 15 of many

max is how many rules an agent keeps, not how many of a larger pile get injected. Capture enforces it when it writes, so the set stays small enough that every rule in it has been weighed against every other one. That last part is the reason for the cap, and it matters more than the token cost. While the store could grow without limit and only the top slice was injected, nothing ever compared one rule against another. An agent could hold two corrections that could not both be satisfied - captured weeks apart, from separate rejections, each perfectly reasonable alone - and nothing would notice. So when the set is full, a new learning has to be paid for. In order:
  1. Fold. The evaluator sees every rule the agent already carries, each with its id, and is asked to reconcile rather than merely avoid duplicating. If its new learning restates, sharpens, or contradicts an existing rule, it returns one rule that satisfies both, naming the id it replaces. The replaced rule is retired, not deleted.
  2. Trade. Nothing related in the set? The weakest auto-extracted rule is retired to make room - but only if the new rule is worth more than the one it displaces, so the set keeps the best rules rather than the last ones.
Once the set is full this applies to reviewer corrections too. They cannot be traded away, so for them the answer is always to fold. That is the part that keeps the set at its size. Folding is not picking a winner. The merged wording has to carry every case the originals covered, and the model writing it can see all of them. Two things are never evicted: a rule you wrote or approved, and a rule you have repeated. A repeat means the wording is not landing, which is a reason to rewrite it, not to drop it. Precedence within the set is unchanged - rules you saved yourself, then reviewer comments, then self-extracted - with the most recent first inside each group.

When a correction does not fit

If the capture model returns a correction without naming a rule to fold it into, and no auto-extracted rule is left to trade away, the correction is kept anyway, outside the cap. It is not dropped - losing a reviewer’s correction because a helper model failed to pick an id would be worse. But a rule outside the cap is never injected, so the run tells you plainly:
This should be rare. If it is not, the corrections are carrying what your agent file should have said, and the fix is in the instructions rather than the store.
A rule outside the cap cannot recover on its own. It is never injected, so nothing about it is ever observed, and it is a human correction so it is never evicted either. Left alone it stays there having no effect. This is why a full set folds rather than grows - an earlier design let corrections accumulate past the cap, and one agent reached 70 of them, permanently unreachable.
A store written before the cap was enforced can hold far more than max. The first capture after upgrading drains the excess by retiring auto-extracted rules from the bottom of the ranking - the ones that were not reaching the model anyway. Nothing is deleted, and rules you wrote or repeated are never touched, so the drain tends to promote a starved correction into force.

Tidying up

When learnings outgrow the cap, or the agent file has been rewritten under them, one action gets them back in order:
or the Tidy up button in the serve UI, on the session view and the agent’s Learnings tab. Both run the same thing. It makes six kinds of change:
  • re-vet every rule that is stale or was never vetted against the current instructions, re-stamping the ones that still hold and quarantining the ones that no longer do, with the reason
  • merge near-duplicates into one rule
  • rewrite a learning you have repeated, a repeat means the wording is not landing, so restating it sharply is the fix
  • retire what has been superseded. A retired rule is removed, and re-asserting it later simply adds it back
  • graduate the learnings that have proven themselves into the agent’s own instructions, where they apply on every run and cost no cap slot
  • rewrite the permanent block in your agent file as one document, combining rules that overlap and dropping any another rule now fully states
The re-vet pass is why a tidy-up is worth running after you edit an agent file, even on a set that is comfortably under the cap: it is what gets stale rules injecting again, and what backfills a store captured before v0.19.0. That last change is the only thing that ever makes the permanent block smaller. Graduation alone only ever added to it, so on a long-running agent it accumulated the same way the staging file did, and more expensively: those rules apply on every single run. The rewrite reads the whole block at once, which is what lets it combine two rules that are halves of one procedure, or fold a correction into the rule it corrects. Two things check the result, because it edits a file you wrote:
  • Nothing may vanish. Every rule that goes in must come back inside some rule, or be named as dropped with a reason. If one goes missing the whole rewrite is discarded rather than written.
  • Nothing may be quietly summarised away. Each rewritten rule is then audited against the originals it claims, and asked what instructions it no longer carries, a case, a threshold, an exception, a worked example. Anything reported missing puts those originals back untouched, and the rest of the rewrite still applies.
The audit asks about meaning, not length. A merge that halves the wording while keeping every instruction passes; one that keeps the length but drops an exception does not. That matters because the tidy-up is supposed to make the block denser, shorter for the same instructions, and a length-based check would have blocked exactly the merges worth having. It applies immediately and then shows you what changed: a summary, the rules that became permanent named individually, each edit to the permanent block, and the diff of both files. Undo with agentuse learnings undo ./blog-writer.agentuse or the Undo button, which covers the re-vet pass along with everything else.
Each pass reads every learning still in force, so a pass takes about a minute. It runs in two stages: first it decides which learnings relate to which, in small groups weighed in parallel, then it writes each replacement rule in its own call, again in parallel. One tidy-up keeps going until another pass would not help. A single pass is cautious by design, and it compares learnings in small groups, so two duplicates that never share a group both survive it. Rather than making you press the button again, the tidy-up goes back over whatever is left, up to five passes, and stops as soon as a pass frees no slot. It all happens in memory: both files are written once at the end, so however many passes it took, one tidy-up is one Undo. In the web UI it runs on its own page, counting the rules as it writes them and naming the pass it is on; leaving that page does not stop it, and the result waits there with its Undo button. The agent’s Learnings tab links back to the last tidy-up (Tidied up 5m ago, see what changed or undo it) for as long as it is undoable, whether it was run from the browser or the terminal.

When it ends still over the cap

That is a normal ending for a well-used agent, not a failure, so the result says which rule kept each learning that is still in force:
The counts add up to the number still in force, so nothing is unaccounted for. When pressing again genuinely would get further (the five passes ran out, or a group of learnings could not be planned), it says so instead.
“You wrote it by hand” is not on that list, and used to be. A rule you typed was once exempt from retirement entirely, which sounds protective and is not: the only thing that can retire one of your rules is a later correction of your own, and a veto put that out of reach. One agent reached 85 corrections it could neither apply nor consolidate. Authorship now weighs heavily in the judgement instead of ending it. What still cannot be retired is a rule you have repeated, a repeat means the wording is not landing, so it gets sharpened rather than dropped.
Inspect first with agentuse learnings ./blog-writer.agentuse (a list by status) or agentuse learnings tidy ./blog-writer.agentuse --dry-run (the plan and both diffs, nothing written).

What makes a learning permanent

Graduation is earned, not guessed. A learning qualifies when any of:
  • you repeated it (re: above zero), saying the same thing twice is the clearest evidence a rule matters, or
  • it was in force across 3 runs you approved without leaving a comment. Approving with no notes is a vote for every rule that applied that run; a run you commented on credits nothing, because you had to correct something, or
  • it has been in force for 10 runs. Surviving that long without ever being contradicted is weaker evidence than the other two, but it is evidence, and without it a rule nobody comments on either way waits forever.
Writing a rule yourself does not graduate it on its own. It used to, and the result was that hand-written rules went permanent before they had ever been checked against the rules already there. Graduated rules are written into your agent file inside a marked block:
Only the bytes inside the markers ever change; your frontmatter, comments and formatting are left exactly as they were. Because the block is part of the agent file, it is diffable, reviewable in a pull request, and readable by a teammate who wants to know what this agent has been taught. Re-running the tidy-up replaces the block rather than appending a second copy. The block in the file is the source of truth for these rules, not a printout of one held elsewhere: the tidy-up reads it back before every edit, so wording you change by hand survives, and is what the next rewrite works from. The block is also excluded from the instruction hash, so a rule graduating never makes the rest of the set stale. Rules still on probation are injected under a separate ## Relevant Learnings heading, so the two tiers never collide.
Graduation is skipped, and the result says so, when the agent file is not writable. Nothing else can stop it: there is one learnings file per agent, so making a rule permanent never affects another agent.

Seeing what capture is doing

“Capture is producing junk” should be measurable, not anecdotal. Three surfaces show the same numbers. agentuse learnings <agent-file> lists every rule by status, grouped:
agentuse doctor <agent-file> adds the per-channel breakdown and the token cost:
legacy in that breakdown is entries captured before channels existed. The serve UI’s Learnings panel shows the same states with quarantine reasons inline, and links to the last tidy-up. Everything is agent-operable: agentuse learnings <agent-file> --json reports cap, active, injected, dormant, stale, and quarantined counts at the top level, and each entry carries its full record plus computed state, injected, and stale flags. agentuse learnings tidy --dry-run prints the plan without writing. No step in the lifecycle needs a human at a terminal, so a scheduled maintenance agent can do the cleanup.

Learning Categories

Learnings are categorized for context:
  • tip - General best practices
  • warning - Things to avoid
  • pattern - Successful approaches
  • tool-usage - How to use specific tools
  • error-fix - Solutions to known errors (the tool-errors channel always uses this one)

How long a learning should be

A captured rule is written as an order, not an explanation: one behaviour, a few sentences, and under 800 characters. It keeps the specifics that change what the agent does - a threshold, a trigger, an exception, the one example that shows what the rule means - and drops the incident it came from. Dates, session ids, names and quoted complaints are almost never load-bearing. This matters more than it looks. A rule too long to hold beside its peers cannot be compared against them, and comparison is what stops two contradicting rules being in force at once. If a rule needs headings or numbered sections, it is more than one rule.

Storage Format

Learnings are stored as readable markdown:
Every field except the date is optional, so older files load unchanged, and unknown tokens are ignored rather than rejected:
  • src: records who authored it, auto (an evaluator), approval (promoted from a reviewer comment), or manual (explicitly saved by a reviewer). Files without it load as auto.
  • ch: records the capture channel, one of corrections, tool-errors, custom, agent. Absent on entries written before channels existed.
  • ih: is the instruction hash the rule was last vetted against. Absent on entries that predate it; those count as fresh, not stale, until a capture or tidy backfills them.
  • injected: counts injections into a run’s prompt. applied: is the pre-v0.19.0 name and reads as an alias; the file is rewritten with injected: on the next save.
  • tool: and sig: are the tool-errors dedupe key, the tool and its normalized failure signature.
  • sess: is the session the rule was captured in.
  • state:graduated means the rule now lives in the agent file and this staged copy is on its way out. state:quarantined means it failed the vet and is never injected; the reason is on the <!-- why: … --> line beneath. Absent means active. A state:retired entry in an older file is skipped on read and dropped on the next write, so retired rules do not accumulate.
  • re: counts how many times a human repeated the learning; ok: counts the approved, uncommented runs it was in force for. These are the evidence the tidy-up uses to decide what to rewrite and what to make permanent.
  • <!-- evidence: … --> carries the one-line evidence trail, for tool-errors the failed and corrected calls.
The <!-- agent: … --> line under the heading is a breadcrumb, so a file sitting in the state directory can be traced back to the agent that wrote it. Nothing reads it back; it is there for you.

Upgrading an existing agent

No migration is needed and no file moves. Existing learnings files load as they are; the first capture or tidy after the upgrade backfills the instruction hash and vets the entries it finds, quarantining rather than deleting anything that no longer holds. undo covers that pass like any other. The dividing rule for config: hard-error and quit when honoring the key would resurrect risky behavior or the config contradicts itself; warn once and continue when the faithful mapping is strictly safer than what you had. Nothing is ever silently ignored. If you were relying on free-form capture and want it back, the one-line answer is a custom block naming what is worth keeping:
If you reached for apply: false to stop bad auto-captured rules from reaching the agent, try turning it back on. The vet is what apply: false was standing in for, and it discriminates: it drops the junk instead of throwing away the valid corrections along with it.

Example: Manual Review Workflow

After 5-10 runs, review what it captured with agentuse learnings ./blog-writer.agentuse (a list by status) or agentuse learnings ./blog-writer.agentuse --edit (the file itself):
Then update your agent instructions with the best insights:
This keeps you in control while still benefiting from extracted patterns.

Best Practices

Start with corrections

The default channel is the one a human authored. Run on it for a while before opening free-form capture with custom or agent

Scope free-form capture

When you do enable custom, say what is worth keeping and what to ignore. An unscoped evaluator finds something every run

Read the quarantine

A quarantined rule names the instruction it collided with. That is usually a defect in the agent file worth fixing, not just a bad rule

Tidy after you edit the agent

Rewriting instructions makes rules stale and holds them out of injection. agentuse learnings tidy re-vets them and graduates the proven ones

Next Steps

Store Guide

Persistent data storage for agents

Manager Agents

Orchestrate teams of learning agents