UMS — Update Memories and Skills
Actively review recent session context and update all relevant memory files and skill definitions to capture what was learned. Unlike record-learnings (which records individual facts in place as they arise), UMS is a reflective checkpoint: survey what accumulated, categorize it, and persist it all in one committed pass.
When this fires
- As soon as a learning worth saving shows up — a corrected mistake, a new preference, a tool quirk, a workflow gap. This is the primary trigger: run UMS right then, interleaved with the main work, instead of batching learnings for a wrap-up step at the end. Don’t wait for the task to finish or for
/clearto accumulate a backlog — and don’t gate it on approval or on a PR merging: capture the learning the moment it appears, even while the PR that taught it is still open and unreviewed. - User says “ums”, “update memories and skills”, “record what we learned”
- At the start of
/clear— a backstop, not the primary trigger: catch anything accumulated since the last proactive pass before context is lost - After a workflow reveals a gap (e.g., a skill was followed but missed a step, or a preference wasn’t encoded)
- When the user says “did you update memories?” (the answer should be “let me do that now”)
- While paused waiting on a subagent or a long-running background process to complete. That idle stretch is exactly when there’s time to survey what’s accumulated so far and persist it, rather than only running UMS at a hard stop. Don’t let a real wait sit fully idle when a useful pass is available to run alongside it.
Procedure
Scan recent context. Review the conversation for:
- Mistakes made and corrected (skill gaps)
- New preferences expressed by the user
- Tool quirks discovered
- Workflow steps that were missing or unclear in existing skills
- Debugging insights
- Codebase conventions discovered
Categorize each learning. For each item, decide:
- Is it a skill update? (workflow step missing, procedure unclear)
- Is it a memory note? (tool quirk, preference, debugging insight)
- Is it both? (general guidance → update skill AND preferences)
- Is it already recorded? (grep before writing – avoid duplicates)
- Is it cross-project or project-specific? (
memories/preferences.md’s “Memory and skill storage” rule: cross-project lessons commit tod-morrison/ai-config; a convention/gotcha tied to one repo we own commits to that repo’s own agent docs instead — see the checklist item below for where. This changes step 4’s target, not just the content.)
Apply updates. For each item:
- Read the target file first (skill or memory) to understand current state
- Grep that file for the item’s specific subject – the tool name, the API call, the error string – before appending anything. Reading the region you’re editing is not enough: a topical memory file runs to hundreds or a thousand-plus lines, so an existing entry on the same subject can sit far away in an unrelated cluster and never enter your view. Grep the whole
memories/directory rather than one file – a fact can plausibly sit in either of two adjacent topical files. When one exists, extend it in place; don’t add a second bullet. (ai-config#689: alist_workflow_runscost bullet went in next to the relatedget_check_runsguidance while an entry on the same tool already sat ~2000 lines below in the write-access cluster – caught by the review bot, not by the author.) - Make the edit — concise bullet points, not prose
- If updating a skill: the change should be specific enough that following the skill next time would avoid the mistake
Commit and push — via a branch + PR, not direct to
main, in whichever repo step 2 routed the item to.Cross-project items (skills, cross-project memory notes): both live in the ai-config repo. Discover its path with
git -C ~/.claude/skills/ums rev-parse --show-toplevel— point-Cat a skill subdir (any one), not the~/.claude/skillsparent.bootstrap.shmay symlink skills per-child into a real~/.claude/skillsdirectory (cloud/web sessions pre-populate it), so the parent itself isn’t a symlink into the repo andgit -Cthere fails with “not a git repository”; a child like…/skills/umsfollows the symlink into the repo. (Both beat the olderdirname "$(readlink …)", which resolves only one symlink hop.) Never leave ANY changes (skills, memories, etc.) as local-only uncommitted edits. Run one of the two paths below — not both:Stage only the files you actually edited — NEVER
git add -A. The working tree often holds unrelated in-flight edits (the user’s own UMS commits, another skill being drafted);git add -Asweeps those into your commit and onto your PR, where they bloat the review and extend the cycle. List the specific paths instead. Thengit statusto confirm only your intended files are staged — if something unexpected is there, the working tree had in-flight work; unstage it rather than bundling it. (Avoidgit add -phere: it needs a terminal and hangs in non-interactive sessions.)Already on the open PR’s branch (e.g. mid-ARDI): commit + push to it.
cd "$(git -C ~/.claude/skills/ums rev-parse --show-toplevel)" git add "skills/<name>/SKILL.md" "memories/<file>.md" # the files you touched git commit -m "ums: <brief summary>" # COMMIT git push origin HEAD # PUSHNo PR yet: branch off main first — a direct-to-main push is denied by auto-mode and bypasses review.
Same-repo case (this checkout’s
originIS the repo you’re targeting):cd "$(git -C ~/.claude/skills/ums rev-parse --show-toplevel)" git fetch origin main && git checkout -b "ums-<topic>" origin/main # FETCH + CREATE_BRANCH git add "skills/<name>/SKILL.md" "memories/<file>.md" # the files you touched git commit -m "ums: <brief summary>" # COMMIT git push -u origin HEAD # PUSH — PR creation is handled by the post-push verification step belowCross-fork case (this checkout’s
originis your own fork, not the upstream repo you’re targeting): don’t branch from a bareorigin/mainhere – the fork’smaincan be stale relative to upstream’s default branch. Fetch the intended upstream repo explicitly (not just look up its default-branch name) and branch from that fetched ref:cd "$(git -C ~/.claude/skills/ums rev-parse --show-toplevel)" base="$(gh repo view "<upstream-owner>/<repo>" --json defaultBranchRef -q .defaultBranchRef.name)" \ && git fetch "https://github.com/<upstream-owner>/<repo>.git" "$base" \ && git checkout -b "ums-<topic>" FETCH_HEAD # chained with && on purpose -- a failed lookup or fetch must stop the # checkout, or it silently reuses an older FETCH_HEAD from a prior fetch, # recreating the stale-base problem this block exists to prevent git add "skills/<name>/SKILL.md" "memories/<file>.md" # the files you touched git commit -m "ums: <brief summary>" # COMMIT git push -u origin HEAD # PUSH -- to your fork; PR creation is handled by the post-push verification step belowCAUTION: if a compound
add && commit && pushis denied, nothing was committed — verify withgit status/git logbefore anygit reset --hard, or you’ll silently discard the still-uncommitted edits.After every push in UMS, verify PR state for the current branch in the intended base repo.
gh pr list --head <owner>:<branch>silently returns empty for an owner-qualified head — it only matches a bare branch name, even when a matching PR genuinely exists (verified directly:gh pr list --head d-morrison:ums-pr635-lessonsreturned[]against a real open PR on that exact branch, whilegh pr list --head ums-pr635-lessonsfound it). Query the REST API instead, whoseheadfilter does honor the owner-qualified form:gh api --method GET "repos/<upstream-owner>/<repo>/pulls" -f "head=<head-owner>:<current-branch>" -f "state=open" --jq '.[] | {number, url, state}'(fordem-extra1/ai-config, that isgh api --method GET "repos/d-morrison/ai-config/pulls" -f "head=dem-extra1:<current-branch>" -f "state=open" ...). If no open PR exists and upstream is accessible, open it as a cross-fork PR: prepare explicit title and body first, show the draft for approval (per the “always show the draft before posting” rule inmemories/preferences.md), then create non-interactively – baregh pr createwithout--fill/--title/--bodyprompts interactively and can hang a headless session:gh repo view "<upstream-owner>/<repo>" --json defaultBranchRef \ -q .defaultBranchRef.name # discover the base -- don't hard-code main gh pr create --repo "<upstream-owner>/<repo>" --base "<discovered-default-branch>" \ --head "<head-owner>:<current-branch>" \ --title "ums: <summary>" --body-file /tmp/ums-pr-body.md \ --reviewer d-morrisonIf upstream is not accessible in-session, push and explicitly hand off that upstream PR creation is still required.
Project-specific items (a convention or gotcha tied to one repo we own): commit to that repo’s own agent docs (
CLAUDE.md,.github/agents/*.md,.github/instructions/*.md,.github/copilot-instructions.md, or checked-in.claude/memories/) via a branch + PR in that repo — not ai-config. Discover its path the same way,cd-ing into that repo’s own checkout instead of the ai-config one, then follow the same branch/commit/push/PR steps above, substituting that repo’s own default branch for everymain/origin mainreference above (don’t hard-codemain– a project routed here may default tomasteror another name; discover it the same way:gh repo view "<owner>/<repo>" --json defaultBranchRef -q .defaultBranchRef.name). If that repo has no agent-doc infrastructure yet, write to its local Claude project memory (~/.claude/projects/<project-path>/memory/) as short-lived staging only – this is not a durable destination; hand off that the project repo still needs agent-doc infrastructure added (via a PR) and the staged memory migrated there. See the checklist item below.Operational checklist (run in order):
Report what was updated. Provide a brief summary table:
What Where Change Poll for new reviews iterate/SKILL.mdAdded explicit polling procedure glab has no –state flag /memories/github.mdNew bullet
What to look for (checklist)
Relationship to record-learnings and staged capture
record-learnings= records individual facts in place, in the moment they ariseums= a reflective, full-context sweep — survey what accumulated, categorize it, and persist it all in one committed pass
Both write to the same destinations. ums fires proactively, as soon as a learning worth saving shows up, rather than waiting to catch up later; the /clear trigger is only a backstop for anything that slipped through.
spot-skill-opportunities is the standing, continuous version of this skill’s “did a workflow emerge that could be a new skill?” checklist item — it runs the recognition judgment call live, in the moment, instead of only at this checkpoint. agent-builder is the sibling construction step for the other checklist item above — a recurring fan-out worker persona rather than a new user-invocable skill.
learn/promote-memory are a staged alternative for the uncertain case: record-learnings and this skill both write directly to committed memory the moment something looks worth remembering, which is right when you’re confident. When you’re not — a candidate whose generality or evidence isn’t solid yet — learn stages it instead, and a promote-memory pass (which a ums run can fold in, or run standalone) reviews staged candidates before they land in committed memory. Neither replaces the direct-write path; they add a review gate for the cases that need one.
Anti-patterns
- ❌ Saying “I’ll remember that” without actually writing it down
- ❌ Updating memories but not pushing skill changes to origin
- ❌ Recording vague lessons (“be more careful”) instead of specific ones (“always poll for new review after pushing — check commit SHA matches”)
- ❌ Skipping the “check existing notes” step and creating duplicates – specifically, reading only the region you’re appending to instead of grepping the whole target file for the subject (step 3)
- ❌ Updating only preferences when a skill also needs the fix
- ❌
git add -A— it sweeps unrelated in-flight edits (the user’s work, other draft skills) into your commit/PR. Stage the specific files you touched. - ❌ Creating
memories/repo/<repo>.mdfor any repo — this pattern is retired. Put repo-specific lore in the repo’s own agent docs (.github/agents/,CLAUDE.md,.github/instructions/,.github/copilot-instructions.md, or checked-in.claude/memories/) via a PR; if the repo has no agent-doc infrastructure yet, this session’s own local project-memory mechanism (Claude Code:~/.claude/projects/<project-path>/memory/— substitute the equivalent for a non-Claude agent) is short-lived staging only — hand off that a PR adding those agent docs is still required. See the checklist item above andmemories/preferences.mdfor the full rule. - ❌ Naming a tool, flag, or API identifier that appears nowhere else in the corpus without anchoring it somewhere checkable. A lone mention reads identically whether it is correct or hallucinated, so a later session has nothing to verify it against — and the guidance is only actionable if the name is right. When the identifier is a cross-model tool, add it to
tool-mappings.yml(then regenerate) rather than leaving the memory bullet as its only home; otherwise cite where you confirmed it. Having used it successfully in the session you’re writing up is good evidence, but that evidence dies with the session. (ai-config#727:mcp__github__list_commitswas flagged in review as unanchored; it was genuinely verified by use, and the fix was registering it as theLIST_COMMITSoperation.) - ❌ Inserting a new bullet into any memory file with nested lists (including
github-actions.md,preferences.md) without checking the surrounding indentation first. These files mix 0-indent top-level bullets with 2-/4-indent sub-bullets and multi-paragraph continuations; a new top-level bullet dropped in the middle of an existing parent’s sub-list re-parents whatever follows it in Markdown (a sibling sub-bullet silently becomes this new bullet’s child). Before committing an insertion, re-read the few lines immediately above and below the insertion point and confirm the indentation still matches what it did before — or place the new bullet after the complete enclosing list instead of inside it. (Caught by@claudereview on ai-config#335: a new 0-indent bullet landed between two sibling sub-bullets of an existing parent, breaking the nesting.)