How an HTML Dashboard Is Generated from Job Tracker Data

The /html-report command generates a self-contained HTML dashboard by aggregating data from job_search_tracker.csv and documents/applications/*/outcome.md, normalizing application statuses into five canonical buckets, computing funnel statistics, and rendering inline SVG charts to reports/application-dashboard.html.

The ai-job-search repository by MadsLorentzen provides a Claude Code command that transforms raw job application tracking data into a visual, offline-capable report. This tool eliminates external dependencies by embedding all CSS, JavaScript, and SVG graphics directly into a single HTML file that visualizes your entire job search pipeline.

Data Sources and Input Files

The dashboard generation process consumes two primary data sources located within the repository structure.

job_search_tracker.csv sits at the repository root and contains one row per application with fields such as date, company, sector, role, status, and channel. The command reads this file using Python’s csv.DictReader to create the initial dataset.

Outcome files reside under documents/applications/*/outcome.md. These markdown files contain interview stage check-boxes and qualitative notes. During processing, the system parses each outcome file and merges its contents with the matching tracker row using a fuzzy key based on lower-cased company and role names with punctuation removed. Unmatched archives are attached as extra context rather than discarded.

The Four-Stage Generation Pipeline

The generation workflow defined in .claude/commands/html-report.md follows a strict four-stage pipeline.

1. Argument Parsing and Path Resolution

The command accepts an optional output path argument and a --open flag. If no path is provided, the dashboard writes to reports/application-dashboard.html. The implementation guarantees that the reports/ directory exists before writing (lines 16-24 of the spec). When --open is supplied, the command prints a reminder to open the file rather than launching a browser automatically.

2. Data Collection and Status Normalization

After loading the CSV and outcome files, the system normalizes disparate tracker status values into five canonical buckets: Active, Interview, Offer, Hired, and Rejected/Closed (lines 24-30 of the spec). This normalization enables consistent statistical aggregation across different naming conventions that users may have employed in their trackers.

The fuzzy matching algorithm reconciles tracker rows with outcome files by comparing sanitized company and role strings, ensuring that archived applications retain their contextual data even if the original CSV entry uses slightly different punctuation or casing.

3. Statistical Computation

From the normalized dataset, the command derives several summary metrics that populate the dashboard’s stat cards and charts:

  • Total applications count
  • Status distribution across the five canonical buckets
  • Sector and channel breakdowns showing volume by industry and application source
  • Year/season distribution calculated from the date field
  • Funnel rates measuring the percentage of applications that progressed past the resume screening stage
  • Rejection rate calculated excluding "Active" rows

These computed values feed directly into four inline SVG visualizations: a status doughnut chart, a sector bar chart, a channel bar chart, and an application funnel graphic.

4. HTML Rendering with Inline Assets

The final stage emits a single HTML file containing no external dependencies. All CSS resides within a <style> block and JavaScript (handling lightweight client-side filtering) sits inside a <script> block. The four charts are rendered as hand-written inline SVG elements, eliminating the need for external libraries or CDN resources and ensuring full offline operation.

Every value interpolated into the HTML undergoes strict escaping for &, <, >, ", and ' characters (line 51 of the spec). The layout follows an ASCII-art grid structure defined in lines 55-70 of the specification, featuring stat cards at the top, a two-column chart grid in the middle, and a filterable applications table below. The design targets screens ≥ 900 px and degrades gracefully on smaller viewports. A footer displays "Generated by Claude Code · ai-job-search · {ISO date}".

CLI Usage and Programmatic Examples

Execute the dashboard generation from the command line using the Claude Code interface:


# Generate to default location (reports/application-dashboard.html)

ai-job-search /html-report

# Specify a custom output path

ai-job-search /html-report ~/Desktop/job-dashboard.html

# Print a reminder to open the file after generation

ai-job-search /html-report --open

While the command is parsed by the Claude runtime, the underlying logic can be replicated in standalone Python scripts for custom integrations:

from pathlib import Path
import csv

TRACKER = Path("job_search_tracker.csv")
OUTCOMES_DIR = Path("documents/applications")

def load_tracker_data():
    """Parse the job search tracker CSV into a list of dictionaries."""
    with TRACKER.open(newline="", encoding="utf-8") as f:
        return list(csv.DictReader(f))

def load_outcome_files():
    """Map outcome.md files to their parent directory names."""
    outcomes = {}
    for outcome_path in OUTCOMES_DIR.rglob("outcome.md"):
        with outcome_path.open(encoding="utf-8") as f:
            outcomes[outcome_path.parent.name] = f.read()
    return outcomes

# Additional steps: normalize status buckets, compute stats, render HTML...

Key Implementation Files

File Purpose
.claude/commands/html-report.md Complete specification of the dashboard generation workflow, including the ASCII layout diagram, status normalization rules, and HTML template structure.
tests/test_html_report_command.py Unit tests verifying command parsing, path handling, and .gitignore integration for generated reports.
job_search_tracker.csv Primary input file (user-generated) containing application records.
documents/applications/*/outcome.md Supplementary input files storing interview outcomes and notes.
reports/application-dashboard.html Default output location for the generated dashboard.

Summary

  • The /html-report command creates a single self-contained HTML file with no external dependencies by embedding CSS, JavaScript, and SVG inline.
  • Data originates from job_search_tracker.csv and documents/applications/*/outcome.md, merged via fuzzy matching on company and role names.
  • Status values normalize to five buckets (Active, Interview, Offer, Hired, Rejected/Closed) to enable consistent statistical analysis.
  • The output includes four inline SVG charts (status doughnut, sector bar, channel bar, and funnel) plus a filterable data table.
  • All user-supplied content undergoes HTML entity escaping before interpolation to prevent injection vulnerabilities.
  • The default output path is reports/application-dashboard.html, with support for custom paths and an --open reminder flag.

Frequently Asked Questions

What input files are required to generate the dashboard?

The command requires job_search_tracker.csv at the repository root. While optional, outcome files stored as documents/applications/*/outcome.md provide additional context and interview stage data that enriches the dashboard. If outcome files exist without matching CSV entries, they appear as archived context rather than primary entries.

Can I view the dashboard without an internet connection?

Yes. The generated HTML file is entirely self-contained. All CSS styles, JavaScript filtering logic, and SVG chart graphics are embedded directly within the file, making it fully functional offline without references to external CDNs or libraries.

How does the system handle different status labels in my tracker?

The system maps your existing status values to five canonical buckets during the normalization phase: Active, Interview, Offer, Hired, and Rejected/Closed. This mapping occurs according to lines 24-30 of the specification in .claude/commands/html-report.md, ensuring that variations like "Phone Screen" or "Rejected" are categorized consistently for statistical reporting.

Where can I find the test suite for this feature?

The test suite resides in tests/test_html_report_command.py within the repository. These tests validate that the command file parses correctly, that output writes to the expected reports/ directory, and that generated files respect the repository's .gitignore rules.

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 →