Skip to content
Agent Workspaces
Skill

/card-widget

Push live data to the user's ai-desk-card M5Paper e-ink companion display. Use whenever the user asks to show todos, calendar, weather, AI status, inbox counts, next meeting, or any glanceable info on their card / 卡片 / 副屏 / 墨水屏 / e-ink display. 16 widget types available; AI

From plugin
ai-desk-card
1534 skills9 commands

Claude Code

$ npx -y skills add op7418/ai-desk-card --skill card-widget --agent claude-code

SKILL.md

card-widget.SKILL.md
name: card-widget
description: |
  Push live data to the user's ai-desk-card M5Paper e-ink companion display.
  Use whenever the user asks to show todos, calendar, weather, AI status,
  inbox counts, next meeting, or any glanceable info on their card / 卡片 /
  副屏 / 墨水屏 / e-ink display. 16 widget types available; AI picks slot
  + widget type, fills data, POSTs to the local card daemon (default
  127.0.0.1:9877). Communicates over loopback, so individual widget writes
  don't trigger AI agent approval prompts.
trigger_keywords:
  - card widget
  - 卡片
  - 副屏
  - 墨水屏
  - paper card
  - 显示器副屏
  - secondary display
allowed-tools:
  - Bash
  - Read
  - Write

card-widget — drive the M5Paper 副屏

The card is a 540 × 960 e-ink panel sitting next to the user's monitor. You push 1-4 widgets and the daemon renders a single frame; transfer time depends on the transport.

Transport & latency (v0.8)

The daemon auto-picks Wi-Fi > USB > BLE at startup. Each path has different per-push characteristics — be aware:

| Transport | Single-widget update | Full frame | Power use | |---|---|---|---| | **Wi-Fi** (HTTP) | ~0.2 s | ~2 s | high while connected | | **USB serial** @ 115200 | ~1 s region / ~32 s full | 32 s | n/a | | **BLE** (small cmds only) | works for commands; **frame data hangs** | broken | low |

The daemon also runs a **dirty-region diff** so unchanged pixels don't re-transmit — typical "one widget updated" push is 5-30 KB instead of the 250 KB full frame. You don't manage this; the daemon decides per push.

**Push frequency rules** (e-ink hardware):

  • Per-widget content change: fine, push freely (debounced internally

at 1.5 s)

  • Per-keystroke streaming: NO. Each push triggers e-ink refresh which

damages the panel over time.

  • ai-status taking off / completion: one push at start, one at end.
  • For sub-minute "live" info (timer countdowns, music progress):

push at most every ~30 s.

If the user's on USB (1-32 s) instead of Wi-Fi (0.2 s), strongly suggest configuring Wi-Fi via `/card-wifi-setup` — it's a quality-of-life upgrade.

Layout cheat-sheet

Four slots. **Narrow slots (top-left, top-right) are 270 px wide**; wide slots (middle, bottom, full) span the full 540 px. Some widgets only shine when wide — see the catalog below.

┌───────────┬───────────┐   top-left  / top-right : 270×280   (narrow)
│ top-left  │ top-right │
├───────────┴───────────┤   middle               : 540×340   (wide)
│        middle         │
├───────────────────────┤   bottom               : 540×280   (wide)
│        bottom         │
└───────────────────────┘
        bar (60 px)         status/settings bar — always on

How to pick a layout

Walk this in order:

1. **Ask user what's most important** (or infer from context). The card only fits 4 widgets — be choosy. 2. **One headline widget → middle**. The biggest, most readable slot. Use for the day's most important info (calendar, focus, next-meeting). 3. **Two glance widgets → top-left + top-right**. Pick widgets whose most-important info fits a narrow column (weather, inbox, ai-status, git-status). 4. **One detail widget → bottom**. Lists, multi-row info (todo, deadlines, pr-queue, messages).

Default fallback if the user has no opinion:

top-left  = weather       top-right = ai-status
middle    = calendar      bottom    = todo

If the user is deep in a coding session, swap to:

top-left  = git-status    top-right = ai-status
middle    = focus         bottom    = ai-tasks

If it's a desk-companion / meeting-heavy day:

top-left  = weather       top-right = inbox
middle    = next-meeting  bottom    = pr-queue

Widget catalog

Every widget has a JSON schema at `schemas/<type>.schema.json`. The "shape" lines below are summaries — read the schema for full constraints.

