Self-Improve Command
Bootstrap and operate a self-improving, proactive agent workspace.
Path Resolution (applies to all modes)
Before executing any mode, resolve LEARNINGS_BASE:
- If mode is
init global→ use~/.claude/ - Else if mode is
init local→ use.(current working directory) - Else if
~/.claude/.learnings/exists → use~/.claude/as base (global setup) - Else if
.learnings/exists in the current working directory → use.as base (project setup) - Else if mode is
init(no argument) → ask the user to choose (see init mode below) - Else → default to
~/.claude/, create the directories, and inform the user that global setup was auto-created
~/.claude/ resolves consistently across all platforms (macOS, Linux, Windows) because Claude Code uses os.homedir() for ~. On Windows this maps to C:\Users\<you>\.claude\ — no manual path adjustment needed.
All path references in every mode below use LEARNINGS_BASE as the root:
| Logical path | Resolved path (global) | Resolved path (project) |
|---|---|---|
.learnings/LEARNINGS.md | ~/.claude/.learnings/LEARNINGS.md | .learnings/LEARNINGS.md |
.learnings/ERRORS.md | ~/.claude/.learnings/ERRORS.md | .learnings/ERRORS.md |
.learnings/FEATURE_REQUESTS.md | ~/.claude/.learnings/FEATURE_REQUESTS.md | .learnings/FEATURE_REQUESTS.md |
memory/working-buffer.md | ~/.claude/memory/working-buffer.md | memory/working-buffer.md |
memory/SESSION-STATE.md | ~/.claude/memory/SESSION-STATE.md | memory/SESSION-STATE.md |
memory/YYYY-MM-DD.md | ~/.claude/memory/YYYY-MM-DD.md | memory/YYYY-MM-DD.md |
.learnings/.pending-errors.log | ~/.claude/.learnings/.pending-errors.log | .learnings/.pending-errors.log |
Promoted rules follow the entry's Scope, not LEARNINGS_BASE: a global lesson lands in ~/.claude/rules/<domain>.md, a project lesson in .claude/rules/<domain>.md. The opt-in targets (CLAUDE.md, AGENTS.md, .github/copilot-instructions.md) are always project-local. Only the capture files follow LEARNINGS_BASE.
Reference: references/agent-self-improve.md → Global vs project scope
Helper Script
Modes below run bash ~/.claude/scripts/learnings.sh <subcommand> for anything deterministic (with the platform-guardrails plugin enabled, learnings.sh is on PATH and can be run directly): reading entries, validating them, checking dates, changing a status. If the script is missing, say so once, offer to install it (init global step 5), and do the step by hand. Exit code 3 means another session holds .learnings/.drain.lock. Wait a few seconds and retry once. Exit code 4 means the helper refused: the entry doesn't exist, or it exists and is not eligible. promote also refuses on the wrong status, missing or invalid provenance, a stale or expired entry, an inferred source without --allow-inferred, another project's scope, a Paths conflict with the target, and an entry already promoted elsewhere; unpromote refuses when no rule carries the entry's marker. Never guess which one it was: the helper prints the reason on stderr, so relay that line.
Reference: references/agent-self-improve.md → Helper script
Mode: init global
Scaffold the global workspace under ~/.claude/ — learnings persist across all projects.
/platform-skills:self-improve init global
Steps:
- Set
LEARNINGS_BASE=~/.claude/ - If
~/.claude/.learnings/already exists: report current state, list existing files, and stop — do not overwrite - Create the directory structure:
~/.claude/.learnings/LEARNINGS.mdERRORS.mdFEATURE_REQUESTS.md~/.claude/memory/working-buffer.mdSESSION-STATE.md
- Seed each file with the correct header and an example entry marked
Status: example - On Claude Code, offer the plugin first:
claude plugin install platform-guardrails@platform-skillswires all four hooks from the plugin and putslearnings.shonPATH, and plugin updates deliver fixes to the scripts. If the user takes it, skip the rest of this step, and make sure~/.claude/settings.jsonhas no self-improve hooks left (both wirings at once would capture every event twice; from 1.44.1 the plugin'sSessionStartnames any settings file that still wiresself-improve-hook). Otherwise, detect the user's platform and offer to wire all four hooks (SessionStart,SessionEnd,PostToolUseFailure,PreCompact) in~/.claude/settings.json:- macOS / Linux / WSL / Git Bash →
self-improve-hook.shwith thesession-start,session-end,tool-failureandprecompactsubcommands; point tosettings.json.example - Windows native (PowerShell) →
self-improve-hook.ps1, same four subcommands; point tosettings-windows.json.example, and have the user replace the literalC:\Users\alexwith their own profile path - Alpine or minimal Linux → same as macOS/Linux but remind the user to install bash first:
apk add bash - Also copy
examples/agent-self-improve/scripts/learnings.shto~/.claude/scripts/andchmod +xit.log,recall,review,status,promoteandrevokecall it - The script is in
examples/agent-self-improve/scripts/. Keep"timeout": 10onSessionEndand onPreCompact, and"async": trueonPostToolUseFailure PreCompacttakes nomatcher; it is filtered by itstriggerfield (manualorauto), not by tool name. Do not wire aPostCompacthook:SessionStartalready fires again withsource=compact- If any settings file still contains
Stop,PreToolUseorPostToolUseself-improve entries, point the user at "Migrating from the legacy hooks" inexamples/agent-self-improve/README.mdand do not leave both wirings active
- macOS / Linux / WSL / Git Bash →
- Offer to create
~/.claude/CLAUDE.mdfrom the template atexamples/agent-self-improve/global-claude.md - Print bootstrap summary:
✓ ~/.claude/.learnings/LEARNINGS.md — positive learnings✓ ~/.claude/.learnings/ERRORS.md — mistakes and root causes✓ ~/.claude/.learnings/FEATURE_REQUESTS.md — recurring unmet needs✓ ~/.claude/memory/working-buffer.md — WAL scratchpad and task state✓ ~/.claude/memory/SESSION-STATE.md — always-on session capture✓ ~/.claude/memory/YYYY-MM-DD.md — daily notes (created on first use)
- Remind the user to run
/platform-skills:self-improve reviewafter a few sessions
Reference: references/agent-self-improve.md → Global vs project scope
Mode: init local
Scaffold a project-local workspace in the current working directory — learnings live in the repo.
/platform-skills:self-improve init local
Steps:
- Set
LEARNINGS_BASE=.(current working directory) - If
.learnings/already exists in$PWD: report current state, list existing files, and stop — do not overwrite - Create the directory structure:
.learnings/LEARNINGS.mdERRORS.mdFEATURE_REQUESTS.mdmemory/working-buffer.mdSESSION-STATE.md
- Seed each file with the correct header and an example entry marked
Status: example - Check
.gitignore— ask the user:- Gitignore (recommended for personal notes): add
.learnings/andmemory/to.gitignore - Commit: leave untracked so the team can share and build on them; note that
memory/daily notes grow fast
- Gitignore (recommended for personal notes): add
- Offer to add hooks to
.claude/settings.json(this project only):- PostToolUseFailure →
self-improve-hook.sh tool-failurewith"async": true. The script resolves.learnings/itself, so the same command works at either scope - PreCompact →
self-improve-hook.sh precompactwith"timeout": 10. This drains captured failures at each compaction, which is the only consolidation that still happens when a session is killed rather than closed - Note: the
SessionStartandSessionEndhooks should be wired globally via~/.claude/settings.jsoneven for project-local learnings
- PostToolUseFailure →
- Print bootstrap summary:
✓ .learnings/LEARNINGS.md — positive learnings✓ .learnings/ERRORS.md — mistakes and root causes✓ .learnings/FEATURE_REQUESTS.md — recurring unmet needs✓ memory/working-buffer.md — WAL scratchpad and task state✓ memory/SESSION-STATE.md — always-on session capture✓ memory/YYYY-MM-DD.md — daily notes (created on first use)
- Remind the user to run
/platform-skills:self-improve reviewafter a few sessions
Reference: references/agent-self-improve.md → Global vs project scope
Mode: init (no argument)
When called without global or local, ask the user to choose:
- Recommend
init globalif neither~/.claude/.learnings/nor.learnings/in$PWDexists - If
~/.claude/.learnings/already exists, recommendinit local(global already set up) - If
.learnings/in$PWDalready exists, report its state and suggest usinglog,resume, orreviewinstead
Then proceed as init global or init local based on the answer.
Reference: references/agent-self-improve.md → Directory layout, Entry format
Mode: log
Log a learning, error, or feature request to the appropriate file.
Steps:
- Classify the entry:
- Learning (
LRN) — a technique, pattern, or shortcut that worked - Error (
ERR) — a mistake, misunderstanding, or failed assumption - Feature request (
FEAT) — a need that was unmet by the current skill or tool set
- Learning (
- Generate the ID:
<TYPE>-YYYYMMDD-NNNwhereNNNis the next sequential number in that file today - Before logging, run
bash ~/.claude/scripts/learnings.sh recall --all <2-3 keywords from the Context>to find an existing entry for the same root cause. If one exists, update its Action, set Verified to today, and keep the existing ID. Don't create a duplicate. If the new lesson replaces an older one, write the new entry with**Supersedes**: <old-id>and runbash ~/.claude/scripts/learnings.sh set-status <old-id> superseded --note "replaced by <new-id>" - Run
bash ~/.claude/scripts/learnings.sh whereamifor the scope and project name, then write the entry:### LRN-20260520-001**Status**: pending**Context**: <one sentence — what was happening>**Content**: <the learning, error description, or feature request>**Action**: <what was done or should be done>**Source**: <user | observed | ci | repo | vendor-docs | inferred>**Scope**: <global | project:<name>>**Verified**: <today, YYYY-MM-DD>- Source:
userwhen the user stated it,observedorciwhen a tool result proved it,repoorvendor-docswhen documentation says so,inferredwhen you concluded it yourself. Pick honestly:inferredgoes stale in 30 days and needs confirmation before promotion - Scope:
globalonly when the lesson holds in any repository. Otherwise useproject:<name>fromwhereami. Project-specific details must not leak into global memory - Add
**Paths**: <glob>, <glob>when the lesson only concerns certain files, and**Expires**: <date>for a workaround or exception with a known end
- Source:
- If the fix was applied in this same session, immediately set
Status: resolvedand record what was done in Action. - Append to the correct file without modifying any existing entries
- Run
bash ~/.claude/scripts/learnings.sh lintand fix anyERRORline that names the new entry - Confirm: "Logged as
<ID>in$LEARNINGS_BASE/.learnings/<FILE>.md"
Reference: references/agent-self-improve.md → Entry format, Recurring Pattern Detection
Mode: resume
Resume an incomplete task after context compaction or session interruption.
Steps:
- Read
$LEARNINGS_BASE/memory/working-buffer.md— identify current task and last[x]step - Check the buffer's last-modified date:
- If the buffer is 3 or more days old, warn: "Working buffer is N days old — state may be stale. Verify resources before resuming."
- If the buffer is 7 or more days old, surface as a blocker: "Buffer is N days old. Recommended to clear and start fresh unless you can verify all resource state."
- Read
$LEARNINGS_BASE/memory/SESSION-STATE.md— reload corrections, preferences, and decisions - Read today's
$LEARNINGS_BASE/memory/YYYY-MM-DD.md— reload recent session exchanges - Verify the actual state of affected resources before continuing:
- Files: check they exist and have expected content
- Kubernetes:
kubectl get <resource> -n <namespace> - Terraform:
terraform state list - Git:
git log --oneline -5
- Resume from the first
[ ]step — do not re-run already-committed steps - If a WAL entry shows
Status: PENDING, determine whether the operation completed (check the resource) and update toCOMMITTEDorROLLED_BACKaccordingly
Never ask "where were we?" — the buffer and session state answer that.
Reference: references/agent-self-improve.md → Compaction Recovery, SESSION-STATE
Mode: review
Scan $LEARNINGS_BASE/.learnings/ for recurring patterns and surface actionable items.
Steps:
- Read all three
$LEARNINGS_BASE/.learnings/files - Run
bash ~/.claude/scripts/learnings.sh lint. Report everyERROR(fix it), everyEXPIRED(ask whether to extendExpiresor revoke), and everySTALE(check the current state, then either updateVerifiedor revoke). Put aSTALEline that says "its promoted rule is still loaded" first - Group entries by context keyword similarity
- Report any context that appears three or more times as a promotion candidate:
PROMOTION CANDIDATE — ERR: "missing resource limits"Entries: ERR-20260518-001, ERR-20260519-002, ERR-20260520-001Suggested target: .github/copilot-instructions.md → "Always add resource limits"
- Report entries still in
pendingstate older than 7 days - Report entries in
resolvedstate older than 30 days — these are stale and should be either promoted or discarded:STALE RESOLVED — LRN-20260410-001: "helm diff before upgrade" (45 days in resolved)Action: run /platform-skills:self-improve promote LRN-20260410-001 or set Status: discarded - Report unresolved
FEATentries that could be addressed by an existing platform-skills domain - Process
$LEARNINGS_BASE/.learnings/.pending-errors.logif it exists and is non-empty — convert each line to a properERRentry and clear the log - Print totals:
Learnings: 8 total, 3 pending, 5 resolved (1 stale)Errors: 5 total, 1 pending, 4 resolvedFeature requests: 2 total, 2 pendingPromotion candidates: 1 | Stale resolved: 1
Reference: references/agent-self-improve.md → Recurring Pattern Detection
Mode: recall
Search learnings without changing anything.
/platform-skills:self-improve recall karpenter pod identity
Steps:
- Run
bash ~/.claude/scripts/learnings.sh recall <terms>. Add--limit Nto see more than 8 results. Add--allto include revoked, superseded, discarded, expired and other-project entries, which are flagged - Relay each result with how far to trust it:
STALEorverify before use: check the current state (repository, cluster, docs) before relying on it, and say that you're checking- No flag, source
user,ciorobserved: apply it and cite the ID
- If recall reports excluded entries, mention them. A revoked lesson that matches is a warning worth hearing
- If nothing matches, say so. Never invent a memory
Reference: references/agent-self-improve.md → Helper script
Mode: promote
Promote a resolved entry to the correct memory file.
Steps:
-
Read the entry by ID. Promotion changes behaviour in every future session, so
learnings.sh promoterefuses entries that:- aren't
resolved - lack
Source,ScopeorVerified - are stale or expired
- come from an
inferredsource, unless the user confirms the lesson and you pass--allow-inferred - are scoped to another project
Relay a refusal as-is and help fix its cause. For example, re-verify the lesson and update
Verified. - aren't
-
Pick the domain: a lowercase topic name (
terraform,kubernetes,github-actions). The rule lands in<domain>.md -
Draft the rule: imperative voice, one line, at most 160 characters:
- ERR → negative rule: "Never use
kubectl deletewithout first capturing the manifest" - LRN → positive rule: "Prefer
helm diff upgradebeforehelm upgradeto preview changes"
- ERR → negative rule: "Never use
-
Preview. This prints the evidence, the target and a diff, and writes nothing:
bash ~/.claude/scripts/learnings.sh promote <ID> --domain <domain> --rule "<rule>"Entry scope Default target Loaded global~/.claude/rules/<domain>.mdEvery session on this machine project:<name>withPaths.claude/rules/<domain>.mdwithpaths:frontmatterWhen Claude reads a matching file project:<name>withoutPaths.claude/rules/<domain>.mdEvery session in this project When the team needs the rule in a file other tools read, pass
--target CLAUDE.md,--target AGENTS.mdor--target .github/copilot-instructions.md. The rule goes under## Agent Rules. A rule withPathscan only go to.claude/rules/ -
Show the preview and ask the user to confirm the target and wording
-
Apply: re-run with
--apply. The script writes the rule with a<!-- self-improve:<ID> -->marker and sets the entry topromoted, recording the target inStatus-Note -
For a target inside the repository, commit with a conventional commit message:
docs(memory): promote <ID> — <imperative summary>
Rollback: bash ~/.claude/scripts/learnings.sh unpromote <ID> removes the marked line and sets the entry back to resolved.
Reference: references/agent-self-improve.md → Entry lifecycle, Promotion targets
Mode: revoke
Stop a lesson from influencing behaviour while keeping its history.
/platform-skills:self-improve revoke ERR-20260520-001 "wrong since EKS 1.35"
Steps:
- Ask for the reason if none was given. A revocation without a reason can't be audited later
- If a newer entry replaces this one, use
supersededinstead: set**Supersedes**: <ID>on the newer entry and runset-status <ID> superseded - Retire it. If the entry is
promoted, runbash ~/.claude/scripts/learnings.sh unpromote <ID> --revoke --note "<reason>". That removes the marked rule from every promotion target and setsrevokedin one step. If it reports that no rule carries the marker (the rule predates markers), remove the line by hand first. Otherwise runbash ~/.claude/scripts/learnings.sh set-status <ID> revoked --note "<reason>" - Confirm: "Revoked
<ID>:"
Reference: references/agent-self-improve.md → Entry lifecycle
Mode: state
Capture a correction, preference, decision, or proper noun to memory/SESSION-STATE.md.
Steps:
- Classify the signal:
- Correction — user ruled something out or redirected approach
- Preference — stated preference for this project or session
- Decision — a choice was made between options
- Proper noun — cluster name, team name, account ID, service name
- Append to the correct section in
$LEARNINGS_BASE/memory/SESSION-STATE.md:- YYYY-MM-DD — <one sentence capturing what was said or decided> - Update the
Last updated:timestamp at the top of the file - Confirm: "Captured to
$LEARNINGS_BASE/memory/SESSION-STATE.md"
When to invoke proactively (without being asked):
- User corrects an assumption mid-session
- User states a preference ("I prefer X", "don't do Y here")
- A decision is reached between two approaches
- A non-obvious proper noun appears that isn't in project docs
Reference: references/agent-self-improve.md → SESSION-STATE, Compaction Recovery
Mode: status
Print a one-screen health summary of the self-improve workspace — no changes made.
/platform-skills:self-improve status
Steps:
- Resolve
LEARNINGS_BASE(same auto-detection as all other modes) - Read all three
$LEARNINGS_BASE/.learnings/files and$LEARNINGS_BASE/memory/working-buffer.md. Also runbash ~/.claude/scripts/learnings.sh lint. - Print the summary:
Self-Improve Status───────────────────────────────────────────────Workspace: ~/.claude/ (global) [or: ./ (local)]Learnings 3 pending 8 resolved 2 promotedErrors 1 pending 4 resolved 0 promotedFeature reqs 2 pending 0 resolved 0 promotedPending errors log: 2 unprocessed entriesLint: 0 errors, 2 stale, 1 expired, 5 without metadataWorking buffer: active task — "deploy payments service"Buffer age: 2 daysLast session: 2026-05-23 (today)Sessions since review: 3 of 5Action items:• 1 pending ERR older than 7 days → run review• 2 stale resolved LRN (30+ days) → promote or discard• Run /platform-skills:self-improve review (due in 2 sessions)───────────────────────────────────────────────
- If
.pending-errors.logis non-empty, note count but do not drain it (status is read-only) - If no action items exist, print: "✓ Workspace is healthy"
Reference: references/agent-self-improve.md → Entry lifecycle
Mode: migrate
Move the workspace from one scope to the other without losing any entries.
/platform-skills:self-improve migrate global # project-local → ~/.claude/
/platform-skills:self-improve migrate local # ~/.claude/ → current project
Steps:
- Detect the source location:
migrate global: source is.learnings/andmemory/in$PWDmigrate local: source is~/.claude/.learnings/and~/.claude/memory/
- Detect the target location (opposite of source)
- If target already has entries, ask the user:
- Merge — append source entries to target files (default)
- Replace — overwrite target with source
- Cancel — abort with no changes
- Write a WAL entry to
$LEARNINGS_BASE/memory/working-buffer.mdbefore moving anything - Copy all
.learnings/*.mdentries andmemory/files to the target - Verify the target has all entries (count matches source)
- Ask the user to confirm deletion of the source directory before removing it
- Print migration summary:
Migrated to ~/.claude/ (global):✓ .learnings/LEARNINGS.md — 8 entries✓ .learnings/ERRORS.md — 5 entries✓ .learnings/FEATURE_REQUESTS.md — 2 entries✓ memory/working-buffer.md✓ memory/SESSION-STATE.mdSource removed: ./.learnings/, ./memory/
- If the source had hooks in
.claude/settings.json, offer to update them for the new scope
Reference: references/agent-self-improve.md → Global vs project scope
Load this section only when the user has run
initor explicitly enables proactive mode.
Proactive Agent Protocols
These protocols run automatically when the proactive agent pattern is active. No explicit mode is required.
WAL Protocol
Before any destructive or hard-to-reverse operation:
- Write a WAL entry to
$LEARNINGS_BASE/memory/working-buffer.mdbefore acting - Format:
## WAL Entry — YYYY-MM-DD HH:MM**Operation**: <what is about to happen>**Affected resources**: <list files, K8s resources, cloud resources>**Blast radius**: <what could break>**Rollback**: <exact command to undo>**Status**: PENDING
- Proceed with the operation
- Update
StatustoCOMMITTEDafter success - Update to
ROLLED_BACKif aborted
Destructive operations requiring a WAL entry: deleting files, git reset --hard, git push --force, terraform destroy, dropping database tables, modifying shared infrastructure.
Working Buffer
Maintain $LEARNINGS_BASE/memory/working-buffer.md as a live task scratchpad:
- Write at task start with the plan and steps
- Update after each significant step with
[x]progress markers - At ~60% context: write a compaction-ready summary proactively — do not wait for a compaction event
- Read at session start to resume after compaction
- Do not delete the buffer at session end if the task is incomplete
SESSION-STATE
Maintain $LEARNINGS_BASE/memory/SESSION-STATE.md as always-on session capture. Write to it before responding whenever:
- The user corrects an assumption or rules out an approach
- A preference is stated
- A decision is made between options
- A non-obvious proper noun or fact is encountered
This file is the second read in compaction recovery (after working-buffer, before daily notes).
Daily Notes
Write notable exchanges, discoveries, and outcomes to $LEARNINGS_BASE/memory/YYYY-MM-DD.md (today's date). One file per day, append-only. Read today's file at session start alongside the working buffer.
Verify Before Reporting (VBR)
Before reporting a task as complete:
- Run the validation command (CI check, test suite,
kubectl get,terraform plan) - Read the file that was changed to confirm the edit landed
- Text change ≠ behavior change — test actual outcomes
Never claim a fix is done based on the intent to fix it. Evidence required.
ADL Protocol
When choosing between implementation approaches, apply this priority:
Stability > Explainability > Reusability > Scalability > Novelty
Log the decision in the buffer when it was a non-obvious choice.
VFM Scoring
Before unsolicited proactive action, score against four dimensions (max 100). Act only if score ≥ 50:
- High Frequency (×3) — will this recur?
- Failure Reduction (×3) — prevents real breakage?
- User Burden (×2) — saves meaningful user effort?
- Self Cost (×2) — low effort for the agent?
Check CLAUDE.md or AGENTS.md for VFM_THRESHOLD=<N> before applying the default of 50. Use that value if present.
Heartbeat
For tasks > 10 steps or > 5 minutes, report progress without waiting to be asked:
[Heartbeat] Completed 4/7 steps. Currently: <step>. Next: <step>.
Reverse Prompting
Ask one clarifying question before acting on ambiguous or high-risk instructions. Never ask more than one question per instruction.