Skip to content

lbliii/kida

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

369 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

)彡 Kida

PyPI version Build Status Python 3.14+ License: MIT

Pure-Python components for HTML, Markdown, terminal output, and CI reports.

Kida gives Python templates a real component model: typed props, named slots, static call-site validation, scoped state, error boundaries, and free-threaded rendering on Python 3.14t. No JavaScript build step. No runtime dependencies.

Quick Start

pip install kida-templates
{% def card(title: str, variant: str = "default") %}
<article class="card card--{{ variant }}">
  <h3>{{ title }}</h3>
  {% if has_slot("header_actions") %}
  <div class="actions">{% slot header_actions %}</div>
  {% endif %}
  <div class="body">{% slot %}</div>
</article>
{% enddef %}

{% call card("Settings", variant="elevated") %}
  {% slot header_actions %}<button>Save</button>{% end %}
  <p>Configure your preferences.</p>
{% endcall %}
from kida import Environment, FileSystemLoader

env = Environment(loader=FileSystemLoader("templates/"))
template = env.get_template("page.html")
html = template.render(title="Hello")

Static Validation

Kida catches component mistakes before a user sees a page, report, or terminal screen.

{% def badge(count: int, label: str) %}
<span class="badge">{{ count }} {{ label }}</span>
{% enddef %}

{{ badge(count="five", lable="Messages") }}
kida check templates/ --strict --validate-calls
templates/dashboard.html:5: K-CMP-001: Call to 'badge' — unknown params: lable; missing required: label
templates/dashboard.html:5: K-CMP-002: type: badge() param 'count' expects int, got str ('five')

Validation catches unknown params, missing required params, and literal type mismatches at check time.

Use Kida For

Surface What Kida gives you
Web apps Component templates for Flask, FastAPI, Django, Chirp, and Bengal
Static sites Reusable layouts, slots, typed content components, and scoped state
CI reports Markdown step summaries and PR comments from pytest, coverage, ruff, ty, and more
Terminal tools ANSI-aware tables, badges, panels, dashboards, and progress output
Framework tooling Template metadata, block rendering, component discovery, and dependency analysis

Component Model

Kida brings frontend-style composition to ordinary Python templates.

Feature Syntax
Typed props {% def card(title: str, count: int = 0) %}
Named slots {% slot header %} / {% slot %} (default)
Conditional slots has_slot("footer")
Scoped slots (data up) {% slot row let:item=item %}
Slot forwarding {% yield name %}
Context propagation {% provide theme = "dark" %} / consume("theme")
Error boundaries {% try %}...{% fallback error %}...{% endtry %}
Co-located styles {% push "styles" %} / {% stack "styles" %}
Pattern matching {% match status %}{% case "active" %}...{% endmatch %}
Block-scoped variables {% set %} (scoped) / {% let %} (template-wide) / {% export %}

Component Discovery

kida components templates/

# components/card.html
#   def card(title: str, subtitle: str | None = None)
#     slots: header_actions, footer
#
# components/button.html
#   def button(label: str, variant: str = "primary")
#     slots: (none)
#
# 2 component(s) found.

Introspection API

template = env.get_template("components/card.html")
meta = template.def_metadata()
card = meta["card"]
print(card.params)           # (DefParamInfo(name='title', annotation='str', ...), ...)
print(card.slots)            # ('header_actions', 'footer')
print(card.has_default_slot) # True

Render Surfaces

One template syntax can target HTML, terminal output, Markdown, and CI reports.

HTML
from kida import Environment, FileSystemLoader

env = Environment(loader=FileSystemLoader("templates/"))
html = env.get_template("page.html").render(title="Hello")
Terminal
from kida.terminal import terminal_env

env = terminal_env()
template = env.from_string("""
{{ "Deploy Status" | bold | cyan }}
{{ hr(40) }}
{% for svc in services %}
{{ svc.name | pad(20) }}{{ svc.status | badge }}
{% endfor %}
""")
print(template.render(services=[
    {"name": "api", "status": "pass"},
    {"name": "worker", "status": "fail"},
]))
Markdown
from kida.markdown import markdown_env

env = markdown_env()
md = env.from_string("# {{ title }}\n\n{{ body }}").render(
    title="Report", body="All tests passed."
)
CI Reports (GitHub Action)

Turn pytest, coverage, ruff, and other tool output into step summaries and PR comments.