Work staples

`weather` — _narrow OK_

City + big temp + condition + up to 2-day forecast.

{"location":"Beijing",
 "current":{"temp_c":22,"condition":"晴"},
 "forecast":[{"day":"明","high":26,"low":14,"condition":"多云"}]}

`calendar` — _wide preferred_ (narrow shows fewer rows)

Today's events. Pass `now_iso` so the renderer can mark which is current.

{"now_iso":"2026-05-21T13:30:00",
 "events":[{"start":"09:30","title":"standup"},
           {"start":"14:00","end":"15:00","title":"design review"}]}

`next-meeting` — _wide preferred_

The single next event with big countdown. Use when only ONE thing matters.

{"title":"design review","start_in":"in 42m","start_at":"14:00",
 "location":"Zoom","attendees":"Alice, Bob, Carol"}

`messages` — _wide preferred_

Up to 3 IM previews. Each item: sender + preview + age.

{"items":[{"sender":"Bob","preview":"PR ready for review","age":"2m"}]}

`inbox` — _narrow OK_

Total unread + per-source breakdown. Cap 4 sources.

{"total":12,
 "sources":[{"name":"gmail","count":4},{"name":"slack","count":8}]}

`system` — _narrow OK_

CPU / mem / disk / battery / net / temp. Vertical 4-row in narrow slot. **Note**: field is `memory_pct` (not `mem_pct`); `battery_pct=255` means no battery.

{"cpu_pct":42,"memory_pct":63,"disk_pct":81,"battery_pct":88,
 "net_down_kbps":120,"temp_c":56}

`git-status` — _narrow OK_

Branch + modified/untracked/staged + ahead/behind + last commit.

{"repo_name":"ai-desk-card","branch":"main",
 "modified":3,"untracked":1,"staged":0,"ahead":2,"behind":0,
 "last_commit_msg":"add login flow"}

`pr-queue` — _wide preferred_

PR counts + up to 4 items. Status: `review` | `yours` | `approved` | `blocked`.

{"review_count":2,"your_open_count":1,
 "items":[{"number":"#42","title":"fix race","author":"alice","status":"review"},
          {"number":"#51","title":"feat: cron","author":"you","status":"yours"}]}

`now-playing` — _wide preferred_

Track + artist + position/duration (seconds, not float progress).

{"track":"Stairway","artist":"Led Zeppelin",
 "sou
Read more
@op7418
Ships withai-desk-card

🌏 English version: README.en.md 一个适配 Claude Code / Codex 等 Agent 的桌面副屏 Skill。把 M5Paper V1.1 4.7 寸墨水屏立在显示器旁边,由 AI Agent 推送 widget:天气、日程、todo、PR 队列、AI 状态、休息提醒…… 装上 Skill 后,烧固件 / 配 Wi-Fi / 推内容 / 设置定时全部由 Agent 引导,你不用自己跑一行 pio 或 curl。

Stars on GitHub

Momentum

stars in total
153
Star history of op7418/ai-desk-card on GitHub, a chart by star-history.com

Other skills on ai-desk-card.

card-onboard

card-onboard

Onboard a user setting up AI Desk Card for the first time, or after moving to a new machine, plugging the device into a new…

@op7418@op7418Install Skill
card-refresh

card-refresh

Invoked by cron (or manually) to refresh the widgets on the ai-desk-card e-ink display with fresh data. Reads the current widget…

@op7418@op7418Install Skill
card-wifi-setup

card-wifi-setup

Walk a user through provisioning Wi-Fi on their AI Desk Card device. After provisioning, device joins the user's home Wi-Fi,…

@op7418@op7418Install Skill

More skills from other plugins.

paseo

paseo

Paseo reference for managing hosts, projects, workspaces, workspace scripts, agents, schedules, and heartbeats.

paseo2w23k
@getpaseo@getpaseoInstall Skill
10x
Auto-invoked

10x

Personalized audit that teaches the advanced Paradev (formerly Superset) features the user isn't using yet (automations, parallel…

paradev5d16k
@superset-sh@superset-shInstall Skill
capabilities

capabilities

Your capability catalog — read this at boot. Lists the temporal date-range skills and the external integrations (reached via the…

@chaitanyagiri@chaitanyagiriInstall Skill

Questions about card-widget.

Which coding agents can use card-widget?
card-widget installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.