Skip to content

Text Audit

Use when the user wants a review-style scan of Apple text code for risks such as TextKit fallback, editing lifecycle bugs, deprecated APIs, performance traps, or Writing Tools breakage. Reach for this when the job is findings from real code, not a symptom-first debug answer or direct API lookup.

Workflow Skills

Use when the user wants a review-style scan of Apple text code for risks such as TextKit fallback, editing lifecycle bugs, deprecated APIs, performance traps, or Writing Tools breakage. Reach for this when the job is findings from real code, not a symptom-first debug answer or direct API lookup.

Family: Front Door Skills

Use this skill when the user wants a review-style scan instead of a reference answer.

  • “Audit this editor”
  • “Scan for TextKit issues”
  • “Review this text view code for fallback, performance, or Writing Tools risks”
  • Need concrete findings from code -> stay here
  • Need symptom-first debugging without a code scan -> /skill apple-text-textkit-diag
  • Need API explanation instead of review findings -> launch the relevant domain agent (textkit-reference, editor-reference, rich-text-reference, or platform-reference)

Audit the Apple text system code in $ARGUMENTS.

If no arguments are supplied, audit the current workspace for TextKit, UIKit/AppKit text view, text input, and Writing Tools issues.

When the textkit-auditor agent is available, delegate the scan to it. When the agent is not available — or when a quick manual pass is enough — use the inline checklist below.

Work through these items in order. Each maps to the severity rubric the full auditor uses. Skip items that do not apply to the codebase.

P0 — Critical (broken behavior, crashes, data loss)

Section titled “P0 — Critical (broken behavior, crashes, data loss)”
  1. TextKit 1 fallback triggers. Search for .layoutManager access on UITextView or NSTextView. Any access without checking .textLayoutManager first forces an irreversible fallback to TextKit 1. Also check textContainer.layoutManager.
  2. Missing edited() in NSTextStorage subclasses. Every override of replaceCharacters(in:with:) and setAttributes(_:range:) must call edited(_:range:changeInLength:) with the correct mask and delta. Without it, layout managers never learn about changes.
  3. Character mutation in didProcessEditing. The didProcessEditing delegate is attributes-only. Character changes here corrupt the editing lifecycle and can crash.
  4. Wrong changeInLength values. Compare the delta passed to edited() against the actual string length change. Off-by-one or encoding confusion (Swift count vs NSString length) causes range errors and layout corruption.
  5. Missing beginEditing()/endEditing() around batched mutations. Without batching, each mutation triggers a separate processEditing() pass — multiple layout invalidations that can crash mid-batch if ranges shift.

P1 — Important (correctness, deprecation, performance)

Section titled “P1 — Important (correctness, deprecation, performance)”
  1. Deprecated glyph APIs without TextKit 1 guard. glyph(at:), glyphRange(for:), numberOfGlyphs, drawGlyphs(forGlyphRange:at:) — these are TextKit 1 only. Use them without confirming the editor is on TextKit 1 and the code will crash or silently fail on TextKit 2.
  2. ensureLayout(for: textContainer) on large documents. Forces full-document layout. Use range-scoped or rect-scoped variants instead.
  3. Full-document enumeration with .ensuresLayout. enumerateTextLayoutFragments with .ensuresLayout over the full document range defeats viewport optimization.
  4. Missing allowsNonContiguousLayout for TextKit 1. Large documents need this for acceptable scroll performance.
  5. NSLinguisticTagger usage. Replaced by the NaturalLanguage framework. Deprecated since iOS 14.
  6. Old UIMenuController usage. Replaced by UIEditMenuInteraction in iOS 16.
  7. Direct NSTextStorage edits without performEditingTransaction (TextKit 2). Element tree may not regenerate correctly. Wrap all mutations in performEditingTransaction { }.

P2 — Improvement (compatibility, maintainability)

