Classes
Severity
0
▼
Severity of a contract validation issue.
Severity
0
▼
Severity of a contract validation issue.
ContractIssue
6
▼
A single validation issue found during contract checking.
ContractIssue
6
▼
A single validation issue found during contract checking.
Attributes
| Name | Type | Description |
|---|---|---|
severity |
Severity
|
— |
category |
str
|
— |
message |
str
|
— |
template |
str | None
|
— |
route |
str | None
|
— |
details |
str | None
|
— |
FragmentContract
2
▼
Declares that a route returns a specific template fragment.
Used for documentation and validation.…
FragmentContract
2
▼
Declares that a route returns a specific template fragment.
Used for documentation and validation. Chirp verifies at freeze time that the template and block exist.
Attributes
| Name | Type | Description |
|---|---|---|
template |
str
|
— |
block |
str
|
— |
SSEContract
2
▼
Declares the event types an SSE endpoint emits.
Used for documentation and validation. Optionally…
SSEContract
2
▼
Declares the event types an SSE endpoint emits.
Used for documentation and validation. Optionally declares
fragments that the SSE stream yields, soapp.check()can
verify the templates/blocks exist.
Attributes
| Name | Type | Description |
|---|---|---|
event_types |
frozenset[str]
|
— |
fragments |
tuple[FragmentContract, ...]
|
— |
FormContract
3
▼
Declares which dataclass a route binds form data to.
Used by ``app.check()`` to verify that ``<inp…
FormContract
3
▼
Declares which dataclass a route binds form data to.
Used byapp.check() to verify that <input name="...">,
<select name="...">, and <textarea name="...">fields in the
template match the dataclass fields expected by the handler.
Attributes
| Name | Type | Description |
|---|---|---|
datacls |
type
|
— |
template |
str
|
— |
block |
str | None
|
— |
RouteContract
3
▼
Full contract metadata for a route.
Attached to routes via the ``contract`` parameter on ``@app.ro…
RouteContract
3
▼
Full contract metadata for a route.
Attached to routes via thecontract parameter on @app.route().
Attributes
| Name | Type | Description |
|---|---|---|
returns |
FragmentContract | SSEContract | None
|
— |
form |
FormContract | None
|
— |
description |
str
|
— |
CheckResult
14
▼
Result of a hypermedia surface check.
CheckResult
14
▼
Result of a hypermedia surface check.
Attributes
| Name | Type | Description |
|---|---|---|
issues |
list[ContractIssue]
|
— |
routes_checked |
int
|
— |
templates_scanned |
int
|
— |
targets_found |
int
|
— |
hx_targets_validated |
int
|
— |
dead_templates_found |
int
|
— |
sse_fragments_validated |
int
|
— |
forms_validated |
int
|
— |
component_calls_validated |
int
|
— |
page_context_warnings |
int
|
— |
Methods
errors
0
list[ContractIssue]
▼
property
errors
0
list[ContractIssue]
▼
def errors(self) -> list[ContractIssue]
Returns
list[ContractIssue]
warnings
0
list[ContractIssue]
▼
property
warnings
0
list[ContractIssue]
▼
def warnings(self) -> list[ContractIssue]
Returns
list[ContractIssue]
ok
0
bool
▼
property
ok
0
bool
▼
def ok(self) -> bool
Returns
bool
summary
0
str
▼
Human-readable summary.
summary
0
str
▼
def summary(self) -> str
Returns
str
Functions
_extract_targets_from_source
1
list[tuple[str, str]]
▼
Extract (attr_name, url) pairs from template source text.
Scans raw template s…
_extract_targets_from_source
1
list[tuple[str, str]]
▼
def _extract_targets_from_source(source: str) -> list[tuple[str, str]]
Extract (attr_name, url) pairs from template source text.
Scans raw template source for htmx URL attributes and form actions. This catches static URLs in HTML; dynamic URLs (from template expressions) are not captured and should be validated separately.
Parameters
| Name | Type | Description |
|---|---|---|
source |
str |
Returns
list[tuple[str, str]]
_extract_hx_target_selectors
1
list[str]
▼
Extract ``hx-target`` values from template source.
Returns raw selector string…
_extract_hx_target_selectors
1
list[str]
▼
def _extract_hx_target_selectors(source: str) -> list[str]
Extracthx-targetvalues from template source.
Returns raw selector strings, skipping template expressions.
Parameters
| Name | Type | Description |
|---|---|---|
source |
str |
Returns
list[str]
_extract_static_ids
1
set[str]
▼
Extract all static ``id`` attribute values from template HTML.
Skips IDs conta…
_extract_static_ids
1
set[str]
▼
def _extract_static_ids(source: str) -> set[str]
Extract all staticidattribute values from template HTML.
Skips IDs containing template expressions (these are dynamic and cannot be validated at compile time).
Parameters
| Name | Type | Description |
|---|---|---|
source |
str |
Returns
set[str]
_extract_template_references
1
set[str]
▼
Extract template names referenced via Jinja tags.
Catches static references fr…
_extract_template_references
1
set[str]
▼
def _extract_template_references(source: str) -> set[str]
Extract template names referenced via Jinja tags.
Catches static references from{% extends %}, {% include %},
{% from %}, and {% import %}. Dynamic expressions
(e.g.{% include variable %}) are not captured.
Parameters
| Name | Type | Description |
|---|---|---|
source |
str |
Returns
set[str]
_extract_form_field_names
1
set[str]
▼
Extract ``name`` attribute values from form fields in template HTML.
Scans for…
_extract_form_field_names
1
set[str]
▼
def _extract_form_field_names(source: str) -> set[str]
Extractnameattribute values from form fields in template HTML.
Scans for<input>, <select>, and <textarea>elements.
Skips template expressions and framework-injected fields like
CSRF tokens.
Parameters
| Name | Type | Description |
|---|---|---|
source |
str |
Returns
set[str]
_closest_field
3
str | None
▼
Find the closest field name by edit distance, or ``None``.
_closest_field
3
str | None
▼
def _closest_field(target: str, fields: set[str], *, max_dist: int = 2) -> str | None
Parameters
| Name | Type | Description |
|---|---|---|
target |
str |
|
fields |
set[str] |
|
max_dist |
int |
Default:2
|
Returns
str | None
_edit_distance
2
int
▼
Levenshtein distance between two strings.
_edit_distance
2
int
▼
def _edit_distance(a: str, b: str) -> int
Parameters
| Name | Type | Description |
|---|---|---|
a |
str |
|
b |
str |
Returns
int
_closest_id
3
str | None
▼
Find the closest ID by edit distance, or ``None`` if nothing is close.
_closest_id
3
str | None
▼
def _closest_id(target: str, ids: set[str], *, max_dist: int = 3) -> str | None
Parameters
| Name | Type | Description |
|---|---|---|
target |
str |
|
ids |
set[str] |
|
max_dist |
int |
Default:3
|
Returns
str | None
_check_hx_target_selectors
2
tuple[list[ContractIssue…
▼
Validate ``hx-target`` selectors against the pool of static element IDs.
Only …
_check_hx_target_selectors
2
tuple[list[ContractIssue…
▼
def _check_hx_target_selectors(template_sources: dict[str, str], all_ids: set[str]) -> tuple[list[ContractIssue], int]
Validatehx-targetselectors against the pool of static element IDs.
Only validates simple#id selectors. Extended selectors (closest,
find, next, previous) and special keywords (this, body)
are skipped — they can't be validated statically.
Parameters
| Name | Type | Description |
|---|---|---|
template_sources |
dict[str, str] |
|
all_ids |
set[str] |
Returns
tuple[list[ContractIssue], int]
_check_hx_indicator_selectors
2
list[ContractIssue]
▼
Validate ``hx-indicator`` selectors against the pool of static element IDs.
On…
_check_hx_indicator_selectors
2
list[ContractIssue]
▼
def _check_hx_indicator_selectors(template_sources: dict[str, str], all_ids: set[str]) -> list[ContractIssue]
Validatehx-indicatorselectors against the pool of static element IDs.
Only validates simple#id selectors. Extended selectors (closest,
find, inherit) and comma-separated multiples are skipped.
Parameters
| Name | Type | Description |
|---|---|---|
template_sources |
dict[str, str] |
|
all_ids |
set[str] |
Returns
list[ContractIssue]
_check_hx_boost
1
list[ContractIssue]
▼
Validate ``hx-boost`` values are ``"true"`` or ``"false"``.
htmx silently trea…
_check_hx_boost
1
list[ContractIssue]
▼
def _check_hx_boost(template_sources: dict[str, str]) -> list[ContractIssue]
Validatehx-boost values are "true" or "false".
htmx silently treats any non-"true"value as false, which is
confusing. Chirp catches this at compile time.
Parameters
| Name | Type | Description |
|---|---|---|
template_sources |
dict[str, str] |
Returns
list[ContractIssue]
_check_sse_self_swap
1
list[ContractIssue]
▼
Error when ``sse-swap`` is on the same element as ``sse-connect``.
htmx's SSE …
_check_sse_self_swap
1
list[ContractIssue]
▼
def _check_sse_self_swap(template_sources: dict[str, str]) -> list[ContractIssue]
Error whensse-swap is on the same element as sse-connect.
htmx's SSE extension usesquerySelectorAll on the sse-connect
element to find swap targets.querySelectorAllnever includes
the root element itself, sosse-swapon the same element is a
silent no-op — events arrive but nothing is swapped.
The fix is to movesse-swapto a child element.
Parameters
| Name | Type | Description |
|---|---|---|
template_sources |
dict[str, str] |
Returns
list[ContractIssue]
_check_sse_connect_scope
2
list[ContractIssue]
▼
Warn when ``sse-connect`` is inside a broad ``hx-target`` scope.
If a layout s…
_check_sse_connect_scope
2
list[ContractIssue]
▼
def _check_sse_connect_scope(template_sources: dict[str, str], broad_targets: set[str]) -> list[ContractIssue]
Warn whensse-connect is inside a broad hx-targetscope.
If a layout setshx-target="#app-content"and an SSE container
does not usehx-disinheritto break inheritance, every
sse-swapdescendant inherits the broad target and SSE fragments
replace the wrong region.
The fix ishx-disinherit="hx-target hx-swap"on the
sse-connectelement.
Parameters
| Name | Type | Description |
|---|---|---|
template_sources |
dict[str, str] |
|
broad_targets |
set[str] |
Returns
list[ContractIssue]
_collect_broad_targets
1
set[str]
▼
Collect broad inherited ``hx-target`` values from layout-level elements.
Retur…
_collect_broad_targets
1
set[str]
▼
def _collect_broad_targets(template_sources: dict[str, str]) -> set[str]
Collect broad inheritedhx-targetvalues from layout-level elements.
Returns a set of"#target (template)"strings. Broad targets
are those on<body>, <main>, or elements with
hx-boost="true"— scopes likely to be inherited by many
descendants.
Parameters
| Name | Type | Description |
|---|---|---|
template_sources |
dict[str, str] |
Returns
set[str]
_check_swap_safety
1
list[ContractIssue]
▼
Warn on mutation tags that may inherit broad container targets.
This catches a…
_check_swap_safety
1
list[ContractIssue]
▼
def _check_swap_safety(template_sources: dict[str, str]) -> list[ContractIssue]
Warn on mutation tags that may inherit broad container targets.
This catches a common htmx footgun:
- a layout-level element sets a broad
hx-target="#app-content" - a mutating request does not set its own target
- a fragment response can replace the whole container accidentally.
Parameters
| Name | Type | Description |
|---|---|---|
template_sources |
dict[str, str] |
Returns
list[ContractIssue]
_normalize_sse_url
1
str
▼
Normalize a ``sse-connect`` URL for route matching.
Jinja template expressions…
_normalize_sse_url
1
str
▼
def _normalize_sse_url(url: str) -> str
Normalize asse-connectURL for route matching.
Jinja template expressions like{{ doc.id }}are replaced with
__p__ so that _path_matches_routetreats them as concrete
segments that match{param}route patterns.
Parameters
| Name | Type | Description |
|---|---|---|
url |
str |
Returns
str
_extract_sse_swap_values
1
set[str]
▼
Extract all ``sse-swap`` event names from a template source.
_extract_sse_swap_values
1
set[str]
▼
def _extract_sse_swap_values(source: str) -> set[str]
Parameters
| Name | Type | Description |
|---|---|---|
source |
str |
Returns
set[str]
_check_sse_event_crossref
2
list[ContractIssue]
▼
Cross-reference ``sse-swap`` values against ``SSEContract.event_types``.
For e…
_check_sse_event_crossref
2
list[ContractIssue]
▼
def _check_sse_event_crossref(template_sources: dict[str, str], router: Router) -> list[ContractIssue]
Cross-referencesse-swap values against SSEContract.event_types.
For each template withsse-connect, match the URL to a route.
If the route declaresSSEContract(event_types=...), verify that:
- Every
sse-swapvalue in the template exists inevent_types(template listens for events the stream never emits). - Every
event_typesentry has a matchingsse-swapin the template (stream emits events no template listens for).
Parameters
| Name | Type | Description |
|---|---|---|
template_sources |
dict[str, str] |
|
router |
Router |
Returns
list[ContractIssue]
_check_accessibility
2
list[ContractIssue]
▼
Check for htmx URL attributes on non-interactive elements.
Warns when ``hx-get…
_check_accessibility
2
list[ContractIssue]
▼
def _check_accessibility(source: str, template_name: str) -> list[ContractIssue]
Check for htmx URL attributes on non-interactive elements.
Warns whenhx-get, hx-post, etc. appear on elements like
<div> or <span> without role or tabindexattributes
that would make them accessible to keyboard and screen reader users.
Parameters
| Name | Type | Description |
|---|---|---|
source |
str |
|
template_name |
str |
Returns
list[ContractIssue]
_attr_to_method
1
str
▼
Map an htmx attribute name to its HTTP method.
_attr_to_method
1
str
▼
def _attr_to_method(attr: str) -> str
Parameters
| Name | Type | Description |
|---|---|---|
attr |
str |
Returns
str
_collect_route_paths
1
dict[str, frozenset[str]]
▼
Build a mapping of path → allowed methods from the router.
Returns a dict wher…
_collect_route_paths
1
dict[str, frozenset[str]]
▼
def _collect_route_paths(router: Router) -> dict[str, frozenset[str]]
Build a mapping of path → allowed methods from the router.
Returns a dict where keys are route path patterns and values are sets of allowed HTTP methods. Multiple routes on the same path have their methods merged.
Parameters
| Name | Type | Description |
|---|---|---|
router |
Router |
Returns
dict[str, frozenset[str]]
_path_matches_route
2
bool
▼
Check if a URL could match a route pattern.
Handles static paths exactly and p…
_path_matches_route
2
bool
▼
def _path_matches_route(url: str, route_path: str) -> bool
Check if a URL could match a route pattern.
Handles static paths exactly and parameterized paths approximately
(any path segment can match a{param}segment).
Parameters
| Name | Type | Description |
|---|---|---|
url |
str |
|
route_path |
str |
Returns
bool
check_hypermedia_surface
1
CheckResult
▼
Validate the hypermedia surface of a Chirp application.
**Checks:**
1. **Fragm…
check_hypermedia_surface
1
CheckResult
▼
def check_hypermedia_surface(app: App) -> CheckResult
Validate the hypermedia surface of a Chirp application.
Checks:
- Fragment references: Every route with a FragmentContract references a template and block that exist.
- SSE fragment references: SSEContract fragments resolve to valid templates and blocks.
- htmx URL targets: Every
hx-get,hx-post, etc. in template HTML resolves to a registered route with the correct method. - hx-target selectors: Every
hx-target="#id"in template HTML references an element ID that exists somewhere in the template tree (warning — IDs may come from dynamic expressions or JS). - Accessibility: htmx URL attributes on non-interactive elements
(
<div>,<span>, etc.) withoutroleortabindex(warning, not error). - Form field validation: Routes with FormContract have template fields that match the dataclass fields.
- Orphan routes: Routes that are never referenced from templates (info, not error).
- Dead templates: Templates not referenced by any route or other template (info, not error).
- Page context gaps: Routes with FragmentContract where the full template requires variables the target block does not — a sign that full-page Page renders may crash at runtime (warning).
- Component call validation:
{% call %}sites match{% def %}signatures (requires kida typed def support).
Parameters
| Name | Type | Description |
|---|---|---|
app |
App |
A frozen Chirp application. |
Returns
CheckResult
_check_inline_templates
2
None
▼
Warn about routes whose return annotation includes InlineTemplate.
InlineTempl…
_check_inline_templates
2
None
▼
def _check_inline_templates(router: Router, result: CheckResult) -> None
Warn about routes whose return annotation includes InlineTemplate.
InlineTemplate is a prototyping shortcut and should be replaced with file-based templates before shipping to production.
Parameters
| Name | Type | Description |
|---|---|---|
router |
Router |
|
result |
CheckResult |
_load_template_sources
1
dict[str, str]
▼
Load all template sources from the kida environment's loader.
Returns a dict o…
_load_template_sources
1
dict[str, str]
▼
def _load_template_sources(kida_env: Any) -> dict[str, str]
Load all template sources from the kida environment's loader.
Returns a dict of template_name → source_text.
Parameters
| Name | Type | Description |
|---|---|---|
kida_env |
Any |
Returns
dict[str, str]
contract
3
Any
▼
Attach a contract to a route handler.
Usage::
@app.route("/search", metho…
contract
3
Any
▼
def contract(returns: FragmentContract | SSEContract | None = None, *, form: FormContract | None = None, description: str = '') -> Any
Attach a contract to a route handler.
Usage::
@app.route("/search", methods=["POST"])
@contract(returns=FragmentContract("search.html", "results"))
async def search(request):
...
Parameters
| Name | Type | Description |
|---|---|---|
returns |
FragmentContract | SSEContract | None |
Default:None
|
form |
FormContract | None |
Default:None
|
description |
str |
Default:''
|
Returns
Any