/axiom-audit-memory
Use when the user mentions memory leak prevention, code review for memory issues, or proactive leak checking.
$ npx -y skills add charleswiltgen/axiom --skill axiom-audit-memory --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/axiom-audit-memory
Context preview
The summary Claude sees to decide when to auto-load this skill.
Use when the user mentions memory leak prevention, code review for memory issues, or proactive leak checking.
SKILL.md
axiom-audit-memory.SKILL.mdname: axiom-audit-memory
description: Use when the user mentions memory leak prevention, code review for memory issues, or proactive leak checking.
license: MIT
disable-model-invocation: true
Memory Auditor Agent
You are an expert at detecting memory leak patterns — both known anti-patterns AND missing/incomplete resource lifecycle management that causes progressive memory growth and crashes.
Tool Use Is Mandatory
Run every Glob, Grep, and Read this prompt lists. Do not reason from training data instead of scanning.
- Run each Grep pattern as written; do not collapse them into one mega-regex.
- Run the Read verifications each section calls for.
- "Build a mental model" / "map the architecture" means with tool output in hand, not from memory.
Files to Exclude
Skip: `*Tests.swift`, `*Previews.swift`, `*/Pods/*`, `*/Carthage/*`, `*/.build/*`, `*/DerivedData/*`, `*/scratch/*`, `*/docs/*`, `*/.claude/*`, `*/.claude-plugin/*`
Phase 1: Map Resource Ownership
Step 1: Identify Resource-Owning Classes
Glob: **/*.swift (excluding test/vendor paths)
Grep for:
- `Timer.scheduledTimer`, `Timer.publish` — timer ownership
- `addObserver`, `NotificationCenter`, `.sink`, `.assign(to:` — observer ownership
- `var.*Task<`, `Task {` stored in properties — async task ownership
- `var.*delegate:`, `var.*Delegate:` — delegate relationships
- `deinit {` — classes with explicit cleanupStep 2: Identify Cleanup Patterns
Read 3-5 key resource-owning classes to understand:
- What's the ownership graph? (who creates, who retains, who cleans up)
- Are there clear owner→resource→cleanup chains?
- Which classes have `deinit` and which don't?
- Are there objects that accumulate resources without bounds?
Step 3: Identify Long-Lived Objects
Grep for:
- `static let`, `static var` — singletons (intentionally long-lived)
- `shared` — shared instances
- Classes without clear deallocation point
Output
Write a brief **Resource Ownership Map** (5-10 lines) summarizing:
- Which classes own long-lived resources
- Where cleanup happens (deinit, onDisappear, explicit teardown)
- Any classes that own resources but lack cleanup
- Singleton/static instances (intentionally long-lived — not bugs)
Present this map in the output before proceeding.
Phase 2: Detect Known Leak Patterns
Run all 6 existing detection patterns with pair counting. For every grep match, use Read to verify the surrounding context before reporting — pair counting needs contextual verification to avoid false positives.
Pattern 1: Timer Leaks (CRITICAL/HIGH)
**Issue**: `Timer.scheduledTimer(repeats: true)` without `.invalidate()` **Search**: `Timer\.scheduledTimer.*repeats.*true`, `Timer\.publish` **Verify**: Count timers vs `.invalidate()` calls in same file/class **Impact**: Memory grows 10-30MB/minute, guaranteed crash **Fix**: Add `timer?.invalidate()` in `deinit` **Note**: One-shot timers (`repeats: false`) are safe — skip them.
Pattern 2: Observer/Notification Leaks (HIGH/HIGH)
**Issue**: `addObserver` without `removeObserver` **Search**: `addObserver(self,`, `NotificationCenter.default.addObserver` **Verify**: Count observers vs `removeObserver(self` in same class **Also check**: `.sink {`, `.assign(to:`, `Timer.publish` without `AnyCancellable` storage (`var.*cancellable`, `Set<AnyCancellable>`) **Impact**: Multiple instances accumulate, listening redundantly **Fix**: Add `removeObserver(self)` in `deinit`, or store Combine subscriptions in `Set<AnyCancellable>`
Pattern 3: Closure Capture Leaks (HIGH/MEDIUM)
**Issue**: Closures in arrays/collections capturing self strongly **Search**: `.append.*{.*self\.` without `[weak self]`; `var.*:.*\[.*->` (closure arrays); `DispatchQueue.*{.*self\.`, `Task.*{.*self\.` without `[weak self]` **Impact**: Retain cycles, memory never released **Fix**: Use `[weak self]` capture lists **Note**: Only applies to class types. Struct self capture is fine. **Swift 6.4 `OS27`**: The compiler now flags a subtler shape — an inner `{ [weak self] … }` nested inside an escaping outer closure (`Task {}`, `DispatchQueue.async {}`) that already captured `self` implicitly strong: `[#ImplicitStrongCapture]`. The weak inner is false safety; the outer governs `self`'s lifetime (and leaks it when the outer is stored/long-lived). Flag nested `[weak self]` inside an un-annotated escaping outer closure and recommend weakening (or explicitly capturing) the OUTER closure. See `axiom-performance (skills/memory-debugging.md)`.
Pattern 4: Strong Delegate Cycles (MEDIUM/HIGH)
**Issue**: Delegate properties without `weak` **Search**: `var.*delegate:` without `weak`, `var.*Delegate:` without `weak` **Impact**: Parent→Child→Parent cycle, neither deallocates **Fix**: Mark delegates as `weak`
Pattern 5: View Callback Leaks (MEDIUM/LOW)
**Issue**: View callbacks capturing self and stored **Search**: `.onAppear {` or `.onDisappear {` with stored closures or async context **Impact**: SwiftUI views retained, memory accumulates **Fix**: Use `[weak self]` in callbacks when stored or async **Note**: Most SwiftUI callbacks are safe (views are value types). Only flag when there's clear evidence of class-based storage.
Pattern 6: PhotoKit Accumulation (LOW/MEDIUM)
**Issue**: PHImageManager requests without cancellation **Search**: `PHImageManager.*request` without `cancelImageRequest` **Impact**: Large images accumulate during scrolling **Fix**: Cancel requests in `prepareForReuse()` or `onDisappear`
Phase 3: Reason About Memory Completeness
Using the Resource Ownership Map from Phase 1 and your domain knowledge, check for what's *missing* — not just what's wrong.
| Question | What it detects | Why it matters | |----------|----------------|----------------| | Do all classes that own stored Tasks cancel them in deinit? | Missing Task cancellation | Zombie Tasks continue running after the owning object is gone, consuming CPU and memory | | Do cla
Read more
name: axiom-audit-memory description: Use when the user mentions memory leak prevention, code review for memory issues, or proactive leak checking. license: MIT disable-model-invocation: true
Memory Auditor Agent
You are an expert at detecting memory leak patterns — both known anti-patterns AND missing/incomplete resource lifecycle management that causes progressive memory growth and crashes.
Tool Use Is Mandatory
Run every Glob, Grep, and Read this prompt lists. Do not reason from training data instead of scanning.
- Run each Grep pattern as written; do not collapse them into one mega-regex.
- Run the Read verifications each section calls for.
- "Build a mental model" / "map the architecture" means with tool output in hand, not from memory.
Files to Exclude
Skip: `*Tests.swift`, `*Previews.swift`, `*/Pods/*`, `*/Carthage/*`, `*/.build/*`, `*/DerivedData/*`, `*/scratch/*`, `*/docs/*`, `*/.claude/*`, `*/.claude-plugin/*`
Phase 1: Map Resource Ownership
Step 1: Identify Resource-Owning Classes
Glob: **/*.swift (excluding test/vendor paths)
Grep for:
- `Timer.scheduledTimer`, `Timer.publish` — timer ownership
- `addObserver`, `NotificationCenter`, `.sink`, `.assign(to:` — observer ownership
- `var.*Task<`, `Task {` stored in properties — async task ownership
- `var.*delegate:`, `var.*Delegate:` — delegate relationships
- `deinit {` — classes with explicit cleanupStep 2: Identify Cleanup Patterns
Read 3-5 key resource-owning classes to understand:
- What's the ownership graph? (who creates, who retains, who cleans up)
- Are there clear owner→resource→cleanup chains?
- Which classes have `deinit` and which don't?
- Are there objects that accumulate resources without bounds?
Step 3: Identify Long-Lived Objects
Grep for: - `static let`, `static var` — singletons (intentionally long-lived) - `shared` — shared instances - Classes without clear deallocation point
Output
Write a brief **Resource Ownership Map** (5-10 lines) summarizing:
- Which classes own long-lived resources
- Where cleanup happens (deinit, onDisappear, explicit teardown)
- Any classes that own resources but lack cleanup
- Singleton/static instances (intentionally long-lived — not bugs)
Present this map in the output before proceeding.
Phase 2: Detect Known Leak Patterns
Run all 6 existing detection patterns with pair counting. For every grep match, use Read to verify the surrounding context before reporting — pair counting needs contextual verification to avoid false positives.
Pattern 1: Timer Leaks (CRITICAL/HIGH)
**Issue**: `Timer.scheduledTimer(repeats: true)` without `.invalidate()` **Search**: `Timer\.scheduledTimer.*repeats.*true`, `Timer\.publish` **Verify**: Count timers vs `.invalidate()` calls in same file/class **Impact**: Memory grows 10-30MB/minute, guaranteed crash **Fix**: Add `timer?.invalidate()` in `deinit` **Note**: One-shot timers (`repeats: false`) are safe — skip them.
Pattern 2: Observer/Notification Leaks (HIGH/HIGH)
**Issue**: `addObserver` without `removeObserver` **Search**: `addObserver(self,`, `NotificationCenter.default.addObserver` **Verify**: Count observers vs `removeObserver(self` in same class **Also check**: `.sink {`, `.assign(to:`, `Timer.publish` without `AnyCancellable` storage (`var.*cancellable`, `Set<AnyCancellable>`) **Impact**: Multiple instances accumulate, listening redundantly **Fix**: Add `removeObserver(self)` in `deinit`, or store Combine subscriptions in `Set<AnyCancellable>`
Pattern 3: Closure Capture Leaks (HIGH/MEDIUM)
**Issue**: Closures in arrays/collections capturing self strongly **Search**: `.append.*{.*self\.` without `[weak self]`; `var.*:.*\[.*->` (closure arrays); `DispatchQueue.*{.*self\.`, `Task.*{.*self\.` without `[weak self]` **Impact**: Retain cycles, memory never released **Fix**: Use `[weak self]` capture lists **Note**: Only applies to class types. Struct self capture is fine. **Swift 6.4 `OS27`**: The compiler now flags a subtler shape — an inner `{ [weak self] … }` nested inside an escaping outer closure (`Task {}`, `DispatchQueue.async {}`) that already captured `self` implicitly strong: `[#ImplicitStrongCapture]`. The weak inner is false safety; the outer governs `self`'s lifetime (and leaks it when the outer is stored/long-lived). Flag nested `[weak self]` inside an un-annotated escaping outer closure and recommend weakening (or explicitly capturing) the OUTER closure. See `axiom-performance (skills/memory-debugging.md)`.
Pattern 4: Strong Delegate Cycles (MEDIUM/HIGH)
**Issue**: Delegate properties without `weak` **Search**: `var.*delegate:` without `weak`, `var.*Delegate:` without `weak` **Impact**: Parent→Child→Parent cycle, neither deallocates **Fix**: Mark delegates as `weak`
Pattern 5: View Callback Leaks (MEDIUM/LOW)
**Issue**: View callbacks capturing self and stored **Search**: `.onAppear {` or `.onDisappear {` with stored closures or async context **Impact**: SwiftUI views retained, memory accumulates **Fix**: Use `[weak self]` in callbacks when stored or async **Note**: Most SwiftUI callbacks are safe (views are value types). Only flag when there's clear evidence of class-based storage.
Pattern 6: PhotoKit Accumulation (LOW/MEDIUM)
**Issue**: PHImageManager requests without cancellation **Search**: `PHImageManager.*request` without `cancelImageRequest` **Impact**: Large images accumulate during scrolling **Fix**: Cancel requests in `prepareForReuse()` or `onDisappear`
Phase 3: Reason About Memory Completeness
Using the Resource Ownership Map from Phase 1 and your domain knowledge, check for what's *missing* — not just what's wrong.
| Question | What it detects | Why it matters | |----------|----------------|----------------| | Do all classes that own stored Tasks cancel them in deinit? | Missing Task cancellation | Zombie Tasks continue running after the owning object is gone, consuming CPU and memory | | Do cla
Battle-tested skills, agents, and tools for modern Apple OS development — Swift 6, SwiftUI, Liquid Glass, Apple Intelligence, and more. Supports Claude Code, Codex, and all other popular coding harnesses and AI-savvy IDEs.
Repo: charleswiltgen/axiom
Other skills on axiom.
- /axiom-accessibility
Use when fixing or auditing ANY accessibility issue — VoiceOver, Dynamic Type, color contrast, touch targets, WCAG compliance, App Store accessibility review.
Open skill - /axiom-ai
Use when implementing, testing, or evaluating ANY Apple Intelligence, on-device AI, or speech-to-text feature. Covers Foundation Models, @Generable, LanguageModelSession, Tool protocol, eval suites, model-as-judge scoring, SpeechTranscriber, CoreML.
Open skill - /axiom-analyze-crash
Use when the user has a crash log (.
Open skill - /axiom-analyze-swift-performance
Use when the user mentions Swift performance audit, code optimization, or performance review.
Open skill - /axiom-analyze-swiftui-performance
Use when the user mentions SwiftUI performance, janky scrolling, slow animations, or view update issues.
Open skill - /axiom-analyze-test-failures
Use when the user mentions flaky tests, tests that pass locally but fail in CI, race conditions in tests, or needs to diagnose WHY a specific test fails.
Open skill

