trmnlc/CLAUDE.md
Kate Meerburg 2e34246d14 Add today-view plugin with Tana, ICS, and Donetick data sources
Implements an e-ink daily dashboard plugin ("today") with four sections:
date/focus/success header, agenda timeline, chores checklist, and
due/overdue task lists.

Data sources:
- Focus & success text: Tana daily note (src/sources/tana.ts)
- Due/overdue tasks: Tana task search (src/sources/tana.ts)
- Agenda events: ICS calendar feeds (src/sources/ics.ts)
- Chores: Donetick API (src/sources/donetick.ts)

All sources fetch in parallel and fall back gracefully on error.
Tests use mock HTTP servers with synthetic data — no real services needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-24 23:18:13 +02:00

3.1 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

TRMNLc is a self-hosted server that serves rendered displays to TRMNL e-ink devices. It renders plugin UIs as HTML using React SSR, screenshots with Puppeteer (Firefox), dithers with ImageMagick for e-ink, and serves via the TRMNL device API.

Running

bun install

# Run the server (requires Firefox and ImageMagick in PATH)
FIREFOX=/path/to/firefox CONFIG_FILE=config.json COLORMAP=./colormap.png bun run src/web.ts

# Run tests
bun test

The server runs on port 2300 by default (BUN_PORT env var). See config.sample.json for the config format.

Architecture

Plugin system

Each device is configured with a plugin name and settings object. The plugin registry (src/plugins.ts) maps names to factory functions that return a Renderable. The Renderable interface (src/template.ts) requires hash, nextEvent?, and async render().

Available plugins:

  • calendar — Full-screen ICS calendar view with current/next/later event slots. UI is in Dutch ("VRIJ", "BEZET", "VOLGENDE"). Implementation: src/xlcalendar.tsx.
  • today — Daily dashboard with date header, focus/success lines, agenda timeline, chores checklist, and due/overdue tasks. Implementation: src/todayview.tsx.

Data sources (src/sources/)

The today plugin fetches from external services during render(), all in parallel:

  • tana.ts — Fetches daily focus/success text and due/overdue tasks from a Tana server. Focus: calendar node → markdown field parsing. Tasks: single search query (lt tomorrow), split client-side by due date.
  • ics.ts — Fetches today's non-full-day events from ICS feeds, returns AgendaEvent[]. Note: location lives on instance.event.location, not on the expanded instance directly.
  • donetick.ts — Fetches chores from a Donetick instance (defaults to app.donetick.com). Filters by user_id and isActive. Done status: nextDueDate > today means completed.

Config structure

{
  "base_url": "http://host:2300",
  "devices": {
    "DEVICE_MAC": {
      "plugin": "today",
      "settings": { ... },
      "refresh": 300,
      "model": "inkplate_10"
    }
  }
}

Render pipeline

  1. src/web.ts — Bun HTTP server. Routes: /api/setup, /api/display (PNG), /api/display/html (raw HTML), /api/render/:id/:ignore (cached PNGs).
  2. src/template.ts — Wraps plugin HTML in a full page with TRMNL's CSS/JS framework.
  3. src/render.ts — Puppeteer (Firefox) screenshots the HTML, then ImageMagick dithers to 2-bit grayscale PNG.
  4. src/devices.ts — Fetches device model definitions (screen dimensions, CSS classes) from trmnl.com/api/models at startup.

Deployment

Deployed as a NixOS module via flake.nix / default.nix. The default.nix defines a systemd service with DynamicUser=true. The Nix derivation copies source directly (no build step — runs with bun run at runtime).

Formatting

Uses Prettier: single quotes, trailing commas (es5), 2-space indent, bracket same line.