axiom-audit-textkit
- Repo stars 977
- Forks 74
- License MIT
- Author updated Jun 15, 2026, 03:09 AM
- Author repo Axiom
- Domain
- Engineering
- Compatible agents
-
- Claude Code
- Cursor
- Cline
- Codex
- Windsurf
- Gemini CLI
- +20
- Trust score
- 94 / 100 · audit passed
- Author / version / license
- @CharlesWiltgen · MIT
- Token usage
- Moderate
- Setup complexity
- Guided setup
- External API key
- Not required
- Operating systems
- macOS
- Runtime requirements
- No special requirements
- Permissions
-
- Read-only
- Write / modify
- Network behavior
- Local-only
- Install commands
- 26 variants
Profile is derived at build time from SKILL.md and install vectors. Subject to drift from author intent.
Heads up: 未限定 allowed-tools,默认拥有全部工具权限。
---
name: axiom-audit-textkit
description: Use when the user mentions TextKit review, text layout issues, Writing Tools integration, or UIT…
category: engineering
runtime: no special runtime
---
# axiom-audit-textkit output preview
## PART A: Task fit
- Use case: Use when the user mentions TextKit review, text layout issues, Writing Tools integration, or UITextView/NSTextView code review. 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 tex….
- Inputs: target material, constraints, expected output, and acceptance criteria.
- Evidence boundary: follow “Tool Use Is Mandatory / Files to Exclude / Phase 1: Map Text Layout Architecture” and do not present inference as author intent.
## PART B: Execution result
- **01** The card summarizes the use case; runtime output centers on “Use when the user mentions TextKit review, text layout issues, Writing Tools integration, or UITextView/NSTextView code review. 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 tex…”.
- **02** When the source has headings, the agent prioritizes “Tool Use Is Mandatory / Files to Exclude / Phase 1: Map Text Layout Architecture” so the result follows the author’s structure.
- **03** Typical output includes task judgment, concrete steps, required commands or file edits, validation, and follow-up options.
- **04** Risk context follows the fingerprint: read files, write/modify files; mostly runs locally; usually needs no extra API key.
## Running Rules
- read files, write/modify files; mostly runs locally; usually needs no extra API key.
- Validate with a small sample before expanding scope.
- Return the result, validation criteria, and next iteration options. The source does not require a stable slash command. After installation, invoke the skill by name and describe the task.
Name target files or source material, expected output, forbidden changes, and whether network or shell access is allowed. Permission fingerprint: read files, write/modify files.
Start with a small task and check whether the result follows “Tool Use Is Mandatory / Files to Exclude / Phase 1: Map Text Layout Architecture”. Inspect diffs, logs, previews, or tests before expanding scope.
Confirm the final output includes a concrete result, evidence, and next action. If it stays generic, tighten inputs, boundaries, and acceptance criteria.
---
name: axiom-audit-textkit
description: Use when the user mentions TextKit review, text layout issues, Writing Tools integration, or UIT…
category: engineering
source: CharlesWiltgen/Axiom
---
# axiom-audit-textkit
## When to use
- Use when the user mentions TextKit review, text layout issues, Writing Tools integration, or UITextView/NSTextView cod…
- Use it when the task has clear inputs, repeatable steps, and validation criteria.
## What to provide
- Target material, scope, expected result, and forbidden changes.
- Whether network, commands, file writes, or external services are allowed.
## Execution rules
- Organize steps around “Tool Use Is Mandatory / Files to Exclude / Phase 1: Map Text Layout Architecture” and keep inference separate from source facts.
- read files, write/modify files; mostly runs locally; usually needs no extra API key.
- Validate with a small sample before expanding the task.
## Output requirements
- Return the deliverable, key evidence, validation method, and next action.
- Mark missing information as unknown; do not invent commands, platforms, or dependencies. The author source anchors workflow facts; repository files anchor sources and commands; Fluxly only adds fit, limitations, and quality judgment.
skill "axiom-audit-textkit" {
input -> user goal + target files + boundaries + acceptance criteria
context -> Tool Use Is Mandatory / Files to Exclude / Phase 1: Map Text Layout Architecture
rules -> SKILL.md triggers / order / output contract
runtime -> no special runtime | read files, write/modify files | mostly runs locally
guardrails -> usually needs no extra API key + small-sample validation + diff/log review
output -> copyable result + checklist + next iteration
} 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
textLayoutManageroverlayoutManager - 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
UIViewRepresentablewrappers 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 aUITextVieworNSTextView)- Verify by inspection that the result is used (not just a no-op reference)
Verify: Read matching files;
textView.textLayoutManageris the TextKit 2 access;textView.layoutManageris 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.
Search:
NSLayoutManager\(— direct instantiation:\s*NSLayoutManagerDelegate— delegate conformancevar\s+layoutManager:\s*NSLayoutManager— explicit ownership Verify: Read matching files; flag custom code (not iOS 15 fallback paths gated behind availability checks). Fix: Migrate toNSTextLayoutManagerandNSTextLayoutManagerDelegate. UseNSTextLayoutFragment.enumerate...for measurement and rendering.
Pattern 3: Deprecated Glyph APIs (CRITICAL/HIGH)
Issue: numberOfGlyphs, glyphRange, glyphIndex, rectForGlyph return wrong values for complex scripts. Arabic ligatures, Kannada split vowels, Thai cluster shaping all break a glyph-by-glyph model.
Search:
numberOfGlyphsglyphRangeglyphIndexrectForGlyph,boundingRectForGlyphRangecharacterIndex\(forGlyphAt:glyphIndexForCharacterNSGlyph\b,NSGlyphInfoVerify: Read matching files; flag every site, even if "it works on English text" — the bug surfaces only when an international user types. Fix: UsetextLayoutManager.enumerateTextLayoutFragments(...)and readfragment.textLineFragmentsfor line metrics; for character positions useNSTextLocation.
Pattern 4: NSRange Mixed with TextKit 2 APIs (HIGH/MEDIUM)
Issue: NSTextLayoutManager and NSTextContentManager use NSTextRange and NSTextLocation. Passing NSRange to TextKit 2 APIs is a paradigm error — the conversion may silently truncate or produce wrong ranges.
Search:
textLayoutManager.*NSRangeNSTextLayoutManager.*NSRangeNSTextContentManager.*NSRangeenumerateTextLayoutFragments\(from:.*NSRangeVerify: Read matching files; check whether the call wrapstextContentManager.location(_:offsetBy:)to convert toNSTextLocation. Fix:
guard
let start = textContentManager.location(documentRange.location, offsetBy: nsRange.location),
let end = textContentManager.location(start, offsetBy: nsRange.length),
let textRange = NSTextRange(location: start, end: end)
else { return }
Pattern 5: Missing Writing Tools Configuration (MEDIUM/MEDIUM)
Issue: UITextView/NSTextView instances on iOS 18+/macOS 15+ without writingToolsBehavior set fall back to the panel-only Writing Tools experience instead of the inline experience.
Search:
UITextView\(,NSTextView\(— count instanceswritingToolsBehavior— count configurations- Files containing text views but not the behavior assignment
Verify: Read matching files; flag editing text views (not display-only). The default is
.completeon iOS 18+, but explicit setting documents intent. Fix:textView.writingToolsBehavior = .completefor full inline experience;.limitedfor richer-than-default-but-not-full;.noneto opt out (rare).
Pattern 6: Missing isWritingToolsActive State Check (MEDIUM/MEDIUM)
Issue: Programmatic text mutation (autosave, sync, formatting) during a Writing Tools session corrupts the in-progress generation and may strand the user with a partial result. Search:
\.text\s*=on a UITextView/NSTextView in a sync/autosave/format/transform context\.attributedText\s*=,\.textStorage\.setAttributedStringisWritingToolsActive— count check sites Verify: Read matching files; mutations on a text view that haswritingToolsBehaviorconfigured should guard withisWritingToolsActive. Fix:guard !textView.isWritingToolsActive else { return }before any programmatic text mutation.
Phase 3: Reason About TextKit Completeness
Using the TextKit 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 |
|---|---|---|
Does the codebase observe _UITextViewEnablingCompatibilityMode (UIKit) or willSwitchToNSLayoutManagerNotification (AppKit)? |
Silent TextKit 1 fallback | Without observation, fallback happens invisibly; Writing Tools disappears with no error or log |
For text views that handle Arabic/Hebrew/Thai/Indic input, does measurement use enumerateTextLayoutFragments rather than glyph APIs? |
Glyph-API regression for international users | English text "works" with glyph counts; complex scripts produce off-by-multiple results that look like layout glitches |
Is writingToolsResultOptions set to match the editor's content model (plain / rich / list / table)? |
Wrong-result-type pollution | Users get rich text inserted into a plain-text editor, or formatted lists in a code editor; they delete and retype |
Are programmatic text mutations gated by isWritingToolsActive AND the willBegin/didEndWritingToolsSession lifecycle? |
Mid-session corruption | Autosave/format/sync triggers mid-generation; the partial result + the new mutation race |
For SwiftUI UIViewRepresentable/NSViewRepresentable wrappers around UITextView/NSTextView, are TextKit 2 properties forwarded (textLayoutManager, writingToolsBehavior)? |
Wrapper drops TextKit 2 | The custom wrapper accidentally instantiates TextKit 1 paths, undoing all the TextKit 2 work in the wrapped class |
If the app supports macOS Catalyst or backports to iOS 16, is the TextKit 1 path gated behind if #available(iOS 17, macOS 14, *)? |
Wrong-OS fallback | TextKit 2 is available on iOS 16+/macOS 13+; TextKit 1 fallback should only run on older OS, not as the default |
| Are NSAttributedString attributes (paragraph styles, attachments, custom keys) verified to round-trip through TextKit 2 layout fragments? | Attribute loss across migration | Custom attribute keys silently disappear during TextKit 2 layout; user's formatting flickers or vanishes |
Are large attributed-string assignments (loading a saved document) performed off-main and applied via textStorage.setAttributedString on main? |
Main-thread stalls | A 100KB attributed string can stall the main thread for 100-300ms during typing if applied incorrectly |
| Does the editor disable autosave / undo registration / autocorrection during an active Writing Tools session? | Writing Tools UX corruption | Undo entries from the system rewrite get tangled with user undo; autocorrect steals focus from Writing Tools UI |
For custom NSTextLayoutFragment subclasses, are RTL languages tested (mirrored bounds, baseline metrics, fragment rendering origin)? |
Custom-fragment RTL bug | Custom rendering looks correct in English and breaks subtly on Arabic; QA misses it |
For SwiftUI TextEditor, is iOS 18+ Writing Tools support assumed (TextEditor wires it automatically)? Or is a UIViewRepresentable wrapper short-circuiting that? |
Lost-by-wrapping | Wrapping UITextView to add a feature unintentionally removes Writing Tools; user reports "feature missing" |
Require evidence from the Phase 1 map — don't speculate without reading the code.
Phase 4: Cross-Reference Findings
Bump severity for these combinations:
| Finding A | + Finding B | = Compound | Severity |
|---|---|---|---|
Direct .layoutManager access (Pattern 1) |
iOS 18+ deployment target + UITextView with edit content | Guaranteed Writing Tools loss; users on iOS 18 silently lose a system feature | CRITICAL |
| Glyph APIs (Pattern 3) | Codebase ships in non-English locales | Layout corruption + measurement errors for any user typing Arabic/Hebrew/Thai/Indic | CRITICAL |
| NSLayoutManager subclass (Pattern 2) | Custom rendering / decoration drawing | No migration path to TextKit 2 without ground-up rewrite of the rendering pipeline | HIGH |
Missing writingToolsBehavior (Pattern 5) |
iOS 18+ deployment + edit-rich app (notes, mail, social) | Users see panel-only Writing Tools instead of inline; perceived as "Writing Tools doesn't work here" | HIGH |
| NSRange + TextKit 2 API (Pattern 4) | Document with structured content (multiple text containers, tables) | Range conversion silently truncates at container boundaries; selections jump or break | HIGH |
Missing isWritingToolsActive check (Pattern 6) |
Autosave timer / sync timer / network mutation | Mid-Writing-Tools-generation mutation corrupts the result; user sees partial text + autosave wiping their work | HIGH |
| TextKit 1 fallback trigger | Custom NSAttributedString attribute keys | Attributes silently lost when fallback occurs; user's bold/color/link disappears with no error | HIGH |
| SwiftUI UIViewRepresentable wrapper (Phase 3) | Missing forwarding of writingToolsBehavior/textLayoutManager |
Wrapper undoes TextKit 2 work; the parent app thinks it's modern but the wrapped view is not | HIGH |
| Large attributed-string load (Phase 3) | Main-thread assignment | 100-500ms typing stall on document load; users perceive "lag" without root cause | MEDIUM |
Custom NSTextLayoutFragment (Phase 3) |
RTL/Indic untested | Custom-rendered editor breaks for international users; ships with no test coverage | MEDIUM |
Cross-auditor overlap notes:
- Background
NSAttributedStringconstruction crossing actor boundaries → compound withconcurrency-auditor - Large document loads stalling main thread → compound with
swift-performance-analyzer - Custom text view that breaks VoiceOver navigation → compound with
accessibility-auditor - TextKit 1 fallback losing rotor / Mark Up support → compound with
accessibility-auditor - SwiftUI
UIViewRepresentablewrapper churn re-creating the text view → compound withswiftui-performance-analyzer - Saved-document file location and protection → compound with
storage-auditor
Phase 5: TextKit Modernity Health Score
| Metric | Value |
|---|---|
| Text view count | N UITextView/NSTextView/TextEditor instances |
| TextKit version | TextKit 2 / TextKit 1 / mixed |
| Glyph API sites | M deprecated-glyph-API references |
| Writing Tools coverage | M of N edit views configure writingToolsBehavior (Z%) |
| State-check discipline | M of N programmatic mutations check isWritingToolsActive (Z%) |
| Range type discipline | NSTextRange used with TextKit 2 / mixed with NSRange |
| Fallback observation | notifications observed / absent |
| SwiftUI wrapper hygiene | TextKit 2 properties forwarded / dropped / N/A |
| Health | MODERN / MIXED / LEGACY |
Scoring:
- MODERN: No CRITICAL issues, all text views on TextKit 2 with
textLayoutManager, no glyph APIs, Writing Tools configured on every edit view,isWritingToolsActivechecked at every programmatic mutation, NSRange↔NSTextRange conversion explicit at boundaries, fallback notifications observed. - MIXED: Some TextKit 2 surface but TextKit 1 fallback paths fire silently, partial Writing Tools coverage, glyph APIs in measurement code that "works" for English but breaks on complex scripts, range types mixed without explicit conversion.
- LEGACY: TextKit 1 only or majority TextKit 1 (
NSLayoutManagerdirect usage, glyph APIs throughout, no Writing Tools wiring, no fallback observation). Writing Tools is unavailable to users; international users see broken layout.
Output Format
# TextKit Audit Results
## TextKit Map
[5-10 line summary from Phase 1]
## Summary
- CRITICAL: [N] issues
- HIGH: [N] issues
- MEDIUM: [N] issues
- LOW: [N] issues
- Phase 2 (pattern detection): [N] issues
- Phase 3 (completeness reasoning): [N] issues
- Phase 4 (compound findings): [N] issues
## TextKit Modernity Health Score
[Phase 5 table]
## Issues by Severity
### [SEVERITY/CONFIDENCE] [Pattern Name]: [Description]
**File**: path/to/file.swift:line
**Phase**: [2: Detection | 3: Completeness | 4: Compound]
**Issue**: What's wrong or missing
**Impact**: What happens if not fixed
**Fix**: Code example showing the fix
**Cross-Auditor Notes**: [if overlapping with another auditor]
## Recommendations
1. [Immediate actions — CRITICAL fixes (fallback triggers, glyph APIs in international code, missing Writing Tools on iOS 18+)]
2. [Short-term — HIGH fixes (NSLayoutManager migration, NSRange↔NSTextRange discipline, isWritingToolsActive guards, wrapper forwarding)]
3. [Long-term — completeness gaps from Phase 3 (fallback observation, RTL fragment testing, attribute round-trip verification, async document loading)]
4. [Test plan — Arabic/Hebrew/Thai/Kannada input, Writing Tools on every edit view, fallback notification firing, autosave during Writing Tools session]
Output Limits
If >50 issues in one category: Show top 10, provide total count, list top 3 files. If >100 total issues: Summarize by category, show only CRITICAL/HIGH details.
False Positives (Not Issues)
- TextKit 1 code gated behind
if #available(iOS 16, *) { ... } else { /* TextKit 1 */ }— legitimate fallback layoutManagermentioned only in comments or documentation stringsNSLayoutManagerreferenced in migration code with explicit guards (preserving old behavior on iOS 15)- Glyph APIs in code paths that operate on monospaced ASCII content (rare but valid: terminal emulators, code that explicitly disclaims international support)
- Display-only
Text(...)SwiftUI views (no editing, no Writing Tools concern) UITextField(single-line; uses different layout system; not in scope)NSAttributedStringconstruction in non-text-view contexts (e.g., for Drawing/PDFKit)writingToolsBehaviornot set on text views withisEditable = false(Writing Tools is for edit content)
Related
For TextKit 2 architecture and migration patterns: axiom-uikit (skills/textkit-ref.md)
For accessibility regressions when TextKit 1 fallback fires: accessibility-auditor agent
For background attributed-string construction crossing actors: concurrency-auditor agent
For main-thread stalls when loading large documents: swift-performance-analyzer agent
For SwiftUI wrappers re-creating text views on every render: swiftui-performance-analyzer agent
For saved-document file location and protection: storage-auditor agent
Decide Fit First
Design Intent
How To Use It
Boundaries And Review