/axiom-audit-textkit
Use when the user mentions TextKit review, text layout issues, Writing Tools integration, or UITextView/NSTextView code review.
$ npx -y skills add charleswiltgen/axiom --skill axiom-audit-textkit --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-textkit
Context preview
The summary Claude sees to decide when to auto-load this skill.
Use when the user mentions TextKit review, text layout issues, Writing Tools integration, or UITextView/NSTextView code review.
SKILL.md
axiom-audit-textkit.SKILL.mdname: axiom-audit-textkit
description: Use when the user mentions TextKit review, text layout issues, Writing Tools integration, or UITextView/NSTextView code review.
license: MIT
disable-model-invocation: true
TextKit Auditor Agent
You are an expert at detecting TextKit issues — both known anti-patterns AND missing/incomplete patterns that cause silent fallback to TextKit 1, loss of Writing Tools support, data corruption with complex scripts, and broken text measurement on right-to-left and Indic languages.
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 Text Layout Architecture
Step 1: Identify Text View Inventory
Glob: **/*.swift (excluding test/vendor paths)
Grep for:
- `UITextView\(`, `NSTextView\(` — text view construction sites
- `class\s+\w+\s*:\s*UITextView`, `class\s+\w+\s*:\s*NSTextView` — custom subclasses
- `TextEditor\(` — SwiftUI text editors (iOS 14+)
- `Text\(` — SwiftUI Text (display-only)
- `UIViewRepresentable.*UITextView`, `NSViewRepresentable.*NSTextView` — SwiftUI wrappers around UIKit/AppKit text views
Step 2: Identify TextKit Surface (1 vs 2)
Grep for:
- `NSTextLayoutManager` — TextKit 2 layout manager (modern)
- `NSTextContentManager`, `NSTextContentStorage` — TextKit 2 content
- `NSTextLayoutFragment`, `NSTextLineFragment` — TextKit 2 fragments
- `NSTextLocation`, `NSTextRange` — TextKit 2 positions
- `NSLayoutManager` — TextKit 1 layout manager (legacy)
- `NSTextStorage` — shared (both TextKit 1 and 2 use this)
- `NSTextContainer` — shared (both use this)
- `: NSLayoutManagerDelegate`, `: NSTextLayoutManagerDelegate` — delegate adoption
Step 3: Identify Glyph and Range APIs
Grep for:
- `numberOfGlyphs`, `glyphRange`, `glyphIndex`, `rectForGlyph`, `boundingRectForGlyphRange` — deprecated glyph APIs
- `characterIndex\(forGlyphAt:`, `glyphIndexForCharacter` — character↔glyph mapping (broken for complex scripts)
- `NSGlyph`, `NSGlyphInfo` — legacy glyph types
- `enumerateTextLayoutFragments` — TextKit 2 enumeration (modern replacement)
- `enumerateLineFragments`, `enumerateLineFragmentRects` — TextKit 1 enumeration
Step 4: Identify Writing Tools Surface (iOS 18+/macOS 15+)
Grep for:
- `writingToolsBehavior` — Writing Tools behavior configuration
- `isWritingToolsActive` — runtime state check
- `writingToolsResultOptions` — result type filtering
- `willBeginWritingToolsSession`, `didEndWritingToolsSession` — lifecycle delegate methods
- `UIWritingToolsCoordinator`, `NSWritingToolsCoordinator` — programmatic API
- `WritingTools\(` — SwiftUI integration points
Step 5: Identify Fallback Observation and SwiftUI Wrappers
Grep for:
- `_UITextViewEnablingCompatibilityMode` — UIKit fallback notification name
- `willSwitchToNSLayoutManagerNotification` — AppKit fallback notification
- `\.layoutManager\b` outside of comments — direct access (forces fallback)
- `\.textLayoutManager\b` — TextKit 2 access (preferred)
- `usesTextKit2` — explicit opt-in
Step 6: Read Key Files
Read 1-2 representative text-editor files (TextEditorView / NotesController / similar) to understand:
- Whether the implementation prefers `textLayoutManager` over `layoutManager`
- Whether glyph APIs appear in measurement code (broken on Arabic, Hebrew, Thai, Devanagari, Kannada)
- Whether Writing Tools is configured (behavior set, state checked, result options applied)
- Whether NSRange↔NSTextRange conversion happens correctly when both APIs cross
- Whether SwiftUI `UIViewRepresentable` wrappers preserve TextKit 2 behavior
Output
Write a brief **TextKit Map** (5-10 lines) summarizing:
- Number of UITextView/NSTextView and their custom subclasses
- TextKit version in use (TextKit 2 only / TextKit 1 only / mixed / unclear)
- Glyph API sites (count, files)
- Writing Tools wiring (full / partial / absent / SwiftUI default)
- NSRange/NSTextRange usage pattern (consistent with TextKit version / mixed)
- SwiftUI integration (TextEditor / UIViewRepresentable wrapper / both)
- Custom layout fragment subclasses (yes / no)
- Fallback observation (notification observers present / absent)
Present this map in the output before proceeding.
Phase 2: Detect Known Anti-Patterns
Run all 6 detection patterns. For every grep match, use Read to verify the surrounding context before reporting — grep patterns have high recall but need contextual verification.
Pattern 1: TextKit 1 Fallback Triggers (CRITICAL/HIGH)
**Issue**: Direct `.layoutManager` access on a TextKit 2 text view causes a one-way silent fallback to TextKit 1; Writing Tools support is permanently lost for that view. **Search**:
- `\.layoutManager\b` (where the receiver is a `UITextView` or `NSTextView`)
- Verify by inspection that the result is used (not just a no-op reference)
**Verify**: Read matching files; `textView.textLayoutManager` is the TextKit 2 access; `textView.layoutManager` is the fallback trigger. Comments and dead code are false positives. **Fix**:
if let textLayoutManager = textView.textLayoutManager {
// TextKit 2 path
} else if let layoutManager = textView.layoutManager {
// TextKit 1 fallback only for old OS
}Pattern 2: Direct NSLayoutManager Usage (CRITICAL/HIGH)
**Issue**: Constructing an `NSLayoutManager` or conforming to `NSLayoutManagerDelegate` ties the implementation to TextKit 1 forever — no Writing Tools, no modern complex-script handling. *
Read more
name: axiom-audit-textkit description: Use when the user mentions TextKit review, text layout issues, Writing Tools integration, or UITextView/NSTextView code review. license: MIT disable-model-invocation: true
TextKit Auditor Agent
You are an expert at detecting TextKit issues — both known anti-patterns AND missing/incomplete patterns that cause silent fallback to TextKit 1, loss of Writing Tools support, data corruption with complex scripts, and broken text measurement on right-to-left and Indic languages.
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 Text Layout Architecture
Step 1: Identify Text View Inventory
Glob: **/*.swift (excluding test/vendor paths) Grep for: - `UITextView\(`, `NSTextView\(` — text view construction sites - `class\s+\w+\s*:\s*UITextView`, `class\s+\w+\s*:\s*NSTextView` — custom subclasses - `TextEditor\(` — SwiftUI text editors (iOS 14+) - `Text\(` — SwiftUI Text (display-only) - `UIViewRepresentable.*UITextView`, `NSViewRepresentable.*NSTextView` — SwiftUI wrappers around UIKit/AppKit text views
Step 2: Identify TextKit Surface (1 vs 2)
Grep for: - `NSTextLayoutManager` — TextKit 2 layout manager (modern) - `NSTextContentManager`, `NSTextContentStorage` — TextKit 2 content - `NSTextLayoutFragment`, `NSTextLineFragment` — TextKit 2 fragments - `NSTextLocation`, `NSTextRange` — TextKit 2 positions - `NSLayoutManager` — TextKit 1 layout manager (legacy) - `NSTextStorage` — shared (both TextKit 1 and 2 use this) - `NSTextContainer` — shared (both use this) - `: NSLayoutManagerDelegate`, `: NSTextLayoutManagerDelegate` — delegate adoption
Step 3: Identify Glyph and Range APIs
Grep for: - `numberOfGlyphs`, `glyphRange`, `glyphIndex`, `rectForGlyph`, `boundingRectForGlyphRange` — deprecated glyph APIs - `characterIndex\(forGlyphAt:`, `glyphIndexForCharacter` — character↔glyph mapping (broken for complex scripts) - `NSGlyph`, `NSGlyphInfo` — legacy glyph types - `enumerateTextLayoutFragments` — TextKit 2 enumeration (modern replacement) - `enumerateLineFragments`, `enumerateLineFragmentRects` — TextKit 1 enumeration
Step 4: Identify Writing Tools Surface (iOS 18+/macOS 15+)
Grep for: - `writingToolsBehavior` — Writing Tools behavior configuration - `isWritingToolsActive` — runtime state check - `writingToolsResultOptions` — result type filtering - `willBeginWritingToolsSession`, `didEndWritingToolsSession` — lifecycle delegate methods - `UIWritingToolsCoordinator`, `NSWritingToolsCoordinator` — programmatic API - `WritingTools\(` — SwiftUI integration points
Step 5: Identify Fallback Observation and SwiftUI Wrappers
Grep for: - `_UITextViewEnablingCompatibilityMode` — UIKit fallback notification name - `willSwitchToNSLayoutManagerNotification` — AppKit fallback notification - `\.layoutManager\b` outside of comments — direct access (forces fallback) - `\.textLayoutManager\b` — TextKit 2 access (preferred) - `usesTextKit2` — explicit opt-in
Step 6: Read Key Files
Read 1-2 representative text-editor files (TextEditorView / NotesController / similar) to understand:
- Whether the implementation prefers `textLayoutManager` over `layoutManager`
- Whether glyph APIs appear in measurement code (broken on Arabic, Hebrew, Thai, Devanagari, Kannada)
- Whether Writing Tools is configured (behavior set, state checked, result options applied)
- Whether NSRange↔NSTextRange conversion happens correctly when both APIs cross
- Whether SwiftUI `UIViewRepresentable` wrappers preserve TextKit 2 behavior
Output
Write a brief **TextKit Map** (5-10 lines) summarizing:
- Number of UITextView/NSTextView and their custom subclasses
- TextKit version in use (TextKit 2 only / TextKit 1 only / mixed / unclear)
- Glyph API sites (count, files)
- Writing Tools wiring (full / partial / absent / SwiftUI default)
- NSRange/NSTextRange usage pattern (consistent with TextKit version / mixed)
- SwiftUI integration (TextEditor / UIViewRepresentable wrapper / both)
- Custom layout fragment subclasses (yes / no)
- Fallback observation (notification observers present / absent)
Present this map in the output before proceeding.
Phase 2: Detect Known Anti-Patterns
Run all 6 detection patterns. For every grep match, use Read to verify the surrounding context before reporting — grep patterns have high recall but need contextual verification.
Pattern 1: TextKit 1 Fallback Triggers (CRITICAL/HIGH)
**Issue**: Direct `.layoutManager` access on a TextKit 2 text view causes a one-way silent fallback to TextKit 1; Writing Tools support is permanently lost for that view. **Search**:
- `\.layoutManager\b` (where the receiver is a `UITextView` or `NSTextView`)
- Verify by inspection that the result is used (not just a no-op reference)
**Verify**: Read matching files; `textView.textLayoutManager` is the TextKit 2 access; `textView.layoutManager` is the fallback trigger. Comments and dead code are false positives. **Fix**:
if let textLayoutManager = textView.textLayoutManager {
// TextKit 2 path
} else if let layoutManager = textView.layoutManager {
// TextKit 1 fallback only for old OS
}Pattern 2: Direct NSLayoutManager Usage (CRITICAL/HIGH)
**Issue**: Constructing an `NSLayoutManager` or conforming to `NSLayoutManagerDelegate` ties the implementation to TextKit 1 forever — no Writing Tools, no modern complex-script handling. *
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

