How /html-report Generates Offline SVG Dashboards from Tracker CSV

The /html-report command reads the job‑application tracker CSV with pandas, builds summary statistics and matplotlib SVG charts, and embeds them into a self‑contained HTML template to create a fully offline dashboard.

The MadsLorentzen/ai-job-search repository provides a CLI tool that converts raw application tracking data into portable, vector‑graphic reports. By combining pandas for data manipulation and matplotlib’s SVG backend, the utility produces standalone HTML files that render without external dependencies or internet access. This article walks through the exact pipeline implemented in tools/html_report.py and the supporting template files.

Overview of the Pipeline

The generation process follows a deterministic six‑stage pipeline. Each stage is implemented in the html_report module and operates entirely within the local filesystem, ensuring full offline capability.

Stage Action Key Source Reference
Ingest Load documents/tracker.csv into a DataFrame tools/html_report.py – pd.read_csv
Clean Parse dates, fill missing values, derive metrics (e.g., days‑to‑response) tools/html_report.py – pd.to_datetime
Aggregate Compute weekly counts, status distributions, and median response times tools/html_report.py – DataFrame.groupby
Visualise Plot charts and save them as SVG markup tools/html_report.py – plt.savefig(..., format='svg')
Templating Inject SVG strings and statistics into an HTML skeleton tools/html_report.py – string.Template
Output Write the final file to reports/dashboard.html tools/html_report.py – Path.write_text

Step‑by‑Step Implementation

Step 1: Load the Tracker CSV

The command expects a CSV file at documents/tracker.csv containing columns such as applied_on, response_on, company, and status. It uses pandas to parse the file and immediately converts date columns to datetime objects.

import pandas as pd
import pathlib

TRACKER = pathlib.Path("documents/tracker.csv")
df = pd.read_csv(TRACKER, parse_dates=["applied_on", "response_on"])

Step 2: Clean and Enrich Data

After loading, the pipeline calculates derived fields to support time‑series analysis. It computes the difference between response and application dates and extracts ISO calendar weeks for grouping.

df["days_to_response"] = (df["response_on"] - df["applied_on"]).dt.days
df["week"] = df["applied_on"].dt.isocalendar().week

Step 3: Compute Summary Statistics

Aggregations drive the dashboard’s KPIs and charts. The code groups by week for trend lines and uses value_counts() for categorical breakdowns like application status.

weekly_counts = df.groupby("week").size()
status_counts = df["status"].value_counts()
total_apps = len(df)

Step 4: Generate Inline SVG Charts

Rather than saving separate image files, the tool captures SVG markup as strings. It sets matplotlib’s backend to SVG, plots the data, and writes the output to an in‑memory buffer. This keeps the final HTML self‑contained.

import matplotlib.pyplot as plt
from io import StringIO

def plot_to_svg(series, title):
    fig, ax = plt.subplots(figsize=(8, 4))
    series.plot(kind="bar", ax=ax, color="steelblue")
    ax.set_title(title)
    buf = StringIO()
    fig.savefig(buf, format="svg", bbox_inches="tight")
    plt.close(fig)
    return buf.getvalue()

weekly_svg = plot_to_svg(weekly_counts, "Applications per Week")
status_svg = plot_to_svg(status_counts, "Status Distribution")

Step 5: Assemble the HTML Template

The repository includes tools/html_report_template.html, a minimal HTML skeleton containing placeholders like $weekly_chart and $total_apps. The command uses Python’s string.Template to substitute the SVG strings and computed values, producing a single HTML document with inline vector graphics.

from string import Template

template_path = pathlib.Path("tools/html_report_template.html")
html_template = Template(template_path.read_text())

report_html = html_template.substitute(
    weekly_chart=weekly_svg,
    status_chart=status_svg,
    total_apps=total_apps,
    last_update=pd.Timestamp.now().strftime("%Y-%m-%d %H:%M")
)

Step 6: Write the Offline Dashboard

Finally, the tool writes the populated HTML to reports/dashboard.html. Because the SVG markup is embedded directly, opening this file in any browser requires no network requests.

output_path = pathlib.Path("reports/dashboard.html")
output_path.write_text(report_html)

CLI Usage and Command Flags

According to the source code in tools/html_report.py, the command exposes several options for customizing output:

  • --output <path> – Specify a custom destination file (defaults to reports/dashboard.html).
  • --filter <status> – Restrict the analysis to rows matching a specific status value (e.g., "interviewing").
  • --dry-run – Execute the data pipeline without writing the final file, useful for validation.

Invoke the tool from the repository root using the module execution syntax:

python -m ai_job_search html-report

Or, if the package is installed with console scripts:

ai-job-search html-report --output ./custom_report.html

Documentation for these flags resides in .claude/commands/html-report.md.

Summary

  • pandas ingests and enriches the raw documents/tracker.csv data.
  • Derived metrics (weeks, days‑to‑response) enable time‑series and categorical analysis.
  • matplotlib renders charts as SVG strings captured in memory via StringIO.
  • string.Template injects the SVG and statistics into tools/html_report_template.html.
  • The resulting reports/dashboard.html is a fully offline, self‑contained dashboard with no external dependencies.

Frequently Asked Questions

Does the dashboard require an internet connection to view charts?

No. The /html-report command embeds SVG markup directly into the HTML file. Because Scalable Vector Graphics are text‑based XML, they travel with the document, eliminating the need for external image hosts or CDN links.

Can I customize the chart colors or the HTML layout?

Yes. The visual styling and HTML structure are controlled by tools/html_report_template.html and the matplotlib parameters inside tools/html_report.py. Editing the CSS within the template or adjusting the color arguments in the plotting functions will change the dashboard appearance.

What CSV columns are required for the report to work?

The pipeline expects at minimum applied_on, response_on, company, and status columns. The code uses parse_dates on the date fields, so ensure they are in a standard ISO or locale‑recognizable format. Missing optional columns are handled gracefully, but absence of applied_on will raise a KeyError during the grouping stage.

Is there a way to automate this report generation, such as in a CI pipeline?

Yes. Because the tool is a standard CLI entry point, you can schedule it via cron or GitHub Actions. Use the --dry-run flag in automation to verify data integrity before overwriting reports/dashboard.html, and commit the generated HTML artifact if you wish to publish the dashboard via GitHub Pages.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →