Writing reports¶
A report is a single, self-contained HTML document, rendered from a user-authored Jinja template against your project’s needs index. Because the output has no external dependencies, it can be opened in any browser, attached to a release, archived for an audit, or sent by email.
Templates are .html.j2 files that live in your repository,
in the directory configured by [reports].directory in ubproject.toml (default: reports/).
Quickstart¶
ubc quickstart scaffolds a runnable starter template at reports/needs_overview.html.j2,
including a table of all needs and a pure-SVG bar chart of needs per type.
Render it with:
ubc report needs_overview.html.j2
The rendered HTML is written to <reports-dir>/_build/needs_overview.html by default;
use -o/--outpath to write elsewhere.
To list the templates available in your project:
ubc report --list
Templates may also live in subdirectories of the reports directory:
--list shows them as paths relative to that directory (e.g. dashboards/status.html.j2),
which is the name to pass when rendering,
and the default output keeps the subdirectory under _build/
(so two templates with the same file name never collide).
Template context¶
Templates are rendered with minijinja and receive two variables:
needs— a dictionary of all needs, keyed by need ID.needs_list— the same needs as a sequence, sorted by ID.
Each need exposes id, type, title, and every other field defined for it (e.g. status, tags, custom options).
Missing fields render as empty strings rather than raising errors.
There are deliberately no pre-computed groupings: use standard Jinja filters to build any view you need. For example, to group needs by type:
{% for type, group in needs_list|groupby('type') %}
<h2>{{ type }} ({{ group|length }})</h2>
<ul>
{% for n in group %}
<li><code>{{ n.id }}</code> {{ n.title }}</li>
{% endfor %}
</ul>
{% endfor %}
groupby works for any field (status, tags, custom options, …),
and combines with selectattr / rejectattr for filtered views.
Charts¶
Reports stay self-contained by using inline SVG for charts, generated directly by the template — no JavaScript required. The quickstart template demonstrates the pattern:
{% set groups = needs_list|groupby('type') %}
{% set max_count = groups|map('last')|map('length')|max %}
<svg viewBox="0 0 640 {{ groups|length * 32 + 4 }}" role="img">
{% for type, group in groups %}
<g transform="translate(0, {{ loop.index0 * 32 }})">
<text x="0" y="19" font-size="13">{{ type }}</text>
<rect x="110" y="4" height="22" rx="3" style="fill: var(--vscode-charts-blue, #3b82f6)"
width="{{ (group|length / max_count * 480)|round(1) }}"></rect>
</g>
{% endfor %}
</svg>
The var(--vscode-charts-blue, #3b82f6) fill follows the editor’s chart palette
when previewed in VS Code and falls back to the fixed color everywhere else
(see Matching the editor theme below).
In VS Code¶
The ubCode extension brings the same renderer into the editor.
The Reports view in the ubCode sidebar lists the project’s templates
(the same names as ubc report --list, including subdirectories),
following the active editor or the pinned project
(see the ubcode.views.pinnedProject setting).
The view refreshes automatically when ubproject.toml changes,
so a newly configured [reports].directory is picked up without a reload.
From the view you can:
Generate & Preview (click a template, or its inline play button): indexes the project and renders the template into a WebView panel beside the editor. Each template gets its own panel, with a refresh button in the panel’s title bar to re-render.
Edit template: open the
.html.j2file.Open in Browser (right-click): render and write the HTML to the default output location (
<reports-dir>/_build/…, exactly asubc report) and open it in your external browser.Generate starter report template: shown when the project has no templates yet; scaffolds the same example as
ubc quickstart.
Render failures (template syntax errors, runaway loops, oversized output)
appear in the Problems panel as ubcode-report diagnostics on the template file,
with the failing line where known.
Diagnostics are published when a render is triggered —
templates are not validated as you type —
and clear again on the next successful render.
Note
The in-editor preview renders static HTML only:
<script> elements in a template are not executed there
(charts via inline SVG, as above, display fine).
For templates that embed scripts, use Open in Browser —
the file written to _build/ behaves identically to CLI output.
Matching the editor theme¶
Rendered reports are self-contained documents with no dependency on VS Code. A template can nevertheless opt into the editor’s color theme by referencing VS Code’s CSS variables with a fixed fallback:
:root {
--report-fg: var(--vscode-foreground, #1f2328);
--report-border: var(--vscode-panel-border, #d1d9e0);
}
body { color: var(--report-fg); font-family: var(--vscode-font-family, sans-serif); }
Inside the report preview the --vscode-* variables are defined by the editor,
so the report follows the active theme (light, dark, or high contrast);
in a browser, email client, or print output they are undefined and the fallback applies —
the document renders identically to today, everywhere.
The quickstart template demonstrates the full pattern,
including dark-mode browser fallbacks (prefers-color-scheme)
and themed chart colors (var(--vscode-charts-blue, #3b82f6)).
See the VS Code theme color reference
for the available variables.
Tip
SVG presentation attributes cannot resolve var() —
set fills via the style attribute (style="fill: var(--vscode-charts-blue, #3b82f6)")
or a CSS rule, as the quickstart template does.
Configuration¶
The [reports] section of ubproject.toml has two keys:
[reports]
# directory containing .html.j2 templates,
# relative to this file (default: "reports")
directory = "reports"
# abort renders whose output exceeds this many bytes
# (default: 50 MiB)
max_output_bytes = 52428800
Render-time safety limits beyond the output cap (a deterministic computation budget that terminates runaway loops, and a template recursion limit) are internal to the renderer and need no configuration.
Failure modes¶
ubc report exits non-zero with a descriptive message when:
no template name is given and
--listis not used, or both a template name and--listare given (usage error),the template name cannot be resolved (a path segment starting with
., such as a hidden file or..traversal) or does not exist under the reports directory (usage error),the template fails to parse or render (the message includes the template name and, where known, the line number),
the rendered output exceeds
max_output_bytes,the render exhausts its computation budget (e.g. an unbounded loop).
Without an active license, rendering is limited to small projects,
matching the limits of ubc build needs;
the same limit applies when rendering from VS Code.