skaldr
Turn one YAML file into one polished, self-contained HTML report page. You describe what the report says — findings, tables, a pipeline, the numbers — and skaldr owns how it looks: layout, spacing, colour, light/dark, all decided once, here. No design work, no CSS, no drift.
See it → sales pipeline ·
warehouse count
(rendered from examples/sales-pipeline.yaml and
data/example.yaml).
Install
brew install alex-yanchenko/tap/skaldr # recommended (macOS/Linux)
uv tool install skaldr # or, with uv
pipx install skaldr # or, with pipx
All three put a skaldr command on your PATH. (From a checkout, uv run skaldr … works without
installing.)
Use
skaldr report.yaml # → out/report.html
skaldr report.yaml -o review.html # choose the output path
skaldr report.yaml --watch -o review.html # re-render on every save (live edit→preview; Ctrl-C to stop)
skaldr report.yaml --pdf report.pdf # a ready-to-share PDF (drives a headless Chrome/Chromium)
open review.html # a self-contained file — open it, host it, or share it
That's the whole tool: point it at a content file, get an HTML page (or a PDF). A few more commands help you write the content file and share the result:
skaldr --guide # the authoring guide: every block, the rules, a full example
skaldr --write-schema page.schema.json # JSON Schema for your editor's YAML language server
skaldr report.yaml --embed -o out.html # Artifact-ready fragment (no <html> skeleton) to publish as a claude.ai Artifact
skaldr --check report.yaml # validate against the schema, write nothing (exits non-zero on error)
skaldr --check reports/*.yaml # validate a whole set at once — for a pre-commit hook or CI
skaldr --emit-json report.yaml # print the normalised model as JSON on stdout (for tooling/agents)
For a PDF, use --pdf (above): it prints the page's print styling with a headless browser you
already have — the reliable way to a shareable PDF. (Printing a published Artifact doesn't work: it's
a sandboxed frame the browser flattens to a snapshot, so the print CSS never applies.) --pdf needs
a Chrome/Chromium/Edge on the machine; set SKALDR_BROWSER to point at one if it isn't auto-found.
There are no styling flags — everything is in the content file.
The content file
version: 1
meta:
title: "Q3 Warehouse Inventory Count — Discrepancies & Fixes"
subtitle: ["Reconciled review of the 10,000-unit cycle count."]
source: "WMS export" # optional; feeds the provenance footer
date: "Q3 2026" # optional; never auto-now (builds are reproducible)
toc: true # optional; auto table-of-contents from level-2 headings
hero: true # optional; larger display title + subtitle in a tinted band
badges: # author-declared vocabulary (see below)
FLOOR: { label: "Floor", tone: amber, legend: "Fixable on the floor before the next count." }
SYSTEM: { label: "System", tone: blue, legend: "Defect in the scanning/labeling pipeline." }
blocks:
- { type: heading, text: "Overview" }
- { type: text, body: "Prose with **bold**, *italic*, `code`, ~~strike~~ and [links](https://x)." }
- { type: cards, items: [{ label: "Matched cleanly", value: 8500, of: 10000, tone: success }] }
# … more blocks
Top level is version · meta · optional badges · blocks — nothing else. Every block
carries a type discriminator; the model is a pydantic discriminated union, so an unknown
type, a field from the wrong block, or an unknown key each fails with a precise
blocks.3.items.2.value-style error before anything renders.
Blocks: heading · text · list · fact_strip · key_value · cards · badge_row ·
callout · status_list · meter · table · code · quote · image · timeline ·
flow (a directional pipeline — arrow or step style, optional loop) · section (collapsible) ·
grid (bounded 6-column layout, with optional per-cell emphasis panels). The table is the
workhorse — typed columns, grouped subtotals, sub-rows, colour-only indicator dots, row-level
tone, and a reconcile block that hard-fails the build if the counts don't sum to a declared
total. Badges are declared once and chip onto table rows, cards, timeline entries, and flow
nodes alike. Prose fields take a small markdown subset (**bold**, *italic*, `code`,
~~strike~~, links); raw HTML is never interpreted.
Full reference: skaldr --guide (source: src/skaldr/skill/GUIDE.md),
data/example.yaml (a file exercising every block), and
schema/page.schema.json.
Guarantees
- One self-contained file — inline CSS, system fonts, no external resources; the page
carries its own
<!doctype>+<meta charset>so it renders correctly fromfile://, any static host, or a claude.ai Artifact. - Validation is the product — structural mistakes fail the build with a field path, never reach the reader's eyes.
- Derived, not authored — number formatting, percentages, subtotals, the legend, the TOC, and the provenance footer are all computed, so they can't drift from the data.
- Light & dark — the palette follows the viewer's OS theme; a small corner menu lets the reader switch theme and page width.
Let an AI write it
skaldr ships Claude skills, so you can skip the YAML and just ask. Install them once:
skaldr --install-skill # copies skaldr's skills into ~/.claude/skills (survives upgrades)
skaldr --install-plan-rule # optional: also have the AI keep its working plans as live skaldr docs
--install-skill installs the core authoring skill and task-specific ones — currently a
presentation builder (skaldr-presentation) that writes a word-for-word teleprompter runbook
(with color-coded live/recording cues) and drives the audience deck into the org's real brand
template. Each lands in its own ~/.claude/skills/<name>/.
--install-plan-rule is a separate, optional step: it adds a short, marker-delimited rule to
~/.claude/CLAUDE.md that steers the AI to author its working plans as live skaldr docs (rendered
with --watch so you can follow along). Delete that skaldr:plan-rule block to opt out; re-running
it refreshes the block in place. --install-skill never touches CLAUDE.md on its own.
Then in Claude Code (or Cowork), ask in plain language — "make me a skaldr report on this data
export: what's clean, what's broken, and the fix" — and it writes the content file and renders the
page. The skill reads the current guide from the tool itself (skaldr --guide), so it stays correct
across upgrades without reinstalling.
Development
uv run skaldr data/example.yaml -o out/example.html # run from a checkout
uv run pytest # tests
src/skaldr/models.py— the content-file contract (pydantic).src/skaldr/compute.py— derived values (legend, TOC, subtotals, footer).src/skaldr/render.py+components/— Jinja rendering.src/skaldr/styles.css— the single tokenised stylesheet.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file skaldr-2.3.0.tar.gz.
File metadata
- Download URL: skaldr-2.3.0.tar.gz
- Upload date:
- Size: 93.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cfe0b2d50c93e0d2ab6aef49f6d750a67f49c25ece71293231916b89ce6556b6
|
|
| MD5 |
a7e56d155653ee263a047a3ea77683f5
|
|
| BLAKE2b-256 |
1c4078e085eda46aa5714814c07e6dd82465a2b23252988719f2877108c19440
|
Provenance
The following attestation bundles were made for skaldr-2.3.0.tar.gz:
Publisher:
publish.yml on alex-yanchenko/skaldr
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
skaldr-2.3.0.tar.gz -
Subject digest:
cfe0b2d50c93e0d2ab6aef49f6d750a67f49c25ece71293231916b89ce6556b6 - Sigstore transparency entry: 2261403129
- Sigstore integration time:
-
Permalink:
alex-yanchenko/skaldr@f573dbee8d95d132efd0e3095927716a07f9cc10 -
Branch / Tag:
refs/tags/v2.3.0 - Owner: https://github.com/alex-yanchenko
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f573dbee8d95d132efd0e3095927716a07f9cc10 -
Trigger Event:
release
-
Statement type:
File details
Details for the file skaldr-2.3.0-py3-none-any.whl.
File metadata
- Download URL: skaldr-2.3.0-py3-none-any.whl
- Upload date:
- Size: 102.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ec3ecabc4be36ff1b87309fa71518e63cd181c1ae26f06589d8f801d294ce33b
|
|
| MD5 |
61583d79484959eacda199ed033dfc1b
|
|
| BLAKE2b-256 |
0a7bf1567a3bfa414474a432b6da037409f483baa8f81fb0ebb5c798cd020895
|
Provenance
The following attestation bundles were made for skaldr-2.3.0-py3-none-any.whl:
Publisher:
publish.yml on alex-yanchenko/skaldr
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
skaldr-2.3.0-py3-none-any.whl -
Subject digest:
ec3ecabc4be36ff1b87309fa71518e63cd181c1ae26f06589d8f801d294ce33b - Sigstore transparency entry: 2261403197
- Sigstore integration time:
-
Permalink:
alex-yanchenko/skaldr@f573dbee8d95d132efd0e3095927716a07f9cc10 -
Branch / Tag:
refs/tags/v2.3.0 - Owner: https://github.com/alex-yanchenko
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f573dbee8d95d132efd0e3095927716a07f9cc10 -
Trigger Event:
release
-
Statement type: