Agent skill

Implement Widget

by cryptomilk in cryptomilk/hass-eink-dashboard

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

Apache-2.0Auto-check passedTesting & QA

Install Implement Widget

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

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

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

At a glance

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

  • Works in 6 steps: Add to WidgetType enum (if new widget) → Create the SVG template → Write the context builder → …
  • Tasks that involve Test-driven development
  • SKILL.md covers Before you start, Current SVG infrastructure…, Shared layout helpers… and Existing widget context builders, plus 9 more sections
  • Calls uv; reaches w3.org

What it does

Implement Widget is an agent skill from cryptomilk/hass-eink-dashboard. Implement a widget's SVG template and Python context builder. Creates templates/{type}.svg.j2 and widgets/{type}.py with build{type}context(). Follows TDD green phase — makes existing tests pass.

Its SKILL.md is about 4.8k 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 Testing & QA, covering Test-driven development. It works with Python and 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 Test-driven development

Example prompts

  • “/implement-widget”

Requirements

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

Workflow steps

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

  1. Add to WidgetType enum (if new widget)
  2. Create the SVG template
  3. Write the context builder
  4. Re-export from widgets/init.py
  5. Register in _SVG_RENDERERS
  6. Run tests

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(uv *)

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • uv

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

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • w3.org

    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 loads about 4.8k tokens when it runs. Until then it costs about 54 tokens; SKILL.md has 1,275 words of instructions outside code blocks.

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

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,275 words, ~4,834 tokens.

