add-report
Standardizes the process of building data-driven report cards for ClaudeBar.
Install
mkdir -p .claude/skills/add-report && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/11941" && unzip -o skill.zip -d .claude/skills/add-report && rm skill.zipInstalls to .claude/skills/add-report
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Guide for adding new report cards to ClaudeBar that analyze local data sources and display metrics with comparison deltas. Use this skill when: (1) Adding a new report/analytics card (e.g., weekly summary, model breakdown, session stats) (2) Creating data analysis features that read local files and display aggregated metrics (3) Adding comparison cards that show "today vs previous" style deltas (4) Building any feature that follows the DailyUsage pattern (parse → aggregate → report → card)Key capabilities
- →Define report data source
- →Define metrics for aggregation
- →Define comparison periods
- →Create architecture diagrams for reports
- →Implement domain models for stats and reports
- →Implement infrastructure for parsers and analyzers
How it works
The skill guides the creation of new report cards by defining the data flow from source to card view, implementing domain models for stats and reports, and building infrastructure for parsers and analyzers.
Inputs & outputs
When to use add-report
- →Create weekly usage report
- →Build data breakdown card
- →Add comparison dashboard
About this skill
Add Report Card to ClaudeBar
Add new report cards that analyze local data sources, compute metrics with comparison deltas, and display them in the existing card UI style using TDD.
When to Use
This skill covers adding report-style features — cards that:
- Read and parse local data files (JSONL, JSON, CSV, etc.)
- Aggregate metrics (cost, tokens, time, counts)
- Compare periods (today vs yesterday, this week vs last week)
- Display results in glassmorphism cards matching the existing UI
Architecture Pattern
Every report feature follows this data flow:
Data Source → Parser → Analyzer → Report Model → UsageSnapshot → Card View
Mapped to the codebase layers:
| Layer | Location | What to Create |
|---|---|---|
| Domain | Sources/Domain/{Feature}/ | Rich models + @Mockable protocol |
| Infrastructure | Sources/Infrastructure/{Provider}/ | Parser + Analyzer implementation |
| App | Sources/App/Views/ | Card view(s) |
| Integration | Provider class + statsGrid | Wire analyzer → snapshot → UI |
Reference implementation: See
references/daily-usage-pattern.mdfor the complete DailyUsage feature as a working example of this pattern.
Workflow
Phase 0: Architecture Design (get user approval)
↓
Phase 1: Domain Models + Tests (TDD Red→Green)
↓
Phase 2: Infrastructure Parser + Analyzer + Tests
↓
Phase 3: Card View + Integration
↓
Phase 4: Verify all tests pass
Phase 0: Architecture Design (MANDATORY)
Before writing code, design the feature and get user approval.
Step 1: Define the Report
Answer these questions:
- What data source? (JSONL sessions, API response, local DB, etc.)
- What metrics? (cost, tokens, time, counts, etc.)
- What comparison period? (today vs yesterday, this week vs last, etc.)
- Which provider? (Claude, Codex, or generic across all?)
- How many cards? (one per metric, or a single combined card?)
Step 2: Create Architecture Diagram
Example: Adding a weekly cost breakdown report
┌─────────────────────────────────────────────────────────┐
│ Data Source Infrastructure Domain │
│ │
│ ~/.claude/ → WeeklyParser → WeeklyStat │
│ projects/ (reads JSONL) (per-day cost) │
│ *.jsonl │
│ WeeklyAnalyzer → WeeklyReport │
│ (aggregates by (this week vs │
│ week, implements last week) │
│ protocol) │
│ ↓ ↓ │
│ Provider.refresh() → UsageSnapshot │
│ .weeklyReport │
│ ↓ │
│ statsGrid() → WeeklyCardView │
└─────────────────────────────────────────────────────────┘
Step 3: Document Components
| Component | Purpose | Inputs | Outputs |
|---|---|---|---|
{Name}Stat | Single period's data | Raw aggregated values | Formatted strings, isEmpty |
{Name}Report | Period comparison | Two Stats | Deltas, percentages, progress |
{Name}Analyzing | Protocol | Date/config | Report |
{Name}Analyzer | Implementation | File paths | Report |
{Name}CardView | UI card | Report + metric | Glassmorphism card |
Step 4: Get User Approval
Use AskUserQuestion to confirm the design before proceeding.
Phase 1: Domain Models (TDD)
1a. Create the Stat Model
The stat model represents one period's aggregated data with rich formatting behavior.
Location: Sources/Domain/{Feature}/{Name}Stat.swift
Pattern to follow:
import Foundation
public struct {Name}Stat: Sendable, Equatable {
public let date: Date
// Add your metrics here
public let metricA: Decimal
public let metricB: Int
// Formatting — encapsulate in the model, not the view
public var formattedMetricA: String { /* currency, compact number, duration, etc. */ }
public var formattedMetricB: String { /* ... */ }
public var isEmpty: Bool { /* all zeros check */ }
public static func empty(for date: Date) -> Self { /* zero-valued instance */ }
}
Key rules:
- Use
Decimalfor monetary values (not Double — floating point errors) - Use
TimeIntervalfor durations - Use
Locale(identifier: "en_US")for currency formatting (noten_US_POSIXwhich adds a space) - All formatting lives in the model — views just read formatted strings
isEmptyuses&&(all zeros = empty), not||
1b. Create the Report Model
The report model compares two periods and computes deltas.
Location: Sources/Domain/{Feature}/{Name}Report.swift
Pattern to follow:
public struct {Name}Report: Sendable, Equatable {
public let current: {Name}Stat // e.g., today, this week
public let previous: {Name}Stat // e.g., yesterday, last week
// Delta calculations
public var metricADelta: Decimal { current.metricA - previous.metricA }
public var metricAChangePercent: Double? {
guard previous.metricA > 0 else { return nil } // nil when previous is zero
// ...
}
// Formatted deltas with sign: "+$5.00", "-1.2M"
public var formattedMetricADelta: String { /* ... */ }
// Progress for bar display (0-1 ratio of current vs total)
public var metricAProgress: Double {
let total = /* current + previous */
guard total > 0 else { return 0 }
return current / total
}
}
Key rules:
- Change percent returns
nilwhen previous is zero (avoid division by zero) - Formatted deltas always include sign (
+or-) - Progress is
current / (current + previous), clamped to 0-1 - Use
abs()for formatted values, prepend sign separately
1c. Create the Protocol
Location: Sources/Domain/{Feature}/{Name}Analyzing.swift
import Mockable
@Mockable
public protocol {Name}Analyzing: Sendable {
func analyze() async throws -> {Name}Report
}
1d. Write Tests First
Location: Tests/DomainTests/{Feature}/
Create two test files following Chicago School TDD (test state, not interactions):
{Name}StatTests.swift— Test formatting, isEmpty, edge cases{Name}ReportTests.swift— Test deltas, percentages, nil cases, progress
import Foundation
import Testing
@testable import Domain
@Suite
struct {Name}StatTests {
@Test func `formats metric as expected`() {
let stat = {Name}Stat(date: Date(), metricA: 14.26, ...)
#expect(stat.formattedMetricA == "$14.26")
}
// ...
}
After writing tests → implement the models → run tests → all green.
Phase 2: Infrastructure (TDD)
2a. Create the Parser (if reading files)
If the report reads local files (JSONL, JSON, CSV), create a parser.
Location: Sources/Infrastructure/{Provider}/{Name}Parser.swift
Pattern: Parser is a struct (not protocol) since it's a pure data transformation.
struct {Name}Parser {
func parse(fileURL: URL) throws -> [{Name}Record] { /* ... */ }
func parse(content: String) -> [{Name}Record] { /* for testing */ }
}
2b. Create the Analyzer
Location: Sources/Infrastructure/{Provider}/{Provider}{Name}Analyzer.swift
The analyzer implements the domain protocol and orchestrates:
- Find relevant files (filter by modification date for performance)
- Parse files into records
- Partition records by time period
- Aggregate into stat models
- Return report
Performance rule: Only scan files modified within the relevant time window. With 2000+ JSONL files, scanning all of them is too slow.
public struct {Provider}{Name}Analyzer: {Name}Analyzing, Sendable {
public func analyze() async throws -> {Name}Report {
let files = findRecentFiles(since: periodStart) // Performance!
// parse → partition → aggregate → return
}
}
2c. Write Infrastructure Tests
Location: Tests/InfrastructureTests/{Provider}/
- Parser tests: valid input, missing fields, malformed data, timestamps
- Analyzer tests: use temp directories with JSONL content, test date partitioning
Phase 3: Card View + Integration
3a. Create the Card View
Location: Sources/App/Views/{Name}CardView.swift
The card must match the existing glassmorphism style. Use WrappedStatCard as the reference:
struct {Name}CardView: View {
let metric: {Name}Metric // enum for each displayable metric
let report: {Name}Report
let delay: Double // for cascading entrance animation
@Environment(\.appTheme) private var theme
var body: some View {
VStack(alignment: .leading, spacing: 6) {
// 1. Header: icon + LABEL (uppercased)
// 2. Large value (e.g., "$14.26" or "19.5M")
// 3. Progress bar (animated)
// 4. Delta comparison line (e.g., "Vs Mar 10 -$27.47 (4.9%)")
}
.padding(12)
.background(/* theme.cardGradient + theme.glassBorder stroke */)
.scaleEffect(isHovering ? 1.015 : 1.0)
.onHover { isHovering = $0 }
}
}
Card styling checklist:
.padding(12)on the VStacktheme.cardGradientfill +theme.glassBorderstroke (1pt)theme.cardCornerRadiusfor cornerstheme.fontDesignon all texttheme.textPrimary/theme.textSecondary/theme.textTertiaryfor text hierarchytheme.progressTrackfor bar background- Hover scale effect (1.015)
- Animated progress bar with
delayparameter
3b. Add to UsageSnapshot
Add an optional field for the report:
// In Sources/Domain/Provider/UsageSnapshot.swift
public let {name}Report: {Name}Report?
// Add to init with default nil
3c. Wire into Provider
Content truncated.
When not to use it
- →When the feature does not involve analyzing local data sources
- →When the feature does not require comparison deltas
- →When the feature does not display results in glassmorphism cards
Limitations
- →Guide for adding new report cards to ClaudeBar that analyze local data sources and display metrics with comparison deltas.
- →Read and parse local data files (JSONL, JSON, CSV, etc.)
- →Display results in glassmorphism cards matching the existing UI
How it compares
This skill provides a structured, TDD-driven workflow for adding new report cards with specific data analysis and UI requirements, unlike general feature development.
Compared to similar skills
add-report side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| add-report (this skill) | 0 | 5mo | No flags | Advanced |
| streamlit | 86 | 9mo | No flags | Intermediate |
| openalex-database | 48 | 7mo | Review | Intermediate |
| data-storytelling | 47 | 2mo | No flags | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by tddworks
View all by tddworks →You might also like
streamlit
sverzijl
When working with Streamlit web apps, data dashboards, ML/AI app UIs, interactive Python visualizations, or building data science applications with Python
openalex-database
davila7
Query and analyze scholarly literature using the OpenAlex database. This skill should be used when searching for academic papers, analyzing research trends, finding works by authors or institutions, tracking citations, discovering open access publications, or conducting bibliometric analysis across 240M+ scholarly works. Use for literature searches, research output analysis, citation analysis, and academic database queries.
data-storytelling
wshobson
Transform data into compelling narratives using visualization, context, and persuasive structure. Use when presenting analytics to stakeholders, creating data reports, or building executive presentations.
csv-data-summarizer
coffeefuelbump
Analyzes CSV files, generates summary stats, and plots quick visualizations using Python and pandas.
umap-learn
K-Dense-AI
UMAP dimensionality reduction. Fast nonlinear manifold learning for 2D/3D visualization, clustering preprocessing (HDBSCAN), supervised/parametric UMAP, for high-dimensional data.
data-visualization
anthropics
Create effective data visualizations with Python (matplotlib, seaborn, plotly). Use when building charts, choosing the right chart type for a dataset, creating publication-quality figures, or applying design principles like accessibility and color theory.