NOASSERTIONupdated 1mo ago
Let be the absolute plugin directory two levels above this SKILL.md. Resolve that path before running commands or opening shared references. When these instructions say swiftui-ctx, invoke /scripts/swiftui-ctx; do not assume the command is on PATH.
What can you do with Audit Swiftui Layout And Tables?
name: audit-swiftui-layout-and-tables description: Audit macOS SwiftUI layout and tables for correctness, current APIs, and production conventions. Use for that domain or as part of a full audit.
Bundled resource root
Let <swiftui-plugin-root> be the absolute plugin directory two levels above this SKILL.md. Resolve that path before running commands or opening shared references. When these instructions say swiftui-ctx, invoke <swiftui-plugin-root>/scripts/swiftui-ctx; do not assume the command is on PATH.
Audit SwiftUI Layout & Tables
AUDIT-ONLY Β· macOS-only Β· SwiftUI-only. Run this on a finished or in-progress macOS SwiftUI
project to detect β and where certain, fix β every way an iOS-shaped layout breaks on a Mac: a
resizable window with no min/ideal/max content frame, no scene sizing, a hand-rolled List where
macOS wants a sortable Table, a Table with no sortOrder, default controlSize in a dense pane, a
blanket .fixedSize() that overflows the window, a deprecated .tableStyle case, and a custom Layout
where a built-in would do. Findings are written to disk in the toolkit's unified schema; certain
mechanical defects are fixed under the fix-safety protocol. This is never a from-scratch layout generator.
The training corpus is overwhelmingly iOS β one fixed canvas, no resizable window. So AI has no
mental model that a Mac window has min/ideal/max dimensions the developer must declare, treats List as
the universal container, and leaves controlSize untouched. The result compiles and "works"; it just
looks and behaves like an iPad app dropped into a window. Be suspicious wherever AI sized a window or
modeled a data grid.
Boundary / seam note (stay in lane)
Seam verdicts are the reconciled truth in <swiftui-plugin-root>/references/_shared/cross-ref-graph.md
β apply them in the tells and emit cross_ref on a shared-seam finding; do not double-own.
- Window sizing is a deliberate two-layer split. The content
.frame(min/ideal/max)layer is this skill (lt-01). The scene modifiers.defaultSize/.windowResizabilityare owned byaudit-swiftui-scenes-windows; lt-02 here is a companion note β flag the obvious absence, emitcross_ref: scenes-windows, and defer scene-modifier depth there. - Control density. The
controlSizesizing axis is this skill (lt-05). Style variants (.buttonStyle/.pickerStyle/.formStyle(.grouped)) belong toaudit-swiftui-controls-forms; it ownscontrolSizeonly inside aTable/inspector seam βcross_refthere when style is the issue. NavigationSplitViewcolumns / sidebar sizing belong toaudit-swiftui-navigation-toolbars.- Large-
Table/ large-Listrender cost (β³5,000 rows, heavy cells, theNSTableViewbridge decision) belongs toaudit-swiftui-view-performance; note the ceiling in one line andcross_ref. - A
GeometryReaderfeeding aCanvas(drawing geometry) belongs toaudit-swiftui-drawing-canvas; this skill ownsGeometryReader/Layoutonly when it is doing layout arrangement.
The five layout rules (the judgment core)
- Resizable windows are the whole point. Declare
min/ideal/max.frameon the root content view; iOS never makes you, the Mac always does (lt-01). - Structured Mac data is a
Table, not aList. Multi-field rows want real columns, clickable headers, multi-column sort, and free row selection β a hand-rolledHStack-in-Listhas none of it (lt-03). - A Mac
Tableis sortable. Drive it withsortOrder: $bindingto[KeyPathComparator]; columns built withvalue:become clickable/sortable automatically (lt-04). - Tune density per pane. Pointer-driven dense panes (inspectors, toolbars, settings grids) routinely
use
.controlSize(.small)/.mini; the iOS default reads as oversized (lt-05). - Reach for the targeted tool before the blunt one.
layoutPriority/ single-axisfixedSize(horizontal:vertical:)/containerRelativeFramebefore a blanket.fixedSize()(lt-06) or a customLayout(lt-08).
Full βββ
+ the canonical resizable-window-with-sortable-Table exemplar:
references/layout-window-sizing.md and references/tables-and-density.md.
Defect index (lt-01 β¦ lt-08)
id Β· tell Β· severity Β· fix Β· open reference. Severities: hard-fail (deprecated / never-correct),
warning (compiles but non-native), advisory (judgment / density). auto = mechanical
single-answer fix; flag = show the β
, dev applies.
| id | One-line tell | Sev | Fix | Reference |
|---|---|---|---|---|
| lt-01 | scene root content with no .frame(minWidth:idealWidth:β¦) β window opens awkward / collapses on drag |
warning | flag | layout-window-sizing.md |
| lt-02 | scene (WindowGroup/Window/Settings) with no .defaultSize / .windowResizability |
warning | flag | layout-window-sizing.md |
| lt-03 | List( wrapping HStack { Text β¦ Spacer() Text β¦ } of a struct's fields β wants Table + TableColumn |
warning | flag | tables-and-density.md |
| lt-04 | Table( with no sortOrder: binding / no KeyPathComparator β non-sortable on a click-to-sort platform |
warning | flag | tables-and-density.md |
| lt-05 | dense Mac pane (inspector/settings/toolbar) with no .controlSize(.small/.mini) β oversized density |
advisory | flag | tables-and-density.md |
| lt-06 | blanket both-axis .fixedSize() on a container β freezes both axes, overflows a resizable window |
advisory | flag | layout-window-sizing.md |
| lt-07 | .tableStyle(.inset(alternatesRowBackgrounds:)) / .bordered(alternatesRowBackgrounds:) β DEPRECATED (macOS 26.5) |
hard-fail | flag | tables-and-density.md |
| lt-08 | custom : Layout conformance where a built-in (Grid/ViewThatFits/containerRelativeFrame) fits |
advisory | flag | custom-layout.md |
lt-07 is the only deprecation; lt-02 and lt-05 cross-ref siblings. The macOS 26.5 case-level
deprecation of tableStyle(.inset(alternatesRowBackgrounds:)) is confirmed on developer.apple.com
(swiftui-ctx tracks deprecation at the API level, not the case level β see VERIFY;
primary source: https://developer.apple.com/documentation/swiftui/tablestyle/inset(alternatesrowbackgrounds:)).
The real API, at a glance
Real (exist on macOS, floors are the reconciled truth in floors-master.md β read, never restate):
frame(minWidth:idealWidth:maxWidth:minHeight:idealHeight:maxHeight:alignment:), Table / TableColumn,
KeyPathComparator (Foundation), TableColumnForEach, controlSize(_:) (.large/.regular/.small/
.mini), fixedSize() / fixedSize(horizontal:vertical:), layoutPriority(_:),
containerRelativeFrame(_:alignment:), alternatingRowBackgrounds(_:), the Layout protocol,
Grid/GridRow, ViewThatFits. The scene modifiers defaultSize(_:) / windowResizability(_:)
exist but are owned by scenes-windows (lt-02 companion).
Deprecated: tableStyle(.inset(alternatesRowBackgrounds:)) and the .bordered variant β macOS 26.5,
β .tableStyle(.inset).alternatingRowBackgrounds() (lt-07).
No invented names are central to this domain; if audited code reaches for a layout symbol you can't place
(e.g. a made-up Table modifier), confirm via swiftui-ctx (lookup exit 3 = likely hallucination) +
Sosumi before flagging, and cross-check the canonical invented-name list in
<swiftui-plugin-root>/references/_shared/hallucination-blacklist.md. Signatures + full βββ
:
references/layout-window-sizing.md, references/tables-and-density.md, references/custom-layout.md.
The 8-step audit workflow (execute verbatim)
- ORIENT.
tree/findthe SwiftUI sources. Read the deployment target (project.pbxprojMACOSX_DEPLOYMENT_TARGET, orPackage.swiftplatforms:) β it sets which floor a fix may rely on (e.g.TableColumnForEachis macOS 14.4+,containerRelativeFrame14.0+,alternatingRowBackgrounds14.0+). Note whether the app declares anyApp/Scene(window sizing is moot for a library target). Record it. - LOCATE. Run the shared hybrid lint runner:
bash <swiftui-plugin-root>/scripts/swiftui-lint.sh --skill audit-swiftui-layout-and-tables --dir <sources> --json /tmp/lt.json --sarif /tmp/lt.sarif. It runs this skill's tier-1 grep tells (lint/grep-tells.tsv, lt-01β¦lt-08) + tier-2 structural ast-grep rules (lint/ast-grep/*.ymlβ lt-01 frame-absence, lt-04 Table-without-sortOrder), plus a per-file parse probe, and emits unified JSON + SARIF. Read itsparse_warningsβ a flagged file did not fully parse, so a structural miss can't masquerade as clean; READ those by hand. The runner only LOCATES β never treat a hit as a finding. Engine + rule-file format + degradation:<swiftui-plugin-root>/references/_shared/lint-architecture.md. - READ. Open every located file in full β never pattern-match-and-patch blind. The placement of
a
.frame(root content vs nested subview), whether aList's rows are a struct's fields, whether a.fixedSize()sits on a container vs a singleText, and whether a pane is genuinely dense are all invisible to grep. Build a per-file inventory: each scene + its content-frame + its scene modifiers; eachList/Table+ its column wiring + its sort wiring; each dense pane + itscontrolSize. - DETECT. Apply the index. Assign each candidate a confidence; report a finding only at 100%
certainty (e.g. a
Tablewhose call span carries nosortOrder, a container.fixedSize(), the deprecatedtableStylecase). A lone glanceable signal (a tiny staticTable, aListof plain strings) is not a defect β judge it. - VERIFY. For anything β€ ~70% confidence (a symbol you can't place, a floor you're unsure of, a
deprecation you want to confirm, the canonical shape), run both evidence sources. (a) Practice
β
bash <swiftui-plugin-root>/scripts/swiftui-ctx lookup <api> --json(andswiftui-ctx deprecated <api>for a currency/deprecation rule): read itsconsensus(the canonical shape),deprecated+replacement,recommendedpermalink,introduced_macos, andco_occurs_with; alookupexit 3 (not-found, with a did-you-meansuggestion) corroborates a hallucination β no shipping Mac app uses the symbol. (b) Spec β confirm via Sosumi:curl -sSL https://sosumi.ai/<apple-path>usingreferences/source-directory.mdfor the path and<swiftui-plugin-root>/references/_shared/sosumi-reference.mdfor the protocol (neverWebFetchdeveloper.apple.com). Cross-checkintroduced_macosagainstfloors-master.mdand the Sosumidoc:floor. The CLI contract is<swiftui-plugin-root>/references/_shared/swiftui-ctx-reference.md. lt-07's case-level deprecation is confirmed ondeveloper.apple.com(deprecated tableStylereturnsdeprecated:falseat the modifier level in swiftui-ctx, but bothinset(alternatesRowBackgrounds:)andbordered(alternatesRowBackgrounds:)showmacOS 12.0β26.5 Deprecateddirectly) β citesource: https://developer.apple.com/documentation/swiftui/tablestyle/inset(alternatesrowbackgrounds:). Deeper corpus evidence (lt-08 customLayout): before flagging a: Layoutconformer as needless,bash <swiftui-plugin-root>/scripts/swiftui-ctx conformances Layoutfor real conformers + permalinks (andexamples Table --shapefor realTablecall sites) β 198 shipping repos write a customLayout, almost allFlowLayout(e.g. AerialScreensaver/Aerial), the one shape no built-in covers; cite that permalink to distinguish a legit wrap-flowLayoutfrom one aGrid/ViewThatFitswould replace. - REPORT. Write each confirmed finding (output contract below). One finding per file, zero-padded,
ordered. Write the run's
_index.md. - FIX. Apply corrections under the fix-safety protocol
(
<swiftui-plugin-root>/references/_shared/fix-safety-protocol.md): clean-tree gate, findings-first, onlyfix_mode: auto(lt-07 β the deprecatedtableStylecase is a mechanical single-answer swap), one conventional commit per finding citing itsrule_id, never weaken a check. The β "Correct" is not a hand-written snippet β it is the swiftui-ctx consensus shape put in## Correct, backed by a real macOS-26 example fetched withbash <swiftui-plugin-root>/scripts/swiftui-ctx file <recommended.id> --smartwhose GitHub permalink (plus the Sosumidoc:) goes in## Sourceas the canonical example. The lt-04 β is grounded in the liveswiftui-ctx lookup Tableconsensus + its recommended macOS-26 permalink (seereferences/tables-and-density.md). Leaveflag-onlyfindingsopenwith that β in## Correct. - DOUBLE-CHECK. Re-grep / re-run the lint over each fixed file to confirm the tell no longer matches;
record the evidence in
## Fix applied?. Re-confirm every citation still resolves. If a fix introduced a new tell (e.g. aTableyou made sortable now needs an.onChange(of: sortOrder)), loop that file back to DETECT.
Confidence gating (load-bearing)
Report a finding only at 100% certainty. Anything β€ ~70% goes to VERIFY (step 5) before it can
become a finding β never emit a speculative finding. Auto-fix only lt-07 (the deprecated tableStyle
case β .inset + .alternatingRowBackgrounds()); everything else is fix_mode: flag-only because the
correct fix is a structural/judgment call (which view keeps space, whether a table should sort, what
density a pane wants).
Output contract
Inherits the toolkit's unified contract (full schema + body sections + frontmatter keys:
<swiftui-plugin-root>/references/_shared/finding-schema.md β do not restate it). Specialized for this
domain:
- Findings:
swiftui-audits/layout-and-tables/<context>/NN-slug.md(one finding per file, zero-padded, ordered). Per-run index:swiftui-audits/layout-and-tables/_index.md. domain: layout-and-tables. Frontmatter is the canonical schema;fix_modeisautofor lt-07, elseflag-only.availabilityreads fromfloors-master.md.sourceis an Apple URL + access date (fetched via Sosumi); lt-07's case-level deprecation is confirmed athttps://developer.apple.com/documentation/swiftui/tablestyle/inset(alternatesrowbackgrounds:). Emitcross_refon lt-02 (βscenes-windows), lt-05 (βcontrols-forms, when style not sizing), and any large-Table perf note (βview-performance).
Starter <context> folders (file here whenβ¦):
<context> |
File a finding here when⦠|
|---|---|
window-sizing/ |
the root content lacks a min/ideal frame, or the scene lacks .defaultSize/.windowResizability (lt-01, lt-02) |
list-vs-table/ |
structured multi-field rows are a hand-rolled List that macOS wants as a Table (lt-03) |
table-sorting/ |
a Table has no sortOrder/KeyPathComparator, or the deprecated tableStyle case (lt-04, lt-07) |
control-density/ |
a dense Mac pane runs default controlSize where .small/.mini is wanted (lt-05) β cross_ref controls-forms |
sizing-fixedsize/ |
a blanket both-axis .fixedSize() on a container overflows the window (lt-06) |
custom-layout/ |
a custom Layout conformance where a built-in container fits (lt-08) |
New-folder rule: if a finding does not fit any existing context folder, create a new one under
swiftui-audits/layout-and-tables/ with a lowercase-hyphen slug naming the sub-category, and note it in
the run's _index.md. Prefer an existing folder when the fit is reasonable; consistency across runs is a
hard requirement. Two runs over the same code produce structurally identical trees.
Reference routing
| File | Open when |
|---|---|
references/layout-window-sizing.md |
window content-frame, scene-sizing companion note, and the fixedSize/layoutPriority confusion (lt-01/02/06) + the canonical resizable-window exemplar |
references/tables-and-density.md |
List-vs-Table, the sort wiring, controlSize density, and the deprecated tableStyle case (lt-03/04/05/07) |
references/custom-layout.md |
a custom Layout conformance vs a built-in container, and the GeometryReader-vs-Layout seam (lt-08) |
references/source-directory.md |
step VERIFY β the Apple/WWDC/practitioner source map fetched via Sosumi |
lint/grep-tells.tsv + lint/ast-grep/*.yml |
step LOCATE β this skill's declarative lint rule set fed to the shared runner (tier-1 grep tells lt-01β¦lt-08 + tier-2 structural lt-01 frame-absence / lt-04 Table-without-sortOrder); edit here to tune detection |
Shared toolkit references (point in, never restate):
| Shared file | For |
|---|---|
<swiftui-plugin-root>/references/_shared/floors-master.md |
every floor/availability/deprecation value (the reconciled truth β Table 12.0, controlSize 10.15, TableColumnForEach 14.4, the tableStyle 26.5 deprecation) |
<swiftui-plugin-root>/references/_shared/hallucination-blacklist.md |
the canonical invented-name list (cross-check a made-up layout/Table symbol) |
<swiftui-plugin-root>/references/_shared/macos-arm-gating.md |
the macOS-arm gating rule (a fix that uses a 14.x floor under a lower target needs a gate) |
<swiftui-plugin-root>/references/_shared/finding-schema.md |
the unified finding schema + frontmatter keys + context-folder ownership |
<swiftui-plugin-root>/references/_shared/fix-safety-protocol.md |
the 8-point fix-safety protocol (step 7) |
<swiftui-plugin-root>/references/_shared/sosumi-reference.md |
the Apple-doc spec fetch protocol (step 5 VERIFY) |
<swiftui-plugin-root>/references/_shared/swiftui-ctx-reference.md |
the practice-corpus CLI contract β lookup/deprecated/file --smart for the consensus shape + permalinked example (steps 5 VERIFY Β· 7 FIX) |
<swiftui-plugin-root>/references/_shared/cross-ref-graph.md |
seam ownership + cross_ref targets (window-sizing split, controlSize axis, large-Table perf) |
Detection accelerator
bash <swiftui-plugin-root>/scripts/swiftui-lint.sh --skill audit-swiftui-layout-and-tables --dir <files-or-dir> [--json out.json] [--sarif out.sarif] β the toolkit's one shared hybrid lint engine, fed this
skill's declarative rules: tier-1 grep tells (lint/grep-tells.tsv, lt-01β¦lt-08) + tier-2
ast-grep structural rules (lint/ast-grep/*.yml β lt-01 scene-content-no-frame, lt-04
table-without-sortOrder) that grep cannot express (the absence of a .frame across a closure, the
absence of sortOrder inside a Table call span β both anchored on a kind: call_expression). It
runs a per-file parse probe (surfaces "did not fully parse" so a structural miss can't look clean),
emits unified JSON + SARIF, exits 2 on any hard-fail (lt-07) for a CI gate, and degrades to
grep-only with a notice if ast-grep is unreachable (npx --package @ast-grep/cli ast-grep; faster:
brew install ast-grep). It only LOCATES β always READ each hit in full before reporting (step 3). The
thin scripts/lt-lint.sh is a pointer to this runner. Engine + rule-file format + JSON/SARIF shape +
safety rails: <swiftui-plugin-root>/references/_shared/lint-architecture.md.
Install
Add Audit Swiftui Layout And Tables to your client. Pick the one you use.
npx skills add yigitkonur/plugin-swiftuiInstalls every skill in the repository, then prompts for which to keep.
/plugin marketplace add yigitkonur/plugin-swiftuiAdds the repository as a plugin marketplace; install individual plugins with `/plugin install`.
git clone https://github.com/yigitkonur/plugin-swiftui
cp -r plugins/swiftui/skills/audit-swiftui-layout-and-tables ~/.claude/skills/A skill is a plain directory. Copy it into `.claude/skills/` in a project or in your home directory.
Score
64 / 100
Good