Rules for every string rendered inside the app, plus the sweep that removes in-app prose. Use when writing or changing a label, hint, description, tooltip, empty state or KPI tile in a .tsx file, or when running Pattern Patrol P14 or asked to find or fix long UI text.
Pro scans all 6 files and shows the line behind each finding
Scanned 10/3/2026
npx -y skills add armanisadeghi/ai-matrx --skill interface-text --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Interface Text?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/armanisadeghi-interface-text)More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.
---
name: interface-text
type: Skill
title: "interface-text — in-app text is layout: labels, not prose"
description: "Rules for every string rendered inside the app, plus the sweep that removes in-app prose. Use when writing or changing a label, hint, description, tooltip, empty state or KPI tile in a .tsx file, or when running Pattern Patrol P14 or asked to find or fix long UI text."
tags: [ui, copy, microcopy, patrol, design-system]
timestamp: 2026-09-30T00:00:00Z
---
<!-- SYNCED COPY — do not edit here.
Canonical: common-docs/skills/interface-text/SKILL.md
This file is distributed to every consuming repo by
common-docs/meta/scripts/sync_skills.py. Edit the canonical, run the
sync, and commit each repo. Edits made here are overwritten and lost. -->
# interface-text — in-app text is layout
Doctrine (read once): `common-docs/policies/interface-text-is-layout.md`.
You are writing **interface text**, not prose. Every string the app renders sits in a **slot**
owned by a component, has a **character budget**, and has **siblings** that must match. The
screen is not where you explain, justify, or prove anything — that is what the commit message,
the code comment and `FEATURE.md` are for.
## The card — apply to every string you write or touch
1. **Who is this sentence for?** If it helps someone reading the diff — a formula, a function or
table name, where the number comes from, what changed, what is not built yet, which other
page agrees with it — it is **author-facing**. Put it in a code comment or the commit. It
never renders.
2. **Label first.** Make the label carry the meaning (`Batch savings (7d)`). A number that needs
a paragraph gets a better label; a definition that is still needed gets **one sentence in the
tooltip slot**: `title=` on `KpiTile`, `components/official/InfoHint` everywhere else (hover,
keyboard and touch — a native `title=` attribute on text is unreachable on phones).
3. **Fit the slot.** Secondary text ≤ **60** chars, one line, never two sentences. Tooltip ≤
**140**, one sentence. Placeholder ≤ **60**, an example value. Dialog description / empty /
error state ≤ **140**, at most two sentences: what happened, what to do. No sentence under
a page or section title — ever.
4. **Look at the row and the column.** Your text sets the height of every tile in its row and
the width of every cell in its column. Fill a **visible** slot on **all siblings, at similar
length and in the same shape, or on none**. Tooltips are hidden and per need — never add one
to a sibling just to match.
5. **Use the primitive that enforces the budget.** `components/official/kpi/KpiTile` +
`KpiGrid` for KPI rows (one-line `hint`, `title` tooltip). If the official primitive "cuts
off" your text, your text is too long — shorten it; never hand-roll a component to escape
the limit. A local component that renders unbounded secondary text is itself a finding.
6. **A tooltip states only what you verified in the code or the data contract.** Cannot prove
the definition ("since midnight", "today's budget")? Write no tooltip — a wrong definition
is worse than none.
7. **Honesty is state, not prose.** Unmeasured → `—` with the reason in the tooltip. Partial
feature → the Coming Soon registry. Never "not yet reported by the backend", never "Backfill
brings this up to 100%".
8. **See it rendered, then check it.** In matrx-frontend run
`pnpm check:interface-text --changed` before committing; any other repo:
`node ../matrx-frontend/scripts/interface-text/check-interface-text.mjs --root=. --changed`.
Every `NOVEL` line on your diff is fixed before commit.
## Rationalizations
From the 2026-09-30 baseline runs (`evals.md`) — each one produced a defect.
| Excuse (verbatim) | Reality |
|---|---|
| "the shared tile cuts off long hints" | That is the budget working. Shorten the text; keep the primitive. |
| "swapping only this row would make one page look two ways… should be its own change" | Adopt the primitive for the whole page in this change; it is a few lines. |
| "the rule that every number names its window and item count" | The label `(7d)` names the window; a count fits a 60-char hint. A sentence is not required. |
| "Both are a screen lying." → adds a sentence | Honesty is `—` + tooltip, a badge, or a registry entry. |
| "in the same words the Platform Spend 'Saved by batching' headline uses" | Consistency means the same **label**, not the same paragraph copied to two pages. |
| (with the skill) tooltips added to all six tiles "so the row matches" — two invented "since midnight" / "today's budget" | Parity is for visible slots. An unverified definition is fabrication; leave the tooltip out. |
## Red flags — stop and re-read the card
- You are about to paste words from your commit message, `FEATURE.md` or a code comment into JSX.
- Your string contains a dot-separated or snake_case name, a backtick, "backend", "server", or "not yet".
- One sibling gets a hint and the others do not.
- You are writing a second sentence in a hint or description.
- You are choosing a local component over `components/official/*` because of text length.
- You are writing a tooltip definition you did not read in the code or the data contract.
## The sweep — Discover → Review → Fix → Confirm (Pattern Patrol P14)
Each phase is its own agent. Read **only the file for the phase you were given**:
| Phase | Lane | Read |
|---|---|---|
| Discover — build units for a slice, classify each, propose the exact fix; the validator must pass | `quick` with **sonnet** (haiku mapped rules to verdicts without reading and cut rewrites mid-sentence — 2026-09-30) | `discover.md` |
| Review — accept or correct the classifications, find primitive-level fixes, batch the work, pick what goes to Arman | `standard` (opus) | `review.md` |
| Fix — apply a reviewed batch in its files | `quick` (sonnet) for mechanical batches, `standard` otherwise | `fix.md` |
| Confirm — independent check of a fixed batch | `standard` (opus), never the fixer | `confirm.md` |
The proof record and regression scenario for this skill is `evals.md`; the next editor reruns it.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!