- uses: lbliii/kida@v0.7.0
  with:
    template: pytest
    data: results.xml
    data-format: junit-xml
    post-to: step-summary,pr-comment

Built-in templates for pytest, coverage, ruff, ty, jest, gotest, and sarif. Full action docs →

Designed For Python 3.14t

Kida does not rely on the GIL for correctness. Templates compile to immutable Python code, render state lives in ContextVar, and environment mutation uses copy-on-write patterns. Public APIs are safe under PYTHON_GIL=0 on free-threaded Python 3.14t.

Why Kida?

Traditional templates Kida
Typed parameters Usually no param: str | None
Named slots Usually no {% slot name %}
Scoped variables Often leak or surprise set is block-scoped
Context propagation Prop drilling provide / consume
Error boundaries Rare {% try %}...{% fallback %}
Component styles Disconnected CSS files {% push "styles" %}
Call-site validation Runtime errors Compile-time checks
Component discovery Read every file kida components CLI
Block rendering Framework-specific render_block() for HTMX partials
Streaming Varies render_stream() and render_stream_async()
Free-threading Not usually designed for it GIL-free on Python 3.14t

Advanced Features

Template Inheritance
{# base.html #}
<!DOCTYPE html>
<html>
<body>{% block content %}{% endblock %}</body>
</html>

{# page.html #}
{% extends "base.html" %}
{% block content %}<h1>{{ title }}</h1>{% endblock %}
Regions (Parameterized Blocks)
{% region sidebar(current_path="/") %}
  <nav>{{ current_path }}</nav>
{% endregion %}

{{ sidebar(current_path="/about") }}

Regions are blocks (for render_block()) and callables (for inline use). Ideal for HTMX OOB swaps.

Pattern Matching & Null Safety
{% match status %}
{% case "active" %}Active{% case "pending" %}Pending{% case _ %}Unknown
{% endmatch %}

{{ user.nickname ?? user.name ?? "Anonymous" }}
{{ config?.database?.host }}
{{ data ?|> parse ?|> validate ?|> render }}
Streaming & Block Rendering
# Stream chunks as they render
for chunk in template.render_stream(items=large_list):
    response.write(chunk)

# Render a single block (HTMX partials)
html = template.render_block("content", title="Hello")

# Compose layouts with pre-rendered blocks
html = layout.render_with_blocks({"content": inner_html}, title="Page")
Compile-Time Optimization
template = env.from_string(source, static_context={
    "site": site_config, "settings": app_settings,
})
html = template.render(page_title="Home", items=page_items)

Pure filters can be evaluated at compile time, dead branches can be removed, and small components with constant args can be inlined. Use kida render template.html --explain to see active optimizations.

Framework Integration
# Flask
from kida.contrib.flask import KidaFlask
kida = KidaFlask(app)

# Starlette / FastAPI
from kida.contrib.starlette import KidaStarlette
templates = KidaStarlette(directory="templates")

# Django
TEMPLATES = [{"BACKEND": "kida.contrib.django.KidaDjango", ...}]
CLI
kida render template.txt --data context.json
kida check templates/ --validate-calls --a11y --typed
kida components templates/ --json
kida fmt templates/
kida extract templates/ -o messages.pot

Status

Kida is pre-1.0 and used by Bengal and Chirp. The API can still move, but the core design goals are stable: pure Python, static validation, render-surface parity, and free-threaded safety.

Upgrading

Moving from 0.6.x? See the Upgrade to 0.7 tutorial for the strict_undefined=True migration patterns.

Moving from 0.7.x? See the Upgrade to 0.8 tutorial for the Mapping behavior change in null-safe access (?. and ?[...]).

The Bengal Ecosystem

Kida is part of a pure-Python stack built for 3.14t free-threading.

ᓚᘏᗢ Bengal Static site generator Docs
∿∿ Purr Content runtime
⌁⌁ Chirp Web framework Docs
=^..^= Pounce ASGI server Docs
)彡 Kida Component framework Docs
ฅᨐฅ Patitas Markdown parser Docs
⌾⌾⌾ Rosettes Syntax highlighter Docs
ᓃ‿ᓃ Milo Terminal UI framework Docs

License

MIT License — see LICENSE for details.

About

)彡 Kida — Free-threading template engine for Python 3.14+ with AST compilation and modern syntax

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Contributors

Languages