MarginGuard

Technical Summary


Architecture

MarginGuard is a Next.js application deployed on Vercel with no separate backend service. All analytical logic runs within Next.js API routes at request time. The frontend is a two-page application: a landing page with a button to upload data in the form of Parquet files, and a briefing page that renders the agent's full output as an animated, typewriter-style CFO report with per-project drill-downs and a downloadable PDF view. The Anthropic SDK is called directly from API routes server-side, keeping credentials out of the client. Two routes have extended Vercel function timeouts configured — 120 seconds for /api/briefing and 60 seconds for /api/analyze — to accommodate multi-step Claude inference over large project contexts.

The data layer processes 1.46 million raw records across 405 projects. Using Python scripts, we standardize role names and dates, deduplicate records, and load the parsed data into DuckDB for efficient storage and analysis. We then aggregate project data to generate portfolio scans ranking all projects by margin health, portfolio statistics with GC, cohort, and RFI correlation summaries, and per-project views containing aggregated SOV line costs, labor breakdowns, change order status, billing gaps, and field note excerpts.


Agent Design

The agent operates as a two-stage pipeline. The first stage is a portfolio scan: /api/scan loads the pre-computed scan.json, classifies each of the 405 projects by severity (Critical, Warning, Watch, or Healthy) based on realized margin percentage, and returns portfolio-level statistics. The briefing endpoint then selects the top flagged projects by dollar exposure for deep analysis. The second stage is per-project reasoning: for each flagged project, /api/analyze loads the corresponding pre-aggregated JSON and sends the full data package to Claude with a structured system prompt instructing it to identify root causes across labor, materials, change orders, billing, and schedule dimensions, and to produce specific dollar-quantified recovery actions. A separate portfolio patterns call synthesizes cross-project findings into sector trends, GC performance signals, and cohort trajectory. Results are cached in sessionStorage on the client to avoid redundant API calls within a session.


AI Approach

Claude Sonnet is used for all inference via the Anthropic SDK, called directly from Next.js API routes. The /api/analyze route is the core reasoning step: it sends each flagged project's full pre-aggregated data package — including SOV line-level actuals versus budget, labor hour and cost breakdowns by trade, change order counts and approval status, billing completion percentages versus physical progress, and field note text — to Claude with a tightly constrained system prompt. The prompt instructs the model to act as a CFO agent, forbids generic outputs like 'investigate further', requires specific dollar amounts drawn from the data, and defines a strict JSON output schema covering severity, root causes with variance figures, and recovery actions with estimated recovery values and rationale.

The /api/briefing route orchestrates the full agent run: it fetches the portfolio scan, selects the top projects by dollar exposure, calls /api/analyze for each in sequence, then makes a final Claude call for portfolio-level pattern synthesis using the portfolio_stats.json data. This final call produces sector summaries, GC performance assessments, and a trend reading across year cohorts. The briefing page renders all outputs sequentially with a character-by-character typing animation, designed to feel like the agent is actively reasoning rather than returning a static result.


Key Technical Decisions

Efficient data aggregation was the central architectural design consideration. With 1.2 million labor log rows, the system reduces what Claude needs to reason over from 1.46M records to roughly 6,000 structured summary rows per project, well within a single API call context window. Structuring the agent as sequential API calls rather than a streaming agent loop keeps the system simple to debug and deploy, and the extended Vercel timeouts make this viable. Using sessionStorage caching on the client means repeated views of the briefing are instant while still allowing a fresh analysis run at any time.


Built With

  • claude
  • duckdb
  • next.js
  • recharts
  • shadcn/ui
  • v0
Share this project:

Updates