Edit the prompt. Ship. Hope.
- The playbook is a string in code, with no real versions.
- Feedback floats free. A thumbs-down cannot point at the wording.
- Or the agent edits itself, and the rules drift.
worked example · skill maintenance
A fictional support assistant attaches a discount code to every refund reply—even when the company made the mistake. Three example outcomes expose the problem. The system drafts a narrower rule, but only a person can decide whether it becomes the active playbook.
Simulation · example walkthrough. The support cases, outcomes, and proposed playbook revision are fictional examples used to walk through the maintenance loop. They are not customer incidents or a live policy change.
one ID to remember · nothing promoted automatically
00 · the problem
Today: a person edits a prompt in the codebase, ships it, and waits to see whether the complaints stop. The instructions live in source control, the complaints live in a support tool, and nothing connects a bad reply to the exact wording that produced it.
The assistant follows a playbook. One line of it is too broad.
“Attach a discount code to every refund reply.”
Each one is filed against the exact version of the playbook that caused it.
“Being upsold immediately after our billing error felt tone-deaf.”
The model writes the replacement. It cannot put it into service.
“When the charge was our own error, apologise and refund in full — no discount code.”Until someone approves it, the assistant keeps running the old line.
Report the outcome. Approve, or don’t.
await memseek.feedback.thumbs_down(use_id=use_id, note="Discount on a refund that was our own error.") await memseek.promote(...) # only a person runs this
New to Memseek? You write one small configuration file describing what your application should remember. After that your application only appends what happened; Memseek does the deriving, keeps every conclusion linked to the evidence underneath it, and hands your agent a bounded briefing instead of a pile of text. Everything below is that file and what it produces — how it works.
Three keyed records make up the current skill: steps, pitfalls, and examples. Rendering the skill resolves their current versions and records exactly which heads the agent used.
pitfalls@v1 says “Attach a discount code to every refund reply.”name: maintained_skill
kind: skill
lifecycle: reviewed
blocks:
sections:
document:
collections: [skills]
template: |
{{sections}}
candidate_processor: skill
complete_keys: [steps, pitfalls, examples]lifecycle: reviewedGenerated replacements stop as candidates. The renderer keeps serving the currently promoted records.
documentResolve the current keyed skill records at render time, so every use can identify the exact versions it carried.
complete_keysA candidate must contain the whole skill contract. Reviewers never approve a mysterious partial patch.
An artifact-use receipt pins the rendered skill — pitfalls@v1, “Attach a discount code to every refund reply.” — along with its definition hash and learning target. No skill record changes.
The application reports one task success plus a thumbs-down, a low evaluator score, and an operator correction. Each signal carries the artifact-use receipt, preventing feedback from being misattributed to whatever skill happens to be current later.
name: learning_signals
mode: event
schema:
required: [text, artifact_use, signal]
properties:
artifact_use:
required: [id, artifact, render_sha256]
signal:
required: [kind, source]
properties:
kind:
type: string
enum: [thumbs_down, correction,
task_failure, evaluation]
# plus success and exception kindsmode: eventKeep every selected outcome as immutable evidence. Do not edit history to make the new skill look better.
artifact_useBind the outcome to the precise render that influenced the reply, including its content hash.
signal.kind / sourceSeparate what happened from who judged it, so downstream policy can weigh an end user, evaluator, and application differently.
Four learning_signals records: one success, plus “Being upsold immediately after our billing error felt tone-deaf.” (thumbs down), an evaluation of 0.2, and an operator correction — “Apologize and fix company errors; reserve discounts for goodwill and retention.” The over-broad rule remains active while evidence accumulates.
The derivation compares new evidence with the current skill, first proposes the smallest supported patch, then materializes all three sections. The emission contract requires citations and marks the output for review.
Always include a discount code for the customer’s next order before closing.
Being upsold immediately after our billing error felt tone-deaf.
The always-discount rule fires when the company caused the charge.
Apologize and fix company errors; reserve discounts for goodwill and retention.
The working refund procedure remains intact.
Do not attach a discount when the company caused the error; use one only for a supported goodwill or retention case.
The existing worked examples remain part of the complete draft.
The candidate has an effect only after a person promotes it.
Visible effect: the problematic rule changes in the draft; the rest of the playbook is preserved; production behavior does not move yet.
sources:
new_evidence:
kind: changes
collections: [main, outcomes]
current_skill:
kind: current
collections: [skills]
tasks:
- id: proposal
- id: result
emit:
collection: skills
keys: [steps, pitfalls, examples]
complete: true
review: requiredproposal → resultSeparate diagnosis from writing: identify the smallest evidence-supported change, then construct the complete candidate snapshot.
complete: trueRequire all three keys in one coherent draft, even when only pitfalls changes.
review: requiredStore the output as a candidate. Only an explicit promotion moves the active heads.
One cited candidate replaces “discount every refund” with “When the charge was our own error, apologise and refund in full — no discount code.” steps and examples are carried forward unchanged. The old skill still serves until approval.
01 · the skill
Not a prompt string in your codebase — records in a keyed collection, so the playbook has versions, provenance, and a current head the agent reads at render time.
A new version of pitfalls supersedes the old one. The old one is still addressable, so "what was the playbook in March?" has an answer.
The agent never reads the collection directly. It renders an artifact, which pins the exact heads it used.
A derivation can propose a new version of any of the three keys — but only as a draft.
Each version names the run that wrote it and the evidence that run stood on.
02 · bind a use
Rendering the prompt gives you text. Binding the render gives you a handle: the artifact identity, its content hash, and the exact promoted skill heads that were in force when the assistant ran. Store that ID beside your own result and you are done.
artifacts: - name: daily_agent_prompt kind: prompt lifecycle: live blocks: skill: {document: {collections: [skills]}} calendar: {view: upcoming_calendar@1} memory: {view: agent_relevant_memory@1} # Feedback about a render of this prompt is about the # maintained skill it carried, not about the calendar or the # retrieved memory. Binding a use resolves this to the exact # promoted skill heads that were in force. learning: target_block: skill artifact: maintained_skill@1
03 · report what happened
A thumbs-down, a correction, an evaluation score, a task result — each one lands as a learning_signals record naming the precise skill version that produced the bad reply. No special store, no privileged pipeline.
Submitting an outcome against a use ID always writes a record. That part needs no decision.
Whether a single thumbs-down is worth revising a playbook — or whether it takes three, or a score below a threshold — is a product judgement, so the catalog does not guess it. Your application routes the signals it considers evidence into the collection the skill pipeline watches.
A signal never changes the skill on its own, and never promotes anything.
04 · the draft, and the gate
The shipped skill derivation fires on new evidence, under a cooldown, and emits all three sections at once as a candidate. Because the reviewed artifact names the complete key set, a partial draft cannot be promoted over a working playbook.
A candidate must cover all three, so promotion can never leave the playbook half-updated.
If the live skill moved while the draft sat in review, activation is rejected rather than clobbering it.
Decline and the skill simply never changed — with a permanent record of what was proposed and refused.
name: skill trigger: write: collections: [main, outcomes] types: [skill_brief, outcome, observation, exception, feedback] cooldown_s: 600 # don't redraft on every signal sources: new_evidence: {kind: changes, max_records: 100} current_skill: {kind: current, keys: [steps, pitfalls, examples]} model: strong limits: max_tasks: 2 max_llm_calls: 4 max_total_tokens: 50000 # artifacts/skill.yaml — the reviewed contract artifacts: - name: maintained_skill kind: skill lifecycle: reviewed # not live — promotion required candidate_processor: skill complete_keys: [steps, pitfalls, examples]
05 · from your app
Four calls across the whole loop, and only the last one is a decision.
# 1 · render the prompt your assistant will run on, and bind it prompt = memseek.artifact("daily_agent_prompt") use = await prompt.bind(entity="agent:support") use["id"] # store this one ID beside your own reply use["learning_target"] # the exact promoted skill heads in force # 2 · later, report what the reply actually caused await memseek.feedback.thumbs_down( use_id=use["id"], note="Discount code on a refund that was our own billing error.", ) await memseek.feedback.correction( use_id=use["id"], expected="We've refunded the full charge and fixed the cause.", ) # 3 · draft a revision from the evidence, then read the candidate queued = await memseek.run_processor("skill", entity="agent:support") job = await memseek.job(queued["job_id"]) # poll to a run id review = await memseek.run(job["successful_run_id"]) candidate = review["run"]["content"]["candidate_set"] candidate["covered_keys"] # ["steps", "pitfalls", "examples"] candidate["divergence"] # what actually moved, per key # 4 · the decision. this is the only line that changes the skill. if approved_by_a_human(candidate["divergence"]): await memseek.promote( entity="agent:support", source_run_id=job["successful_run_id"], artifact="maintained_skill", )
The artifact's learning: declaration, the skill derivation's trigger and limits, and the maintained_skill reviewed contract are the checked-in catalog; the loop is examples/skill_maintenance.py. The drafted wording is representative of a real provider run, not a captured transcript.
start building
The script installs a skill, binds a real render, reports outcomes against it, drafts a cited revision — and then stops and asks you. Declining is the interesting path: the skill never changes, and the proposal stays on the record.