Download SKILL.mdSave it as .claude/skills/implement-widget/SKILL.md (or your agent's skills folder).
name
implement-widget
description
Implement a widget's SVG template and Python context builder. Creates templates/{type}.svg.j2 and widgets/{type}.py with _build_{type}_context(). Follows TDD green phase — makes existing tests pass.
allowed-tools
Read, Edit, Write, Bash(uv *)
when_to_use
When implementing the SVG template and context builder for a new widget type. Always run AFTER tests are written (TDD green phase).
argument-hint
[widget-type]
arguments
widget-type

Implement Widget Renderer: $widget-type

Implement the SVG template and Python context builder for $widget-type. The output of this work is two artifacts:

  1. custom_components/eink_dashboard/templates/$widget-type.svg.j2
  2. _build_$widget-type_context() in widgets/$widget-type.py

Before you start

  1. Read the existing tests (TestRender{WidgetName} in tests/test_render_{widget_type}.py) — these define the expected behavior.
  2. Read const.py for WidgetType, COLOR_* constants, PADDING, DEFAULT_CARD_STYLE, Widget, DisplayConfig, color_to_hex.
  3. Read svg_render.py for the Jinja2 environment, _svg_to_png(), icon filter functions (_mdi_svg_filter, _weather_svg_filter), and _SVG_RENDERERS.
  4. Read existing widget modules in widgets/ (e.g. widgets/tile.py) for the context builder pattern, and widgets/_helpers.py for shared layout helpers.
  5. Read templates/_macros.svg.j2 for the three shared macros: card_container, card_row, chip.

Current SVG infrastructure (svg_render.py)

!grep -n "^def \|^_SVG_RENDERERS\|^_jinja_env\|^_TEMPLATE_DIR\|^_FONTS_DIR\|^_mdi\|^_weather" custom_components/eink_dashboard/svg_render.py

Shared layout helpers (widgets/_helpers.py)

!grep -n "^def \|^_ACTIVE" custom_components/eink_dashboard/widgets/_helpers.py

Existing widget context builders

!grep -rn "^def _build_" custom_components/eink_dashboard/widgets/*.py

SVG macro signatures

!grep -n "macro card_container\|macro card_row\|macro chip\|macro icon_circle" custom_components/eink_dashboard/templates/_macros.svg.j2

WidgetMetrics and _compute_metrics (in render.py)

!grep -n "^class WidgetMetrics" -A 10 custom_components/eink_dashboard/render.py

!grep -n "^def _compute_metrics" -A 12 custom_components/eink_dashboard/render.py

Icon name resolver (in render.py)

!grep -n "^def _device_class_icon" -A 6 custom_components/eink_dashboard/render.py

Current SVG renderer registry

!grep -n "_SVG_RENDERERS" -A 12 custom_components/eink_dashboard/svg_render.py

Imports

Context builders live in widgets/{type}.py and use relative imports. _compute_metrics, _device_class_icon, and _load_font live in render.py. color_to_hex, Widget, DisplayConfig, and constants live in const.py. Layout helpers live in widgets/_helpers.py.

python
from ..const import (
    DEFAULT_CARD_STYLE,
    DEFAULT_ROW_H,
    PADDING,
    DisplayConfig,
    Widget,
    color_to_hex,
)
from ..render import (
    _compute_metrics,
    _device_class_icon,
    _load_font,        # chip width measurement only
)
from ..svg_render import _mdi_svg_filter
from ._helpers import (
    _auto_row_height,
    _card_insets,
    _color_context,
    _fmt,
    _metrics_context,
    _widget_dim,
)

Use _fmt(state_val, config) whenever a context builder formats a numeric entity state for display. This applies locale-aware decimal and thousands separators matching the owner's HA preference. Pass the raw state string — non-numeric strings ("on", "unavailable") are returned unchanged.

_color_context() in widgets/_helpers.py returns {"hex_black": ..., "hex_white": ..., "hex_gray": ...} by calling color_to_hex() on the const.py integer constants. Spread it into the context dict with **_color_context() so templates can use {{ hex_gray }} instead of hardcoded hex literals.

Macro usage notes

  • card_container uses Jinja2 {% call %} syntax. The macro passes (x_off, right_inset) back to the caller body: "border" → (m.padding, m.padding); "left_bar" → (bar_w + m.padding, 0); "none" → (0, 0). Content starts at x_off; content width = w - x_off - right_inset. Always pass display_levels from config.
  • card_row expects all sizes from WidgetMetrics fields plus icon_svg (pre-built SVG string, empty string for letter fallback) and letter (single uppercase char, empty string when icon_svg is set). primary is the entity label; secondary is the state + unit. Pass lpad/rpad derived from _card_insets() to prevent double-padding when a card style already provides insets; use the same values for x1/x2 of any divider <line> between rows. Pass icon_no_circle=True when icon_style == "none" — the macro hides the circle but still renders the icon glyph.
  • chip requires pre-computed w because text width depends on font metrics unavailable in Jinja2. The context builder must compute chip widths using _load_font(size).getlength(text) from PIL — the font object is used only for measurement, not for drawing.
  • Icon filters generate the SVG string in Python. Call _mdi_svg_filter(name, size) in the context builder and pass the result as the icon_svg string to the template. Do NOT call filters from inside templates — pass the pre-built string via context.
  • _device_class_icon(attrs, state_val, domain) returns an MDI icon name without the "mdi:" prefix, or None. Extract domain: entity_id.split(".")[0].

Implementation steps

1. Add to WidgetType enum (if new widget)

In const.py, add the new value to WidgetType. Keep alphabetical order.

2. Create the SVG template

Create custom_components/eink_dashboard/templates/$widget-type.svg.j2.

The template receives a pre-computed context dict from the Python context builder. All layout math (positions, sizes, icon SVG strings, chip widths) is computed in Python. Templates only emit SVG markup.

Widget SVGs are composited onto a white canvas using the alpha channel as a mask (render_dashboard() in render.py). Transparent pixels preserve whatever is already on the canvas (white by default), so most templates do not need a white background rect.

Add a full-viewport white background rect only when the template's rendered geometry is smaller than its SVG viewport — i.e. when content does not fill w × h. The separator is the canonical example: its bar (bar_w × bar_h) is much smaller than the widget viewport, so surrounding transparent area would let earlier widget content bleed through without the rect.

Card-style and chip-style templates omit the rect because the card chrome (via card_container) or chip flow covers the meaningful area, and any remaining transparent edge pixels are harmless (canvas is white).

Card-style template pattern (tile, waste_schedule):

jinja
{%- from "_macros.svg.j2" import card_container, card_row -%}
<svg xmlns="http://www.w3.org/2000/svg"
     width="{{ w }}" height="{{ h }}">
{%- call(x_off, r_inset) card_container(
    x=0, y=0, w=w, h=h,
    card_style=card_style,
    radius=m.radius, border=m.border,
    padding=m.padding, left_bar=m.left_bar,
    display_levels=display_levels) -%}
{%- for row in rows -%}
{{ card_row(
    x=x_off, y=row.y,
    w=w - x_off - r_inset, row_h=row_h,
    padding=m.padding, icon_dia=m.icon_dia,
    inner_gap=m.inner_gap, border=m.border,
    font_primary=m.font_primary,
    font_secondary=m.font_secondary,
    primary=row.primary,
    secondary=row.secondary,
    value=row.value,
    icon_svg=row.icon_svg,
    letter=row.letter,
    lpad=lpad, rpad=rpad) }}
{%- if not loop.last -%}
<line
  x1="{{ x_off + lpad }}"
  y1="{{ row.y + row_h }}"
  x2="{{ w - r_inset - rpad }}"
  y2="{{ row.y + row_h }}"
  stroke="{{ hex_gray }}" stroke-width="{{ m.divider }}"/>
{%- endif -%}
{%- endfor -%}
{%- endcall -%}
</svg>

Chip-style template pattern (device_battery):

jinja
{%- from "_macros.svg.j2" import chip -%}
<svg xmlns="http://www.w3.org/2000/svg"
     width="{{ w }}" height="{{ h }}">
{%- for c in chips -%}
{{ chip(
    x=c.x, y=c.y, w=c.w, h=chip_h,
    text=c.text, border=m.border,
    icon_svg=c.icon_svg,
    inverted=c.inverted) }}
{%- endfor -%}
</svg>

Simple template pattern (separator):

When rendered geometry (e.g. a bar or line) is smaller than the SVG viewport, include a full-size white rect before it so the surrounding area is not transparent:

jinja
<svg xmlns="http://www.w3.org/2000/svg"
     width="{{ w }}" height="{{ h }}">
<rect width="{{ w }}" height="{{ h }}" fill="{{ hex_white }}"/>
<!-- widget-specific SVG elements here -->
</svg>

Template coordinates are relative to origin (0, 0) — the outer composition handles absolute x/y placement on the dashboard.

Show full SKILL.md (548 more words)Show less
3. Write the context builder

Create widgets/$widget-type.py with _build_$widget-type_context(widget, config) -> dict. The context builder:

  • Extracts widget dimensions and config from widget and config
  • Calls _compute_metrics(row_h) to get WidgetMetrics
  • Calls _device_class_icon() to resolve icon names
  • Calls _mdi_svg_filter(name, size) to build icon SVG strings
  • Computes all positions, sizes, and data — returns a plain dict

The template receives only this dict; no layout math happens in Jinja2.

Card-style context builder pattern:

python
def _build_{widget_type}_context(
    widget: Widget,
    config: DisplayConfig,
) -> dict[str, object]:
    """Build template context for $widget-type widget.

    Args:
        widget: Widget config dict with x, w, h, entities,
            card_style, title.
        config: DisplayConfig with states and display_levels.

    Returns:
        Template context dict.
    """
    x = widget.get("x", PADDING)
    w = _widget_dim(widget, "w", config["width"] - x)
    title: str = widget.get("title", "")
    card_style = widget.get(
        "card_style", DEFAULT_CARD_STYLE
    )
    entities = widget.get("entities", [])
    states = config.get("states", {})
    display_levels = config.get("display_levels", 16)

    n = len(entities)
    if n == 0:
        return {
            "w": w,
            "h": _widget_dim(widget, "h", DEFAULT_ROW_H),
            "rows": [],
        }
    # Row-based: auto-size height to fit n rows at
    # DEFAULT_ROW_H px each.  An explicit "h" overrides this.
    h = _widget_dim(widget, "h", _auto_row_height(title, n))
    row_h = h // n
    m = _compute_metrics(row_h)
    x_off, r_inset, bar_width = _card_insets(
        m, card_style, display_levels
    )
    lpad = m.padding if x_off == 0 else 0
    rpad = m.padding if r_inset == 0 else 0

    rows: list[dict[str, object]] = []
    for i, entity_id in enumerate(entities):
        state = states.get(entity_id)
        if state is None:
            continue
        attrs = state.get("attributes", {})
        domain = entity_id.split(".")[0]
        # Resolve icon: device_class → attrs["icon"] → letter.
        icon_name = _device_class_icon(
            attrs, state["state"], domain
        )
        if icon_name is None:
            raw = attrs.get("icon", "")
            if raw.startswith("mdi:"):
                icon_name = raw[4:]
        # Call filter in Python; suppress missing-icon errors.
        icon_svg: markupsafe.Markup | str = ""
        if icon_name:
            with contextlib.suppress(FileNotFoundError):
                icon_svg = _mdi_svg_filter(
                    icon_name, m.icon_inner
                )
        letter = ""
        if not icon_svg:
            friendly = attrs.get("friendly_name", entity_id)
            letter = friendly[:1].upper() if friendly else ""
        unit = attrs.get("unit_of_measurement", "")
        state_val = state["state"]
        rows.append({
            "y": i * row_h,
            "primary": attrs.get(
                "friendly_name", entity_id
            ),
            "secondary": f"{_fmt(state_val, config)}{unit}",
            "value": "",
            "icon_svg": icon_svg,
            "letter": letter,
        })
    return {
        "w": w,
        "h": h,
        "card_style": card_style,
        "display_levels": display_levels,
        "rows": rows,
        "row_h": row_h,
        "lpad": lpad,
        "rpad": rpad,
        **_metrics_context(m),
        **_color_context(),
    }

Chip-style context builder — chip width computation:

Chips require pre-computed widths because Jinja2 cannot measure text. Use a PIL font object (Roboto at round(h * 0.46)) only for measurement — _load_font is LRU-cached, so this is cheap:

python
def _build_{widget_type}_context(
    widget: Widget,
    config: DisplayConfig,
) -> dict[str, object]:
    """Build template context for $widget-type widget."""
    x = widget.get("x", PADDING)
    w = _widget_dim(widget, "w", config["width"] - x)
    h = _widget_dim(widget, "h", DEFAULT_ROW_H)
    entities = widget.get("entities", [])
    states = config.get("states", {})
    m = _compute_metrics(h)

    # pad, icon_gap, and font_sz are chip-specific ratios;
    # icon_dia and icon_inner come from _compute_metrics() so
    # they match card_row at the same height.
    pad = round(h * 0.18)
    icon_gap = round(h * 0.14)
    font_size = max(10, round(h * 0.46))
    font = _load_font(font_size)  # PIL, for width measurement only.

    chip_gap = m.border + 4

    chips: list[dict[str, object]] = []
    for entity_id in entities:
        state = states.get(entity_id)
        if state is None:
            continue
        attrs = state.get("attributes", {})
        domain = entity_id.split(".")[0]
        icon_name = _device_class_icon(
            attrs, state["state"], domain
        )
        if icon_name is None:
            raw = attrs.get("icon", "")
            if raw.startswith("mdi:"):
                icon_name = raw[4:]
        icon_svg: markupsafe.Markup | str = ""
        if icon_name:
            with contextlib.suppress(FileNotFoundError):
                icon_svg = _mdi_svg_filter(
                    icon_name, m.icon_inner
                )
        label = attrs.get("friendly_name", entity_id)
        text_w = round(font.getlength(label))
        icon_w = (m.icon_dia + icon_gap) if icon_svg else 0
        chip_w = pad + icon_w + text_w + pad
        chips.append({
            "text": label,
            "icon_svg": icon_svg,
            "inverted": state["state"] == "on",
            "w": chip_w,
        })

    # Flow layout: pack chips left-to-right with wrapping.
    cx, cy = 0, 0
    for c in chips:
        if cx > 0 and cx + c["w"] > w:
            cx, cy = 0, cy + h + chip_gap
        c["x"] = cx
        c["y"] = cy
        cx += c["w"] + chip_gap

    return {
        "w": w,
        "h": h,
        "m": m,
        "chip_h": h,
        "chips": chips,
    }
4. Re-export from widgets/init.py

In widgets/__init__.py, add the import and __all__ entry:

python
from .{widget_type} import _build_{widget_type}_context

__all__ = [
    ...
    "_build_{widget_type}_context",
]
5. Register in _SVG_RENDERERS

In svg_render.py, import from widgets and add to the _SVG_RENDERERS dict:

python
from .widgets import _build_{widget_type}_context

_SVG_RENDERERS: dict[str, SvgContextFn] = {
    ...
    WidgetType.{WIDGET_TYPE}: _build_{widget_type}_context,
}
6. Run tests
bash
uv run --group lint ruff check . && \
uv run --group format ruff format --check . && \
uv run --group typecheck ty check && \
uv run --group test pytest

All tests must pass. Fix any failures — the tests define correct behavior.

Key constraints

  • No font_size parameter. All sizes derive from w and h via _compute_metrics(). TEXT widget is the only exception.
  • Chip proportions from WidgetMetrics. icon_dia and icon_inner come from _compute_metrics(chip_h) — do not derive them from inline ratios or _CHIP_*_RATIO constants (removed in step 0.5). pad, icon_gap, and font_sz are chip-specific and have no WidgetMetrics field.
  • Use shared macros. Do not duplicate card/chip/row SVG markup. Use card_container, card_row, chip from _macros.svg.j2.
  • All layout math in Python. Templates receive final coordinates and data. No arithmetic or conditionals in Jinja2 beyond what the macros already compute internally.
  • White background rect. Only add <rect width="{{ w }}" height="{{ h }}" fill="{{ hex_white }}"/> when the template's rendered geometry is smaller than its SVG viewport (e.g. separator bar). Card-style and chip-style templates omit it — the canvas is pre-filled white and alpha masking handles compositing.
  • Missing state = skip. If states.get(entity_id) returns None, skip the entity and continue. Do not crash.
  • Icon inlining via filter functions. Call _mdi_svg_filter(name, size) or _weather_svg_filter(condition, size) in the context builder and pass the returned string as icon_svg.
  • Font references in SVG. Use font-family="Roboto" and font-weight="500" for Roboto Medium. No _load_font() calls in templates.
  • Template coordinates are relative. Compute row y positions relative to 0, not to the widget's absolute position on the dashboard. Outer composition handles x/y placement.
  • Line length: 79 chars. Applies to Python, Jinja2 templates, and docstrings.

Key references

  • SVG macros: card_container, card_row, chip in templates/_macros.svg.j2

  • SVG pipeline: _jinja_env, _svg_to_png(), _mdi_svg_filter(), _weather_svg_filter() in svg_render.py

  • Layout metrics: _compute_metrics(), WidgetMetrics in render.py

  • Icon name resolution: _device_class_icon() in render.py

  • Colors: COLOR_BLACK=0, COLOR_WHITE=255, COLOR_GRAY=120, COLOR_LIGHT_GRAY=180 in const.py

  • Layout helpers: _widget_dim, _auto_row_height, _card_insets, _metrics_context, _color_context, _fmt, _entity_info_context, _title_layout in widgets/_helpers.py

  • Constants: DEFAULT_ROW_H, Widget, DisplayConfig, color_to_hex in const.py

  • Icon style pattern: _ACTIVE_STATES frozenset (in widgets/_helpers.py) determines active vs inactive state; use contextlib.suppress(FileNotFoundError) around every _mdi_svg_filter() call

  • Custom icon circle: When a widget renders its own icon circle (not via the card_row macro), use the icon_circle macro from _macros.svg.j2 — it handles filled/outlined/no-circle variants and glyph/letter rendering. The context builder must pass icon_cx, icon_cy, icon_r, icon_glyph_x, icon_glyph_y, icon_stroke_w, icon_fill, icon_color, icon_svg, icon_outline, icon_no_circle, letter, and letter_font_sz to the template. Widen the outline stroke on 2-level displays to avoid dithering — compute this in the context builder and pass it as icon_stroke_w:

    python
    # Widen the outline stroke on 2-level displays.
    icon_stroke_w = (
        m.border * 3 if display_levels <= 2 else m.border
    )

    The card_row macro handles this widening internally for row icons. Only apply it explicitly when using icon_circle directly.

© 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 of cryptomilk/hass-eink-dashboard.

Open the folder on GitHubat commit 6142841

Compare with similar skills

Implement Widget 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 compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Implement Widget this skillcryptomilk/hass-eink-dashboard116—~4.8kAutomated safety check: PassApache-2.0
Wobbling Ty Constraint Orderastral-sh/ruff50k—~838Automated safety check: PassMIT
Test Designjjjkkkjjj/Matft147—~2kAutomated safety check: PassBSD-3-Clause
Python Testingaffaan-m/ECC275k6 repos~4.7kAutomated safety check: PassMIT
Python Testingaffaan-m/ECC275k3 repos~4.2kAutomated safety check: PassMIT
Agent-Core Python TestingopenJiuwen-ai/agent-core442—~2.3kAutomated safety check: PassApache-2.0

Similar skills

  • Official

    A skill your agent uses when a user asks to wobble ty constraint ordering, check constraint-set or TDD ordering determinism, test reversed constraint/typevar IDs, or investigate nondeterministic ty…

    50k GitHub stars~838 tokensUpdated today
    Testing & QAAuto-check passed
  • Test Design

    jjjkkkjjj/Matft

    Procedure for designing and writing Matft's XCTest cases with high coverage — boundary values, dtypes, memory layouts, NaN/inf, empty arrays, broadcasting, platform differences, performance and…

    147 GitHub stars~2k tokensUpdated 10 days ago
    Testing & QAAuto-check passed
  • Python Testing

    affaan-m/ECC

    Python testing strategies using pytest, TDD methodology, fixtures, mocking, parametrization, and coverage requirements.

    275k GitHub starsUsed in 6 repos~4.7k tokens
    Testing & QAAuto-check passed
  • Python Testing

    affaan-m/ECC

    使用pytest的Python测试策略,包括TDD方法、夹具、模拟、参数化和覆盖率要求. An agent skill from affaan-m/ECC.

    275k GitHub starsUsed in 3 repos~4.2k tokens
    Testing & QAAuto-check passed
  • Agent-Core Python Testing

    openJiuwen-ai/agent-core

    Pytest patterns for the agent-core codebase: a red-green-refactor workflow, conftest fixtures, custom marks, monkeypatch and patch mocking, and async tests.

    442 GitHub stars~2.3k tokensUpdated today
    Testing & QAAuto-check passed
  • Python Testing Patterns

    jh941213/my-cc-harness

    Implement comprehensive testing strategies with pytest, fixtures, mocking, and test-driven development.

    126 GitHub starsUsed in 17 repos~5.4k tokens
    Testing & QAAuto-check passed

More from cryptomilk/hass-eink-dashboard

  • Implement Widget Frontend

    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…

    116 GitHub stars~3.3k tokensUpdated yesterday
    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 yesterday
    Auto-check passed

Categories

Questions about Implement Widget

What does Implement Widget do?

Implement a widget's SVG template and Python context builder. Implement Widget is an agent skill from cryptomilk/hass-eink-dashboard. Implement a widget's SVG template and Python context builder.

When should I use Implement Widget?

Implement Widget fits situations like: tasks that involve Test-driven development.

How do I install Implement Widget in Claude Code?

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

How do I install Implement Widget in Codex?

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

Can I use Implement Widget 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 -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, .gemini/skills/implement-widget, .github/skills/implement-widget and .opencode/skills/implement-widget in your project.

What does Implement Widget need to run?

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

Does Implement Widget access the network?

SKILL.md names 1 domain. In commands or code: w3.org; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.

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

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

About 4.8k tokens (SKILL.md is roughly 19k 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?

Skills that share tags, products or a category with Implement Widget: Wobbling Ty Constraint Order (astral-sh/ruff, 50k stars), Test Design (jjjkkkjjj/Matft, 147 stars), Python Testing (affaan-m/ECC, 275k stars) and Python Testing (affaan-m/ECC, 275k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Implement Widget?

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.