5.2k★by peetzweg
trmnl – OpenClaw Skill
trmnl is an OpenClaw Skills integration for coding workflows. Generate content for TRMNL e-ink display devices using the TRMNL CSS framework. Use when the user wants to display information on their TRMNL device, send messages to an e-ink display, create dashboard content, show notifications, or update their terminal display. Supports rich layouts with the TRMNL framework (flexbox, grid, tables, progress bars, typography utilities) and sends content via webhook API.
Skill Snapshot
| name | trmnl |
| description | Generate content for TRMNL e-ink display devices using the TRMNL CSS framework. Use when the user wants to display information on their TRMNL device, send messages to an e-ink display, create dashboard content, show notifications, or update their terminal display. Supports rich layouts with the TRMNL framework (flexbox, grid, tables, progress bars, typography utilities) and sends content via webhook API. OpenClaw Skills integration. |
| owner | peetzweg |
| repository | peetzweg/trmnl |
| language | Markdown |
| license | MIT |
| topics | |
| security | L1 |
| install | openclaw add @peetzweg/trmnl |
| last updated | Feb 7, 2026 |
Maintainer

name: trmnl description: Generate content for TRMNL e-ink display devices using the TRMNL CSS framework. Use when the user wants to display information on their TRMNL device, send messages to an e-ink display, create dashboard content, show notifications, or update their terminal display. Supports rich layouts with the TRMNL framework (flexbox, grid, tables, progress bars, typography utilities) and sends content via webhook API.
TRMNL Content Generator
Generate HTML content for TRMNL e-ink display devices.
Quick Start Workflow
- Check for
$TRMNL_WEBHOOKenvironment variable - If missing, prompt user for webhook URL
- Ask user to verify TRMNL display markup is set to:
<div>{{content}}</div> - Confirm device type (default: TRMNL OG, 2-bit, 800x480)
- Read relevant reference docs based on content needs
- Generate HTML using TRMNL framework classes
- Send via POST to webhook (use temp file method)
- Send minimal confirmation only - Do NOT echo content back to chat
Device & Setup
Default target: TRMNL OG (7.5" e-ink, 800x480px, 2-bit)
Display markup required:
<div>{{content}}</div>
Webhook:
export TRMNL_WEBHOOK="https://trmnl.com/api/custom_plugins/{uuid}"
Sending content (temp file method):
cat > /tmp/trmnl.json << 'EOF'
{"merge_variables":{"content":"<div class=\"layout\">HTML</div>"}}
EOF
curl "$TRMNL_WEBHOOK" -H "Content-Type: application/json" -d @/tmp/trmnl.json -X POST
Webhook Limits
| Tier | Payload Size | Rate Limit |
|---|---|---|
| Free | 2 KB (2,048 bytes) | 12 requests/hour |
| TRMNL+ | 5 KB (5,120 bytes) | 30 requests/hour |
Check payload size before sending:
python3 scripts/check_payload.py /tmp/trmnl.json
Tips to reduce payload size:
- Minify HTML (remove unnecessary whitespace)
- Use framework classes instead of inline styles
- Use short class names the framework provides
- Remove comments from HTML
- Use
deep_mergestrategy for incremental updates
Reference Documentation
Read these files as needed:
| File | When to Read |
|---|---|
references/patterns.md | Start here - Common plugin patterns from official examples |
references/framework-overview.md | Device specs, e-ink constraints, responsive prefixes |
references/css-utilities.md | Colors, typography, sizing, spacing utilities |
references/layout-systems.md | Flexbox, grid, overflow/clamp engines |
references/components.md | Title bar, dividers, items, tables, charts |
references/webhook-api.md | Payload format, rate limits, troubleshooting |
assets/anti-patterns.md | Common mistakes to avoid |
assets/good-examples/ | HTML reference implementations |
Scripts:
| Script | Purpose |
|---|---|
scripts/check_payload.py | Verify payload size before sending (run on /tmp/trmnl.json) |
Standard Plugin Structure
Every plugin follows this pattern:
<div class="layout layout--col gap--space-between">
<!-- Content sections separated by dividers -->
</div>
<div class="title_bar">
<img class="image" src="icon.svg">
<span class="title">Plugin Name</span>
<span class="instance">Context</span>
</div>
layout+layout--col= vertical flex containergap--space-between= push sections to edgestitle_bar= always at bottom, outside layoutdivider= separate major sections- CRITICAL: Only ONE
.layoutelement per view (no nesting)
Grid System (10-Column)
Column spans should sum to 10:
<div class="grid">
<div class="col--span-3">30%</div>
<div class="col--span-7">70%</div>
</div>
Simple equal columns: grid--cols-2, grid--cols-3, etc.
Item Component
Standard data display pattern:
<div class="item">
<div class="meta"><span class="index">1</span></div>
<div class="content">
<span class="value value--xlarge value--tnums">$159,022</span>
<span class="label">Total Sales</span>
</div>
</div>
Value Typography
Always use value--tnums for numbers.
| Class | Usage |
|---|---|
value--xxxlarge | Hero KPIs |
value--xxlarge | Large prices |
value--xlarge | Secondary metrics |
value--small | Tertiary data |
value--tnums | Always for numbers |
Auto-fit: <span class="value" data-fit-value="true">...</span>
Columns (for Lists)
<div class="columns">
<div class="column" data-overflow="true" data-overflow-counter="true">
<span class="label label--medium group-header">Section</span>
<div class="item">...</div>
</div>
</div>
Grayscale Dithering
Use dithered classes, not inline gray colors:
bg--black,bg--gray-60,bg--gray-30,bg--gray-10,bg--whitetext--black,text--gray-50
Data Attributes
| Attribute | Purpose |
|---|---|
data-fit-value="true" | Auto-resize text to fit |
data-value-format="true" | Auto-format numbers (locale-aware) |
data-clamp="N" | Limit to N lines |
data-overflow="true" | Enable overflow management |
data-overflow-counter="true" | Show "and X more" |
data-overflow-max-cols="N" | Max columns for overflow |
data-content-limiter="true" | Auto-adjust text size |
data-pixel-perfect="true" | Crisp text rendering |
data-table-limit="true" | Table overflow with "and X more" |
Label & Title Variants
<span class="label label--small">Small</span>
<span class="label label--medium">Medium</span>
<span class="label label--underline">Underlined</span>
<span class="label label--gray">Muted/completed</span>
<span class="title title--small">Compact title</span>
Gap Utilities
gap--space-between | gap--xxlarge | gap--xlarge | gap--large | gap--medium | gap | gap--small | gap--xsmall | gap--none
Typography Guidelines
Recommended: Georgia serif font for e-ink readability.
Content-aware sizing:
- Short content = bigger fonts (24-28px body)
- Long content = smaller fonts (20px body)
- Headings: 36-48px
User Experience
Critical: Do NOT echo content back to chat. Just confirm "Sent to TRMNL".
Anti-Patterns
- Tiny fonts for short content
- Center-aligning columns with different lengths (use
layout--start) - Spoiling content in chat confirmation
- Missing
value--tnumson numbers - Missing
title_bar - Not using
data-fit-valueon primary metrics - Skipping
data-overflowon variable lists - Using inline gray colors instead of
bg--gray-* - Forgetting dividers between sections
Best Practices
- Verify
<div>{{content}}</div>display markup - Use
layout+title_barstructure - Always
value--tnumsfor numbers - Use
data-fit-valueon primary metrics - Use
data-overflowon variable lists - Use
itemcomponent pattern - Use
dividerbetween sections - Use
bg--gray-*dithered classes - Content-aware font sizing
- Top-align columns (
layout--start) - Temp file method for curl
- Minimal confirmations
Mashup Layouts (Multi-Plugin)
For dashboard views with multiple plugins:
| Layout | Description |
|---|---|
mashup--1Lx1R | 2 columns (50/50) |
mashup--1Tx1B | 2 rows (50/50) |
mashup--2x2 | 4 quadrants |
See references/layout-systems.md for all 7 layouts.
Troubleshooting
| Problem | Solution |
|---|---|
| Webhook fails | Verify URL, check rate limits (12/hour free) |
| Content missing | Check display markup is <div>{{content}}</div> |
| Payload too large | Run scripts/check_payload.py, keep under 2KB (free) or 5KB (TRMNL+) |
| Numbers misaligned | Add value--tnums |
| Text overflow | Use data-clamp or data-overflow |
| Columns misaligned | Use layout--start not layout--center |
| Multiple layouts error | Keep only ONE .layout element per view |
| Nested content fails | Use .richtext for nested/formatted content |
No README available.
Permissions & Security
Security level L1: Low-risk skills with minimal permissions. Review inputs and outputs before running in production.
Requirements
- OpenClaw CLI installed and configured.
- Language: Markdown
- License: MIT
- Topics:
FAQ
How do I install trmnl?
Run openclaw add @peetzweg/trmnl in your terminal. This installs trmnl into your OpenClaw Skills catalog.
Does this skill run locally or in the cloud?
OpenClaw Skills execute locally by default. Review the SKILL.md and permissions before running any skill.
Where can I verify the source code?
The source repository is available at https://github.com/openclaw/skills/tree/main/skills/peetzweg/trmnl. Review commits and README documentation before installing.