Section titled “P2 — Improvement (compatibility, maintainability)”
  1. Explicit TextKit 1 creation without justification. Check whether there is a documented reason to stay on TextKit 1. If not, flag for review.
  2. Missing writingToolsIgnoredRangesIn for code or quote content. Code blocks and blockquotes should be excluded from Writing Tools rewrites.
  3. No isWritingToolsActive check before programmatic text changes. Programmatic edits during a Writing Tools session can corrupt the rewrite operation.
  4. String/NSString count confusion in range calculations. String.count counts Characters (grapheme clusters). NSString.length counts UTF-16 code units. Mixing them produces wrong ranges, especially with emoji and complex scripts.
  5. Thread-unsafe text storage access. NSTextStorage must be accessed from the main thread (or the thread it was created on). Background access without coordination is a race condition.
  6. Missing performEditingTransaction wrapper for TextKit 2 edits. Even if the edit “works” today, skipping the transaction is a latent bug.

Return findings ordered by severity with file references and concrete fixes.

## TextKit Audit Results
### P0 — Critical
- [file:line] Description of issue
**Fix:** How to fix
### P1 — Important
- [file:line] Description of issue
**Fix:** How to fix
### P2 — Improvement
- [file:line] Description of issue
**Fix:** How to fix
### Summary
- X files scanned
- Y issues found (Z critical, W important, V improvements)

If no issues are found, say so explicitly and note any residual blind spots (e.g., “no Objective-C files scanned”, “no Writing Tools configuration found”).

  • Use /skill apple-text-textkit-diag for symptom-first troubleshooting.
  • Launch textkit-reference agent for the full fallback trigger catalog or deeper storage/editing lifecycle context.
  • Use /skill apple-text when the prompt is too broad to treat as a code review yet.

This page documents the apple-text-audit workflow skill. Use it when the job is a guided review, implementation flow, or integration pass instead of a single API lookup.

  • apple-text: Use when the user clearly has an Apple text-system problem but the right specialist skill is not obvious yet, or when the request mixes TextKit, text views, storage, layout, parsing, and Writing Tools. Reach for this router when you need the next best Apple-text skill, not when the subsystem is already clear.
  • apple-text-textkit-diag: Use when the user starts with a broken Apple text symptom such as stale layout, fallback, crashes in editing, rendering artifacts, missing Writing Tools, or large-document slowness. Reach for this when debugging misbehavior, not when reviewing code systematically or looking up APIs.
  • apple-text-fallback-triggers: Use when the user needs to know exactly what makes TextKit 2 fall back to TextKit 1, or wants to audit code for fallback risk before it ships. Reach for this when the question is specifically about compatibility-mode triggers, not general text-system debugging.
