Agent skill

Limoni Text Rendering

by thebanri in thebanri/limoni

How Limoni measures and stores text — UAX. An agent skill from thebanri/limoni.

Apache-2.0Auto-check passed

Install Limoni Text Rendering

skills CLI
$ npx skills add thebanri/limoni --skill limoni-text-rendering -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install thebanri/limoni limoni-text-rendering --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/thebanri/limoni.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/limoni-text-rendering .claude/skills/limoni-text-rendering && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
limoni-text-rendering
GitHub stars
152
Token cost
~1.9k tokens
SKILL.md length
923 words
Files
1
Skills in repo
4
Repo updated
First seen
Licence
Apache-2.0

At a glance

How Limoni measures and stores text — UAX. An agent skill from thebanri/limoni.

  • SKILL.md covers Layout of the work, Rules worth remembering, Performance traps (this cost a… and Benchmarking method (use this,…, plus 2 more sections
  • Calls go, git and python3

What it does

Limoni Text Rendering is an agent skill from thebanri/limoni. How Limoni measures and stores text — UAX

Its SKILL.md is about 1.9k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It works with Model Context Protocol. The repository describes itself as: Terminal UI engine for Go that tests can click and AI agents can drive (MCP). Zero-allocation rendering, immediate mode + Elm architecture, 3D, images, charts, accessibility… The licence is Apache-2.0.

Example prompts

  • “/limoni-text-rendering”

Requirements

  • Python 3

What it can do on your machine

Read from SKILL.md and the folder at commit 025c5d5. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • go
    • git
    • python3

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use git, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Limoni Text Rendering loads about 1.9k tokens when it runs. Until then it costs about 16 tokens; SKILL.md has 923 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~16
When it runs · the whole SKILL.md, loaded when a task matches
~1.9k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from thebanri/limoni at commit 025c5d5, republished under its Apache-2.0 licence (© thebanri). 923 words, ~1,896 tokens.

Download SKILL.mdSave it as .claude/skills/limoni-text-rendering/SKILL.md (or your agent's skills folder).
name
limoni-text-rendering
description
How Limoni measures and stores text — UAX

Text: clusters, widths, and the cost of getting them right

A cell holds one rune, but a character can be several code points. Multi-code- point clusters are interned and the cell stores a handle above the Unicode range (cell.RuneClusterBase), so Cell stays 16 bytes and plain text never touches the table.

Layout of the work

PathWhat it owns
core/grapheme/gen.go//go:build ignore generator; reads the UCD, writes tables.go
core/grapheme/tables.gogenerated ranges + property bits (GCB, ExtPict, InCB, emoji, width)
core/grapheme/grapheme.goNext, RuneWidth, StringWidth, Count, GB3–GB999
core/grapheme/mode.goclusters on/off (LIMONI_GRAPHEME=0), mode 2027 sequences
core/cell/clusters.gointerning, NextCluster, ClusterContent, AppendContent
core/buffer/*.goSetStringWithin writes clusters; the diff emits them

Regenerating for a new Unicode version: download the files gen.go lists (GraphemeBreakProperty.txt, emoji-data.txt, DerivedCoreProperties.txt, EastAsianWidth.txt, extracted/DerivedGeneralCategory.txt), run go run gen.go -version <v> -dir <ucd>, and replace testdata/GraphemeBreakTest.txt too.

Rules worth remembering

  • Width of a cluster is the widest code point in it, with VS16 forcing two columns and VS15 one. Zero width comes from general category Mn/Me/Cf — not from GCB Extend, which wrongly zeroes U+FF9E. EastAsianWidth.txt has @missing defaults; ignoring them mismeasures whole unassigned blocks.
  • Correctness is checked against the standard: all 766 cases of GraphemeBreakTest.txt pass. Breaking GB11, GB9c or GB12/13 on purpose fails 3, 16 and 6 cases — use that when changing the state machine.
  • Terminals disagree. Setup asks for mode 2027 (CSI ? 2027 h), which Ghostty, WezTerm, foot and Contour implement. Others advance per code point, so the diff re-anchors the cursor after every cluster: CHA in stream and inline mode, a forgotten cursor position in sparse mode. Without it, one family emoji shifts the rest of the row. core/buffer/cluster_test.go interprets the output the way such a terminal would.
  • REP never repeats a cluster: a terminal may repeat only its last code point.
  • The table is capped at 1 << 20 clusters; past it a cluster degrades to its first code point rather than growing the process without limit.
  • LIMONI_GRAPHEME=0 (or cell.SetGraphemeClusters(false)) restores one code point per cell and stops the mode 2027 request.

Performance traps (this cost a day)

Segmentation is on the hot path; integrating it first cost 20–90% across the draw benchmarks. What recovered it:

  • cell.AppendContent must stay inlinable. Budget is 80; inlining utf8.AppendRune into it pushed the cost to 143 and the diff lost a quarter of its speed. Keep the ASCII byte fast path first and everything else in appendContentSlow. Check with go build -gcflags=-m.
  • ASCII fast paths in Buffer.SetStringWithin, cell.StringWidth and grapheme.Next: printable ASCII followed by another ASCII byte is a one-column cluster, no segmentation needed.
  • ASCII after non-ASCII always breaks (no ASCII code point is Extend, ZWJ, SpacingMark or Extended_Pictographic), so Next returns right after the first rune unless it is Prepend. This is the common shape of UI text.
  • Direct tables beat binary search: bmpProps[0x10000] and pictProps for U+1F000–U+1FFFF, filled from propTable in init, cover nearly everything a UI draws. 136 KB static, emoji width 10.7ns → 4.5ns.

Final measured cost against the previous commit, same machine, -count=3 medians: TextHeavyFrame +5% (three symbols per line), Diff_FullChanges +2%, HundredLayers and Diff_PartialChanges unchanged, zero allocations throughout.

Benchmarking method (use this, not README numbers)

Absolute figures drift with the machine's state. Compare commits on one machine in one sitting:

bash
git worktree add --detach /tmp/base HEAD      # or the commit before the change
(cd /tmp/base && go test ./benchmarks -run '^$' -bench X -count=3)
go test ./benchmarks -run '^$' -bench X -count=3
git worktree remove /tmp/base

Then follow the repo's benchmark honesty rules: publish the delta and say the table's absolute numbers were not re-measured, rather than quietly editing rows.

Show full SKILL.md (370 more words)Show less

Widgets: the tools, and what still walks runes

Widgets measure in columns and cut on cluster boundaries. Use these, never utf8.RuneCountInString as a width or string([]rune(s)[:n]) to cut:

NeedUse
width of a stringcell.StringWidth
longest prefix fitting n columnscell.Truncate(s, n) — a substring, no allocation
draw cut text with "…" / "..."setEllipsized / setClipped (widgets) — prefix and suffix drawn separately, no concatenation
cursor movement / deletion by clusterclusterBounds(text, runeIndex) (widgets)
skip columns when scrolling sidewaysskipColumns (logview.go)

Traps paid for here:

  • Table's old clipToWidth skipped zero-width runes without advancing the byte offset and returned "e\xcc" — invalid UTF-8. Check utf8.ValidString in truncation tests.
  • TextInput put one rune per cell: 日本 drew as blanks (the second rune overwrote the first's continuation cell) and Backspace left "man ZWJ woman ZWJ" behind. TextInputState.Text stays []rune for compatibility; a cached string (str()) is rebuilt only when Text changes, which is what keeps Draw allocation-free.
  • Tests must spell combining characters as escapes. Writing a Go test through a heredoc or an editor turned \u200D and \u0301 into the literal characters, which a normaliser can silently rewrite. Check with python3 -c "print([hex(ord(c)) for c in set(open(f).read()) if ord(c) in (0x301,0x200d)])".
  • Every fix above has a test that fails on the old code: run new tests in a worktree of the previous commit before trusting them.

Markdown measures words by cluster at parse time (StyledSegment.WordWidths) and lays them out cluster by cluster (appendClusters); the palette's match highlighting (drawHighlighted) walks clusters too. FuzzyMatch scores by rune, which is a ranking choice, not a layout one.

Writing a row of cells that includes a wide character's continuation cell through SetCell/SetCellDirect is safe: setContinuation keeps the wide character on its left. Before that, the continuation counted as a narrow cell overwriting the right half and blanked the character — every CJK character and emoji in Markdown drew as spaces. TestWritingContinuationKeepsTheWideCharacter.

The handshake decides whether re-anchoring is needed

driver.ProbeQueries asks DECRQM 2027 and measures: it writes a ZWJ family emoji and reads the cursor back. CapabilityProfile.ClusterWidths (→ DiffOptions.ClusterWidths) is true when mode 2027 is on or the family measured 2 columns; the diff then skips appendClusterResync. Keep the cell.IsCluster(...) && !opts.ClusterWidths order: the other order cost 5% on BenchmarkDiff_FullChanges, because the option load ran for every cell.

© thebanri, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .claude/skills/limoni-text-rendering of thebanri/limoni.

Open the folder on GitHubat commit 025c5d5

Compare with similar skills

Limoni Text Rendering next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Limoni Text Rendering compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Limoni Text Rendering this skillthebanri/limoni152—~1.9kAutomated safety check: PassApache-2.0
MCP Server Builderanthropics/skills180k63 repos~2.3kAutomated safety check: PassApache-2.0
MCP Server BuildershareAI-lab/learn-claude-code78k5 repos~1.2kAutomated safety check: PassMIT
MCP Integration for Pluginsanthropics/claude-plugins-official38k11 repos~3.1kAutomated safety check: PassApache-2.0
Figma use_figma Plugin API Ruleswarpdotdev/warp65k4 repos~4.4kAutomated safety check: PassAGPL-3.0
Stitch to Remotion Walkthrough Videosgoogle-labs-code/stitch-skills8.4k6 repos~3.2kAutomated safety check: NotesApache-2.0

Similar skills

  • MCP Server Builder

    anthropics/skills

    Official

    Guides the design and implementation of Model Context Protocol servers in TypeScript or Python, from tool naming and error messages to evaluation.

    180k GitHub starsUsed in 63 repos~2.3k tokens
    Agent WorkflowsAuto-check passed
  • MCP Server Builder

    shareAI-lab/learn-claude-code

    Walks through building MCP servers in Python or TypeScript that expose tools, resources and prompts to Claude, with templates, registration and testing.

    78k GitHub starsUsed in 5 repos~1.2k tokens
    Agent WorkflowsAuto-check passed
  • MCP Integration for Plugins

    anthropics/claude-plugins-official

    Official

    Explains how to bundle Model Context Protocol servers in a Claude Code plugin, covering config files, stdio, SSE, HTTP and WebSocket server types, and authentication.

    38k GitHub starsUsed in 11 repos~3.1k tokens
    Agent WorkflowsAuto-check passed
  • Required groundwork before any use_figma call: the rules and reference files for running JavaScript in a Figma file through the Plugin API without common failures.

    65k GitHub starsUsed in 4 repos~4.4k tokens
    Frontend & DesignAuto-check passed
  • Stitch to Remotion Walkthrough Videos

    google-labs-code/stitch-skills

    Official

    Builds walkthrough videos from Stitch design projects using Remotion, with transitions, zoom effects and text overlays on each screen.

    8.4k GitHub starsUsed in 6 repos~3.2k tokens
    Media & CreativeAuto-check: notes
  • MCP Development

    coollabsio/coolify

    A skill your agent uses for Laravel MCP development. An agent skill from coollabsio/coolify.

    63k GitHub starsUsed in 1 repo~949 tokens
    Frontend & DesignAuto-check passed

More from thebanri/limoni

  • Limoni Agent Surface

    thebanri/limoni

    How Limoni exposes applications to AI agents and tests — the semantic tree, the automation socket, cmd/limoni-mcp, and the uitest package.

    152 GitHub stars~2.8k tokensUpdated 3 days ago
    Auto-check passed
  • Limoni Performance

    thebanri/limoni

    Where allocations hide in a Limoni frame, how to find them, how to compare benchmarks honestly, and the release and CI checks that catch what one machine cannot.

    152 GitHub stars~1.4k tokensUpdated 3 days ago
    Auto-check passed
  • Limoni Zest

    thebanri/limoni

    zest, the log viewer built on Limoni — how its store, filtering and LogView fit together, how it is verified (in-process, in kitty, over MCP, in the browser), and what it deliberately does not do.

    152 GitHub stars~877 tokensUpdated 3 days ago
    Auto-check passed

Questions about Limoni Text Rendering

What does Limoni Text Rendering do?

How Limoni measures and stores text — UAX. An agent skill from thebanri/limoni. Limoni Text Rendering is an agent skill from thebanri/limoni.

How do I install Limoni Text Rendering in Claude Code?

Run `npx skills add thebanri/limoni --skill limoni-text-rendering -a claude-code`. Or copy the skill folder (.claude/skills/limoni-text-rendering in thebanri/limoni) into .claude/skills/limoni-text-rendering in your project. Claude Code loads it when a task matches its description.

How do I install Limoni Text Rendering in Codex?

Run `npx skills add thebanri/limoni --skill limoni-text-rendering -a codex`. Or copy the skill folder (.claude/skills/limoni-text-rendering in thebanri/limoni) into .agents/skills/limoni-text-rendering in your project. Codex loads it when a task matches its description.

Can I use Limoni Text Rendering in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add thebanri/limoni --skill limoni-text-rendering -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/limoni-text-rendering, .gemini/skills/limoni-text-rendering, .github/skills/limoni-text-rendering and .opencode/skills/limoni-text-rendering in your project.

What does Limoni Text Rendering need to run?

Going by SKILL.md and its folder, Limoni Text Rendering needs the command-line tools its instructions call (go, git and python3). Our summary lists: Python 3.

Does Limoni Text Rendering access the network?

SKILL.md contains no URLs. Its commands use git, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is Limoni Text Rendering safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Limoni Text Rendering use?

Limoni Text Rendering is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Limoni Text Rendering use?

About 1.9k tokens (SKILL.md is roughly 7.6k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Limoni Text Rendering?

Skills that share tags, products or a category with Limoni Text Rendering: MCP Server Builder (anthropics/skills, 180k stars), MCP Server Builder (shareAI-lab/learn-claude-code, 78k stars), MCP Integration for Plugins (anthropics/claude-plugins-official, 38k stars) and Figma use_figma Plugin API Rules (warpdotdev/warp, 65k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Limoni Text Rendering?

thebanri (a GitHub user) maintains it in thebanri/limoni, which has 152 GitHub stars. The repository holds 4 skills in this directory. The repository was last updated on October 5, 2026.

Source: thebanri/limoni on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.