BeClaude

ai-desk-card

New
GitHub TrendingGeneralby op7418

Drive a physical e-ink desk card (M5Paper 540×960) sitting next to the user's monitor. Use whenever the user wants to: - show / push / display ANYTHING on their card / 卡片 / 副屏 / 墨水屏 / e-ink display / desk card / glanceable display / secondary display - set up the device for the first time (flash firmware, pair, provision Wi-Fi) — phrases like "刚拿到 M5Paper", "怎么装卡片", "first-time setup", "刷固件", "卡片没反应" - schedule recurring pushes / "每小时刷一次" / "工作时间显示日历" / "auto-refresh every 30 min" - configure what the card shows (weather, todos, calendar, inbox, PR queue, AI status, focus, scratch, deadlines, messages, now-playing, git-status, system, next-meeting, break-reminder, ai-tasks) - put the device to sleep / show business card / "息屏" / "睡眠" Single Skill, agent-agnostic: probes current state, then routes to the right sub-flow. Never asks "is the daemon running" — it checks.

First seen 5/22/2026

Overview

ai-desk-card — single Skill entry point

A 540×960 e-ink panel sitting next to the user's monitor. AI agents push widgets to it; the daemon renders frames server-side and ships pixels over Wi-Fi / USB / BLE. This Skill is the only thing an agent needs to call — it auto-detects state and routes to the right flow.

Step 1 — ALWAYS probe state first

Before doing anything, run the state probe. Do not ask the user "have you done X" — find out by checking.

bash
bash $SKILL_DIR/scripts/state.sh

($SKILL_DIR is wherever this Skill is installed. If your agent runtime sets $CLAUDE_PLUGIN_ROOT, use that. Otherwise use the repo root.)

Output is JSON with this shape:

jsonc
{
  "hardware":   { "pio_installed": bool, "m5paper_usb": str|null },
  "firmware":   { "flashed": bool, "ours": bool, "version": str|null },
  "daemon":     { "running": bool, "pid": int|null },
  "transport":  { "connected": bool, "type": "BLETransport|SerialTransport|WiFiTransport|null" },
  "device":     { "alive": bool, "last_seen_seconds": int|null,
                  "active_transport": "Wi-Fi|USB|BLE|null",
                  "battery_pct": int|null, "uptime": str|null },
  "wifi":       { "provisioned": bool, "ip": str|null },
  "interests":  { "configured": bool, "path": str|null }
}

The most important field is device.alive. It tells you whether the device has sent a status report in the last ~90 s. transport.connected only says "daemon picked a transport class"; device.alive says "we're actually hearing back from the device right now."

Step 1.5 — Identify the device profile

The Skill supports two devices with different panels + daemons:

  • M5Paper V1.1 (540×960 grayscale, GT911 touch, BLE pair) — original
  • M5Paper Color (600×400 Spectra 6 color, 3 physical buttons, audio + SHT40) — new in v0.10

If GET /heartbeat returns device_status.device == "M5PaperColor" (via color_daemon.py running), use the Color path described in flows/08_paper_color.md:

  • env: pio run -e paper-color
  • daemon: python3 daemon/color_daemon.py --device-ip <IP>
  • Wi-Fi provision: Serial JSON cmd:wifi_set (no BLE pairing UX)
  • slot names: top-left / top-right / bottom-left / bottom-right
  • extra widgets: ambient (SHT40 temp+humid)
  • physical buttons: 顶=sleep / 下左=refresh / 下中=settings

Otherwise (default) use the V1.1 path through the routing table below.

The two daemons can't run on the same port simultaneously — pick one based on which device is in front of the user. The Skill flows below work for V1.1 unless explicitly noted.

Step 2 — Route based on state

Walk the decision tree in this order. First mismatch wins; fix it, then re-probe.

ConditionNext actionDetail flow
firmware.flashed == false AND no device.aliveFirst-time hardware setupflows/01_install.md
daemon.running == falseStart the daemonbash $SKILL_DIR/plugin/scripts/start.sh
device.alive == false AND transport.connected == falseDevice unreachable — could be asleep, off, BLE not paired. Tell user, suggest physical wake (tap rotary / plug USB)flows/02_transport.md
device.alive == false AND transport.connected == true (daemon connected something but no status_report in 90s)Device transport up but not responding — restart daemon, then probeflows/02_transport.md
wifi.provisioned == false (and user wants always-on or battery mode)Provision Wi-Fiflows/03_wifi.md
interests.configured == false AND user just asked for "auto-refresh" or "定时推送"Ask about interests, write ~/.ai-desk-card/interests.yamlflows/04_interests.md
device.alive == true + user said "push X"Build widget JSON, POST to daemonflows/05_push.md
device.alive == true + user said "schedule" / "每 N 分钟" / "auto"Set up scheduled pushflows/06_schedule.md
device.alive == true + user said "sleep" / "息屏"Push business card + deep sleepflows/07_sleep.md