Full SKILL.md source
SKILL.md
---
name: apple-text-audit
description: Use when the user wants a review-style scan of Apple text code for risks such as TextKit fallback, editing lifecycle bugs, deprecated APIs, performance traps, or Writing Tools breakage. Reach for this when the job is findings from real code, not a symptom-first debug answer or direct API lookup.
license: MIT
metadata:
context: fork
agent: textkit-auditor
argument-hint: "[path-or-focus]"
---
# Text Audit
Use this skill when the user wants a review-style scan instead of a reference answer.
## When to Use
- "Audit this editor"
- "Scan for TextKit issues"
- "Review this text view code for fallback, performance, or Writing Tools risks"
## Quick Decision
- Need concrete findings from code -> stay here
- Need symptom-first debugging without a code scan -> `/skill apple-text-textkit-diag`
- Need API explanation instead of review findings -> launch the relevant domain agent (textkit-reference, editor-reference, rich-text-reference, or platform-reference)
## Core Guidance
Audit the Apple text system code in `$ARGUMENTS`.
If no arguments are supplied, audit the current workspace for TextKit, UIKit/AppKit text view, text input, and Writing Tools issues.
When the `textkit-auditor` agent is available, delegate the scan to it. When the agent is not available — or when a quick manual pass is enough — use the inline checklist below.
## Inline Audit Checklist
Work through these items in order. Each maps to the severity rubric the full auditor uses. Skip items that do not apply to the codebase.
### P0 — Critical (broken behavior, crashes, data loss)
1. **TextKit 1 fallback triggers.** Search for `.layoutManager` access on UITextView or NSTextView. Any access without checking `.textLayoutManager` first forces an irreversible fallback to TextKit 1. Also check `textContainer.layoutManager`.
2. **Missing `edited()` in NSTextStorage subclasses.** Every override of `replaceCharacters(in:with:)` and `setAttributes(_:range:)` must call `edited(_:range:changeInLength:)` with the correct mask and delta. Without it, layout managers never learn about changes.
3. **Character mutation in `didProcessEditing`.** The `didProcessEditing` delegate is attributes-only. Character changes here corrupt the editing lifecycle and can crash.
4. **Wrong `changeInLength` values.** Compare the delta passed to `edited()` against the actual string length change. Off-by-one or encoding confusion (Swift count vs NSString length) causes range errors and layout corruption.
5. **Missing `beginEditing()`/`endEditing()` around batched mutations.** Without batching, each mutation triggers a separate `processEditing()` pass — multiple layout invalidations that can crash mid-batch if ranges shift.
### P1 — Important (correctness, deprecation, performance)
6. **Deprecated glyph APIs without TextKit 1 guard.** `glyph(at:)`, `glyphRange(for:)`, `numberOfGlyphs`, `drawGlyphs(forGlyphRange:at:)` — these are TextKit 1 only. Use them without confirming the editor is on TextKit 1 and the code will crash or silently fail on TextKit 2.
7. **`ensureLayout(for: textContainer)` on large documents.** Forces full-document layout. Use range-scoped or rect-scoped variants instead.
8. **Full-document enumeration with `.ensuresLayout`.** `enumerateTextLayoutFragments` with `.ensuresLayout` over the full document range defeats viewport optimization.
9. **Missing `allowsNonContiguousLayout` for TextKit 1.** Large documents need this for acceptable scroll performance.
10. **`NSLinguisticTagger` usage.** Replaced by the NaturalLanguage framework. Deprecated since iOS 14.
11. **Old `UIMenuController` usage.** Replaced by `UIEditMenuInteraction` in iOS 16.
12. **Direct NSTextStorage edits without `performEditingTransaction` (TextKit 2).** Element tree may not regenerate correctly. Wrap all mutations in `performEditingTransaction { }`.
### P2 — Improvement (compatibility, maintainability)
13. **Explicit TextKit 1 creation without justification.** Check whether there is a documented reason to stay on TextKit 1. If not, flag for review.
14. **Missing `writingToolsIgnoredRangesIn` for code or quote content.** Code blocks and blockquotes should be excluded from Writing Tools rewrites.
15. **No `isWritingToolsActive` check before programmatic text changes.** Programmatic edits during a Writing Tools session can corrupt the rewrite operation.
16. **String/NSString count confusion in range calculations.** `String.count` counts Characters (grapheme clusters). `NSString.length` counts UTF-16 code units. Mixing them produces wrong ranges, especially with emoji and complex scripts.
17. **Thread-unsafe text storage access.** NSTextStorage must be accessed from the main thread (or the thread it was created on). Background access without coordination is a race condition.
18. **Missing `performEditingTransaction` wrapper for TextKit 2 edits.** Even if the edit "works" today, skipping the transaction is a latent bug.
## Reporting Findings
Return findings ordered by severity with file references and concrete fixes.
```
## TextKit Audit Results
### P0 — Critical
- [file:line] Description of issue
**Fix:** How to fix
### P1 — Important
- [file:line] Description of issue
**Fix:** How to fix
### P2 — Improvement
- [file:line] Description of issue
**Fix:** How to fix
### Summary
- X files scanned
- Y issues found (Z critical, W important, V improvements)
```
If no issues are found, say so explicitly and note any residual blind spots (e.g., "no Objective-C files scanned", "no Writing Tools configuration found").
## Related Skills and Agents
- Use `/skill apple-text-textkit-diag` for symptom-first troubleshooting.
- Launch **textkit-reference** agent for the full fallback trigger catalog or deeper storage/editing lifecycle context.
- Use `/skill apple-text` when the prompt is too broad to treat as a code review yet.