Agent skill

Implement Widget Frontend

by cryptomilk in cryptomilk/hass-eink-dashboard

Add TypeScript types in ha.d.ts and editor schema in eink-dashboard-editor.ts for a new or updated widget type; also handles deprecating an old type (remove from picker, keep schema, add @deprecated…

Apache-2.0Auto-check passedDevelopment

Install Implement Widget Frontend

skills CLI
$ npx skills add cryptomilk/hass-eink-dashboard --skill implement-widget-frontend -a claude-code

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

GitHub CLI
$ gh skill install cryptomilk/hass-eink-dashboard implement-widget-frontend --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/cryptomilk/hass-eink-dashboard.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/implement-widget-frontend .claude/skills/implement-widget-frontend && 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
implement-widget-frontend
GitHub stars
116
Token cost
~3.3k tokens
SKILL.md length
1,147 words
Files
1
Skills in repo
3
Repo updated
First seen
Licence
Apache-2.0

At a glance

Add TypeScript types in ha.d.ts and editor schema in eink-dashboard-editor.ts for a new or updated widget type; also handles deprecating an old type (remove from picker, keep schema, add @deprecated…

  • Works in 4 steps: Update TypeScript type definitions → Update editor schema → Update frontend tests → …
  • Tasks that involve Type safety
  • SKILL.md covers Before you start, Existing TS widget type…, Widget config specifications and Implementation steps, plus 3 more sections
  • Calls pnpm

What it does

Implement Widget Frontend is an agent skill from cryptomilk/hass-eink-dashboard. Add TypeScript types in ha.d.ts and editor schema in eink-dashboard-editor.ts for a new or updated widget type; also handles deprecating an old type (remove from picker, keep schema, add @deprecated JSDoc). Canvas preview was replaced by server-rendered SVGs in step 4.1; no frontend renderer is needed.

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

It sits in Development, covering Type safety and Technical documentation. It works with Home Assistant. The repository describes itself as: This is beta quality, should be mostly stable. The licence is Apache-2.0.

When your agent uses it

  • Tasks that involve Type safety
  • Tasks that involve Technical documentation

Example prompts

  • “/implement-widget-frontend”

Requirements

  • Python 3
  • Pre-approved tools (allowed-tools): Read, Edit, Write, Bash(pnpm *)

Workflow steps

4 steps, taken from the step headings in SKILL.md.

  1. Update TypeScript type definitions
  2. Update editor schema
  3. Update frontend tests
  4. Verify

What it can do on your machine

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

  • Tool permissions

    Pre-approves these tools, so the agent can use them without asking each time:

    • Read
    • Edit
    • Write
    • Bash(pnpm *)

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • pnpm

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

  • Network

    No URLs in SKILL.md. Its commands use pnpm, 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

Implement Widget Frontend loads about 3.3k tokens when it runs. Until then it costs about 82 tokens; SKILL.md has 1,147 words of instructions outside code blocks.

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

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 cryptomilk/hass-eink-dashboard at commit 6142841, republished under its Apache-2.0 licence (© cryptomilk). 1,147 words, ~3,294 tokens.

Download SKILL.mdSave it as .claude/skills/implement-widget-frontend/SKILL.md (or your agent's skills folder).
name
implement-widget-frontend
description
Add TypeScript types in ha.d.ts and editor schema in eink-dashboard-editor.ts for a new or updated widget type; also handles deprecating an old type (remove from picker, keep schema, add @deprecated JSDoc). Canvas preview was replaced by server-rendered SVGs in step 4.1; no frontend renderer is needed.
allowed-tools
Read, Edit, Write, Bash(pnpm *)
when_to_use
When adding a new widget type, deprecating an existing one, or updating a widget's TypeScript types or editor form. Run AFTER the Python renderer…
argument-hint
[widget-type]
arguments
widget-type

Implement Widget Frontend: $widget-type

Add TypeScript types and editor schema for $widget-type. The card fetches SVGs from the Python backend via WebSocket — no canvas renderer is needed here.

Before you start

  1. Read existing type definitions in frontend/src/types/ha.d.ts.
  2. Read existing schemas in frontend/src/eink-dashboard-editor.ts.
  3. Use the widget config specifications below as the source of truth for which fields to expose.

Existing TS widget type definitions

!grep -n "interface\|^export type" custom_components/eink_dashboard/frontend/src/types/ha.d.ts

Widget config specifications

These are the canonical field lists for each widget type. Use them to determine which fields to add to the TypeScript interface and which controls to add to the editor schema.

Project-specific fields (all widgets)

Every widget config extends HA's card config with these project-specific fields:

  • card_style — "border" | "left_bar" | "none" (default: "none"). Controls decorative frame around the widget.
  • icon_style — "filled" | "outlined" | "none" (default: "filled"). Controls icon circle rendering.
Tile

Single-entity widget modelled after HA's Tile card.

Config fields (add to interface, expose in schema):

  • entity (required) — any HA entity
  • name — override display name
  • icon — override icon (default: entity's domain icon)
  • hide_state — boolean, suppress state text
  • state_content — which state attribute(s) to display
  • show_entity_picture — show entity picture instead of icon
  • card_style — project-specific (see above)
  • icon_style — project-specific (see above)

Fields intentionally omitted: vertical, color, features, features_position, all tap_action / hold_action / double_tap_action variants.

Heading

Section heading with optional icon and entity badges, modelled after HA's Heading card.

Config fields:

  • heading — heading text
  • heading_style — "title" | "subtitle"
  • icon — MDI icon name (e.g. "mdi:fridge")
  • badges — list of entity badge configs
  • icon_style — project-specific (default: "none")
  • card_style — project-specific (see above)

Fields intentionally omitted: tap_action.

Sensor

Single-entity sensor with optional history graph, modelled after HA's Sensor card.

Config fields:

  • entity (required) — sensor, counter, input_number, number
  • name — override display name
  • icon — override icon
  • graph — "line" | none (default: none)
  • hours_to_show — history window (default: 24)
  • detail — graph detail level (1 or 2)
  • unit — unit override
  • limits — { min?: number, max?: number } for graph Y-axis
  • card_style — project-specific (see above)
  • icon_style — project-specific (see above)

Fields intentionally omitted: theme.

Entity

Single-entity display with large value, modelled after HA's Entity card.

Config fields:

  • entity (required) — any HA entity
  • name — override display name
  • icon — override icon
  • attribute — show a specific attribute instead of state
  • unit — unit override
  • card_style — project-specific (see above)
  • icon_style — project-specific (see above)

Fields intentionally omitted: state_color, theme, all tap_action / hold_action / double_tap_action variants.

Entities

Multi-entity list card, modelled after HA's Entities card.

Config fields:

  • title — optional card header text
  • icon — optional header icon
  • entities (required) — list of row configs:
    • Entity row: string entity ID, or { entity, name?, icon? } object
    • Divider row: { type: "divider" }
    • Section row: { type: "section", label? }
  • card_style — project-specific (see above)
  • icon_style — project-specific (see above)

Fields intentionally omitted: show_header_toggle, header, footer, state_color, theme.

Clock

Digital time display, modelled after HA's Clock card.

Config fields:

  • title — optional label above the time
  • clock_size — "small" | "medium" | "large"
  • time_format — 12h or 24h override
  • time_zone — timezone override
  • show_seconds — boolean (default: false)
  • card_style — project-specific (see above)

Fields intentionally omitted: clock_style (digital only), no_background, seconds_motion, border, ticks, face_style.

Weather, Separator, Device Battery, Waste Schedule

Keep existing frontend definitions unchanged.

Implementation steps

1. Update TypeScript type definitions

In frontend/src/types/ha.d.ts:

Add supporting interfaces (if the widget has structured sub-items):

typescript
/** One badge entry displayed beside the heading. */
export interface {WidgetName}Badge {
  /** HA entity ID. */
  entity: string;
  /** Override label; unused in current renderer but reserved. */
  name?: string;
  /** MDI icon name override (e.g. "mdi:thermometer"). */
  icon?: string;
  /** Show the entity state value next to the icon. Default: true. */
  show_state?: boolean;
  /** Render an icon alongside the badge text. Default: false. */
  show_icon?: boolean;
}

Add the widget interface:

typescript
/** One-line summary of what this widget does. */
export interface {WidgetName}Widget extends WidgetBase {
  type: "$widget-type";
  /** Description of primary content field. */
  $main_field?: string;
  /** Ordered list of entity IDs or structured badge configs. */
  badges?: (string | {WidgetName}Badge)[];
  /** Decorative frame style. */
  card_style?: CardStyle;
  /** Icon circle rendering mode. */
  icon_style?: IconStyle;
}

Fields prefixed with $ are placeholders — substitute the real field name from the widget spec (e.g. heading for Heading, entity for Tile).

Include only the fields the Python renderer actually reads. Omit fields that belong to WidgetBase (x, y, w, font_size, color) since those are inherited. Document every member with a JSDoc comment.

Add to the Widget union type:

typescript
export type Widget =
  | TextWidget      // @deprecated — kept for existing configs
  | SeparatorWidget
  | ...
  | {WidgetName}Widget;
Show full SKILL.md (568 more words)Show less
2. Update editor schema

In frontend/src/eink-dashboard-editor.ts:

Add to WIDGET_TYPES (only widgets shown in the picker — deprecated widgets are removed from here but their SCHEMAS entry is kept so existing configs remain editable):

typescript
"$widget-type": {
  label: "Widget Name",
  description: "One-line description shown in the widget picker.",
  icon: "mdi:some-icon",
  defaults: {
    type: "$widget-type",
    x: 24, y: 0, w: 400, h: 56,  // x: 24 = PADDING for content widgets
    $main_field: "",               // content-field default
    card_style: DEFAULT_CARD_STYLE,
    icon_style: DEFAULT_ICON_STYLE, // override per widget spec
  },
},

Use x: 24 (= PADDING) for content widgets (entity, tile — anything with internal text and icons) so newly created widgets land at the standard canvas inset. Use x: 0 only for structural widgets that span full width (separator, heading).

Include defaults for content fields so the form is pre-populated on first open (e.g. heading: "", heading_style: "title"). Override icon_style when the widget spec defines a different default (e.g. Heading uses "none" instead of DEFAULT_ICON_STYLE).

Add to ICON_FALLBACK in frontend/src/eink-widget-picker.ts — every icon value used in WIDGET_TYPES must have a text/emoji entry in ICON_FALLBACK. Without it the picker renders the raw MDI string (e.g. "format-list-bulleted") instead of a glyph. Check whether the icon is already present; add it only if missing:

typescript
const ICON_FALLBACK: Record<string, string> = {
  // … existing entries …
  "mdi:some-icon": "X",   // add a short text or emoji fallback
};

Add to SCHEMAS — use identitySection() plus grouped sections (identitySection first, Content expanded by default, Layout and Appearance collapsed). The flatten: true flag on each expandable section merges the contained fields directly into the widget data object rather than nesting them under a key:

typescript
"$widget-type": (d: DisplayConfig) => [
  identitySection(),
  {
    name: "content",
    type: "expandable",
    flatten: true,
    expanded: true,
    title: "Content",
    icon: "mdi:text",
    schema: [
      { name: "$main_field", selector: { text: {} } },
      {
        name: "badges",
        selector: { entity: { multiple: true } },
      },
    ],
  },
  {
    name: "layout",
    type: "expandable",
    flatten: true,
    title: "Layout",
    icon: "mdi:move-resize",
    schema: [{ type: "grid", name: "", schema: posXYWH(d) }],
  },
  {
    name: "appearance",
    type: "expandable",
    flatten: true,
    title: "Appearance",
    icon: "mdi:palette",
    // Pass a default when the widget overrides DEFAULT_ICON_STYLE:
    //   iconStyleSelector("none")   — for Heading
    schema: [cardStyleSelector(), iconStyleSelector()],
  },
],

Add to getSummary() — return a short human-readable summary for the widget list row. Two common patterns:

typescript
// Text-primary widgets (heading, text):
if (t === "$widget-type") {
  const s = String(widget.$main_field || "");
  return s.length > 30 ? s.slice(0, 30) + "…" : (s || "(empty)");
}

// Entity-primary widgets (tile, weather):
if (t === "$widget-type") {
  return widget.entity || "(no entity)";
}

Add to LABELS — every field name used in the schema that does not already have a label entry needs one:

typescript
$main_field: "Editor label for primary field",

Entity domain filtering: Use the correct domain filter for each widget type:

  • tile, heading → no domain filter (accepts any entity)
  • waste_schedule → { domain: "sensor" } (single entity from waste_collection_schedule)
  • device_battery → { domain: "sensor" } or no filter

Visibility conditions: Every widget form automatically gets a collapsible Visibility section appended by _buildVisibilityEditor() in eink-dashboard-editor.ts. Do NOT add a visibility field to the widget's SCHEMAS entry — it would duplicate the auto-appended section. The visibility field is typed as (Condition | LegacyCondition)[] (both types exported from ha.d.ts) on WidgetBase, so all widget interfaces inherit it.

3. Update frontend tests

In frontend/test/eink-dashboard-editor.test.ts there are two ALL_TYPES constant arrays that must be kept in sync manually:

  • WIDGET_TYPES > ALL_TYPES — lists only picker-visible types (i.e. what is in WIDGET_TYPES). Update the count in the test description too (e.g. "has all N widget types").
  • SCHEMAS > ALL_TYPES — lists every type with a schema builder (picker-visible + deprecated types kept for editing). Update the count in the test description too.

The integration test add-widget integration > appends a widget when a type is selected from the picker clicks a data-type="…" card. If you removed or renamed a widget type in the picker, update the data-type attribute value in this test to an existing picker type.

4. Verify
bash
pnpm --dir custom_components/eink_dashboard/frontend typecheck && \
pnpm --dir custom_components/eink_dashboard/frontend test

Deprecating a widget type

When a widget type is superseded (e.g. text → heading):

  1. Remove from WIDGET_TYPES so it no longer appears in the picker.
  2. Keep in SCHEMAS so existing configs remain editable.
  3. Add @deprecated JSDoc to the TypeScript interface in ha.d.ts.
  4. Update AGENTS.md widget type list.
  5. Keep in the Widget union type — removing it would break type narrowing for existing config objects.

Default values

The Python constant DEFAULT_ROW_H = 56 (in const.py) is the standard single-row height. Use it as the basis for h defaults in WIDGET_TYPES and SCHEMAS:

  • Single-row widget: h: 56
  • Two-row widget: h: 112 (= 2 × DEFAULT_ROW_H)
  • Chip-style widget: h: 28

These values keep the frontend defaults in sync with the Python renderer's own sizing baseline.

Key references

  • Python SVG renderer: custom_components/eink_dashboard/svg_render.py
  • Sizing baseline: DEFAULT_ROW_H = 56 in const.py
  • Types: frontend/src/types/ha.d.ts
  • Editor: frontend/src/eink-dashboard-editor.ts
  • Tests: frontend/test/eink-dashboard-editor.test.ts

© cryptomilk, 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 .agents/skills/implement-widget-frontend of cryptomilk/hass-eink-dashboard.

Open the folder on GitHubat commit 6142841

Compare with similar skills

Implement Widget Frontend 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.

Implement Widget Frontend compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Implement Widget Frontend this skillcryptomilk/hass-eink-dashboard116—~3.3kAutomated safety check: PassApache-2.0
Meilisearch PHP PHPDoc Writermeilisearch/meilisearch-php757—~569Automated safety check: PassMIT
Diataxis Docs Writercalf-ai/calfkit-sdk1491 repos~3kAutomated safety check: PassApache-2.0
Ha Code QualityFutureTense/keymaster349—~462Automated safety check: PassMIT
Repo Guardsimovilab/databus101—~1.3kAutomated safety check: PassApache-2.0
Adk Stylegoogle/adk-python22k—~769Automated safety check: PassApache-2.0

Similar skills

  • Meilisearch PHP PHPDoc Writer

    meilisearch/meilisearch-php

    Documents public methods of the meilisearch-php SDK with compact PHPDoc, including @see links, @since tags and the experimental-feature notice.

    757 GitHub stars~569 tokensUpdated yesterday
    DevelopmentAuto-check passed
  • Diataxis Docs Writer

    calf-ai/calfkit-sdk

    Write or improve software documentation using the Diátaxis framework — four documentation types (tutorials, how-to guides, reference, explanation), each serving a different user need.

    149 GitHub starsUsed in 1 repo~3k tokens
    DevelopmentAuto-check passed
  • Ha Code Quality

    FutureTense/keymaster

    Standards and commands for linting, code formatting, typing validation (Ruff, MyPy, Codespell, ESLint, Pre-commit/Prek, Tox), and adherence to Home Assistant Python 3.14 standards in Keymaster.

    349 GitHub stars~462 tokensUpdated today
    DevelopmentAuto-check passed
  • Repo Guard

    simovilab/databus

    Keep the databus repo clean as it grows — verify new/changed backend code meets the project's docstring, type-hint, and structural conventions, and update any docs the change made stale.

    101 GitHub stars~1.3k tokensUpdated 1 mo ago
    DevelopmentAuto-check passed
  • Adk Style

    google/adk-python

    Official

    Python style and codebase conventions for ADK (Agent Development Kit): private-by-default file visibility, imports, type hints, Pydantic v2 models, formatting, docstrings, logging, async I/O, file…

    22k GitHub stars~769 tokensUpdated today
    DevelopmentAuto-check passed
  • Validate Signature

    peijun1700/bluemouse

    L5-L8 函數簽名驗證 - 檢查參數、返回值、類型提示、文檔字符串. An agent skill from peijun1700/bluemouse.

    109 GitHub stars~923 tokensUpdated 8 mo ago
    DevelopmentAuto-check: notes

More from cryptomilk/hass-eink-dashboard

  • Implement Widget

    cryptomilk/hass-eink-dashboard

    Implement a widget's SVG template and Python context builder.

    116 GitHub stars~4.8k tokensUpdated 2 days ago
    Auto-check passed
  • Implement Widget Tests

    cryptomilk/hass-eink-dashboard

    Write TDD tests for a widget type: structural tests (borders, dividers), alignment tests (icon centering), and scaling tests (proportional sizing).

    116 GitHub stars~4.2k tokensUpdated 2 days ago
    Auto-check passed

Works with

Questions about Implement Widget Frontend

What does Implement Widget Frontend do?

Add TypeScript types in ha.d.ts and editor schema in eink-dashboard-editor.ts for a new or updated widget type; also handles deprecating an old type (remove from picker, keep schema, add @deprecated…. Implement Widget Frontend is an agent skill from cryptomilk/hass-eink-dashboard.ts for a new or updated widget type; also handles deprecating an old type (remove from picker, keep schema, add @deprecated JSDoc).

When should I use Implement Widget Frontend?

Implement Widget Frontend fits situations like: tasks that involve Type safety; tasks that involve Technical documentation.

How do I install Implement Widget Frontend in Claude Code?

Run `npx skills add cryptomilk/hass-eink-dashboard --skill implement-widget-frontend -a claude-code`. Or copy the skill folder (.agents/skills/implement-widget-frontend in cryptomilk/hass-eink-dashboard) into .claude/skills/implement-widget-frontend in your project. Claude Code loads it when a task matches its description.

How do I install Implement Widget Frontend in Codex?

Run `npx skills add cryptomilk/hass-eink-dashboard --skill implement-widget-frontend -a codex`. Or copy the skill folder (.agents/skills/implement-widget-frontend in cryptomilk/hass-eink-dashboard) into .agents/skills/implement-widget-frontend in your project. Codex loads it when a task matches its description.

Can I use Implement Widget Frontend 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 cryptomilk/hass-eink-dashboard --skill implement-widget-frontend -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/implement-widget-frontend, .gemini/skills/implement-widget-frontend, .github/skills/implement-widget-frontend and .opencode/skills/implement-widget-frontend in your project.

What does Implement Widget Frontend need to run?

Going by SKILL.md and its folder, Implement Widget Frontend needs the command-line tools its instructions call (pnpm). Our summary lists: Python 3. Its frontmatter pre-approves these tools: Read, Edit, Write, Bash(pnpm *).

Does Implement Widget Frontend access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Implement Widget Frontend 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 Implement Widget Frontend use?

Implement Widget Frontend 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 Implement Widget Frontend use?

About 3.3k tokens (SKILL.md is roughly 13k 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 Implement Widget Frontend?

Skills that share tags, products or a category with Implement Widget Frontend: Meilisearch PHP PHPDoc Writer (meilisearch/meilisearch-php, 757 stars), Diataxis Docs Writer (calf-ai/calfkit-sdk, 149 stars), Ha Code Quality (FutureTense/keymaster, 349 stars) and Repo Guard (simovilab/databus, 101 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Implement Widget Frontend?

cryptomilk (a GitHub user) maintains it in cryptomilk/hass-eink-dashboard, which has 116 GitHub stars. The repository holds 3 skills in this directory. The repository was last updated on October 6, 2026.

Source: cryptomilk/hass-eink-dashboard on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.