Always tell the user which step you're on. Don't operate silently.

Step 3 — Push a widget (the hot path)

When state is OK and user asks to show something:

bash
curl -sf -X POST "${CARD_DAEMON_URL:-http://127.0.0.1:9877}/widget" \
  -H 'Content-Type: application/json' \
  -d @- <<'JSON'
{
  "slot": "top-left",
  "type": "weather",
  "data": { "city": "Beijing", "temp_c": 22, "icon": "sun", "summary": "晴" }
}
JSON
  • slot: string. Layout is 2-1-1 not 2x2 —

top-left (270×280) · top-right (270×280) · middle (540×340) · bottom (540×280) · full (540×960, takes over the whole screen).

  • type: one of 16 — see plugin/skills/card-widget/schemas/ for full

JSON schemas with examples.

  • Wi-Fi: response in ~0.2 s. USB: 1–32 s. BLE frame-data: broken — small

commands only.

Full per-widget schema + theme reference: plugin/skills/card-widget/SKILL.md

Step 4 — When to suggest scheduled pushes

If the user's request implies recurrence ("keep my calendar updated", "check email every hour", "show me today's todos throughout the day"), don't just push once. Instead:

  1. Confirm the cadence + which widgets they want
  2. Write/update ~/.ai-desk-card/interests.yaml (see flow 04)
  3. Set up the schedule using your agent's native loop primitive:

- Claude Code: /loop 30m or ScheduleWakeup - Codex / Gemini: equivalent scheduling - Fallback: cron line via plugin/skills/card-refresh/scripts/refresh_loop.sh

The Skill provides the what (interests + push) — your agent provides the when (loop primitive).

Constraints to never violate

  • No silent operations. Every sub-step gets a one-line update to the user.
  • No retry loops. If something fails, surface the diagnostic and stop.
  • No assuming state. Always re-probe after fixing something.
  • No font escape hatches. The CJK TTF doesn't include ▢ ▶ ✎ ♪ ↑ ↓ ● ○

— … °. Use the safe glyph set documented in plugin/skills/card-widget/SKILL.md.

  • Wi-Fi preferred over USB / BLE. 0.2 s vs 1-32 s vs broken.

Hardware: what the user needs

  • M5Paper V1.1 (~¥600 / $90) — primary target
  • USB-C data cable (one time, for flashing)
  • Optional: USB-C charger for always-on Wi-Fi mode

What this Skill is NOT

  • Not a Claude-Code-only plugin. The plugin/ directory is provided for

CLIs that consume slash commands, but this SKILL.md is the agent-agnostic entry point.

  • Not a cloud service. Everything runs on the user's machine (daemon at

127.0.0.1:9877 by default) + the device's local Wi-Fi.

  • Not a generic e-ink renderer. The widgets, themes, and renderer all

target this specific device + grid.

Install & Usage

1
Create the skills directory
mkdir -p .claude/skills
2
Download the skill file
mkdir -p .claude/skills && curl -o .claude/skills/ai-desk-card.md https://raw.githubusercontent.com/op7418/ai-desk-card/main/SKILL.md
3
Invoke in Claude Code
/ai-desk-card
View source on GitHub
agent

Security Audits

LicenseUnknownSourceWarnRepositoryPass

Frequently Asked Questions

What is ai-desk-card?

Drive a physical e-ink desk card (M5Paper 540×960) sitting next to the user's monitor. Use whenever the user wants to: - show / push / display ANYTHING on their card / 卡片 / 副屏 / 墨水屏 / e-ink display / desk card / glanceable display / secondary display - set up the device for the first time (flash firmware, pair, provision Wi-Fi) — phrases like "刚拿到 M5Paper", "怎么装卡片", "first-time setup", "刷固件", "卡片没反应" - schedule recurring pushes / "每小时刷一次" / "工作时间显示日历" / "auto-refresh every 30 min" - configure what the card shows (weather, todos, calendar, inbox, PR queue, AI status, focus, scratch, deadlines, messages, now-playing, git-status, system, next-meeting, break-reminder, ai-tasks) - put the device to sleep / show business card / "息屏" / "睡眠" Single Skill, agent-agnostic: probes current state, then routes to the right sub-flow. Never asks "is the daemon running" — it checks.

How to install ai-desk-card?

To install ai-desk-card: create the skills directory (mkdir -p .claude/skills), then run: mkdir -p .claude/skills && curl -o .claude/skills/ai-desk-card.md https://raw.githubusercontent.com/op7418/ai-desk-card/main/SKILL.md. Finally, /ai-desk-card in Claude Code.

What is ai-desk-card best for?

ai-desk-card is a skill categorized under General. It is designed for: agent. Created by op7418.