Kida 0.2.4
Composition API, inherited blocks, slot context inheritance, string concatenation
Status: Released March 6, 2026.
This release adds the composition API for framework integration, inherited block
support inrender_block(), slot context inheritance for layout chains, and
polymorphic string concatenation.
Highlights
- Composition API —
validate_block_exists(),get_structure(), andTemplateStructureManifestfor Chirp, Dori, and custom adapters. - Inherited blocks —
render_block()andlist_blocks()now include parent blocks; rendersidebarfrom a child that extends a base. - Slot context inheritance —
caller()in nested def/call/slot chains correctly resolves to the def's caller (Dori/chirpui layout support). - String concatenation — Polymorphic
+: numeric add when both operands are numeric, else string concat. - Bytecode cache fix — Atomic write with unique temp files prevents concurrent writer races.
Added
Composition API
Newkida.compositionmodule for frameworks that compose templates via block rendering:
from kida import Environment, FileSystemLoader
from kida.composition import validate_block_exists, get_structure
env = Environment(loader=FileSystemLoader("templates/"))
# Validate before render_block
if validate_block_exists(env, "page.html", "content"):
html = env.get_template("page.html").render_block("content", ...)
# Lightweight structure manifest for composition planning
struct = get_structure(env, "page.html")
if struct and "page_root" in struct.block_names:
...
Inherited Block Support
render_block() and list_blocks()now include blocks inherited from parent templates:
# Child extends base.html which defines {% block sidebar %}
template = env.get_template("skills/page.html")
html = template.render_block("sidebar", site=site) # Works — sidebar from parent
blocks = template.list_blocks() # Includes inherited blocks
Slot Context Inheritance
Nested{% def %} / {% call %} / {% slot %} chains now correctly scope caller().
When a slot body containscaller(), it resolves to the def's caller, not an inner wrapper.
Enables layout chains like Dori and ChirpUI.
String Concatenation
The+operator is now polymorphic:
- Both operands numeric → addition:
{{ 1 + 2 }}→3 - Otherwise → string concatenation:
{{ "Hello " + name }}→"Hello World"
String Escape Decoding
String literals now decode Python-style escapes:\n, \t, \r, \\, \', \",
\uXXXX, \UXXXXXXXX. Invalid escapes raise LexerErrorwith location.
Parser Improvements
- Error codes —
ParseErrorcarriesErrorCode(e.g.UNEXPECTED_TOKEN,UNCLOSED_BLOCK) with docs URLs. - Token display names —
TokenType.display_namefor human-readable error messages (e.g. "identifier" instead of "name"). - Hyphen detection —
{% block foo-bar %}and{% fragment foo-bar %}are rejected with a suggestion to use underscores.
Framework Integration Docs
New Framework Integration guide covers block rendering, introspection, and composition for Chirp, Bengal, and Dori.
Changed
- Async API —
Template.render_async()is explicitly a thread-pool wrapper for sync templates; async templates should userender_stream_async(). - Cache TTL —
{% cache key, ttl=... %}enforces per-fragment TTL (numeric seconds ors/m/h/dsuffixes).
Fixed
- Bytecode cache write race —
BytecodeCache.set()uses unique temp files andos.replace()for atomic replacement, preventing concurrent writer collisions.
Upgrade Notes
- No breaking changes — Existing templates continue to work.
- Composition API — Optional; add
validate_block_exists()orget_structure()where you compose templates programmatically. - Block names with hyphens — Use underscores instead (
foo_barnotfoo-bar).