← all builds
▪ internal toolOne late-night build, June 2026

Humbear Ops and AI Console

The internal ops dashboard I built with Claude Code instead of paying for another analytics SaaS.

## the problem

I run Humbear Media on a stack of tools that each have their own dashboard. None of them show the thing I actually care about now: how much work Claude is doing across my projects, and what that work would cost if I were paying metered API rates for it. That number lives in transcript files on my machine, not in any product I pay for.

The obvious move is to buy another SaaS analytics dashboard. But nothing off the shelf knows what a Claude Code transcript is, and I did not want one more subscription whose whole job is displaying numbers I already have on disk. I wanted one dark, dense console: business ops counters on top, Claude usage and modeled cost underneath.

I also knew the data sources would change over time. Some numbers could be real on day one, others would stay placeholders until I wire up Make scenario runs, CRM leads, and maybe the Anthropic Admin API for org-wide usage. So the real problem was not the UI. It was designing a data flow where swapping mock for live data never touches the components.

## what I built

A dark internal analytics console: Next.js App Router, Tailwind, Recharts, and Framer Motion. Eight KPI cards (Active Clients, AI Conversations, Leads Processed, Automations Run, Content Pieces Generated, Campaigns Live, Error Count, Estimated AI Value), a hero card showing estimated AI value with a model composition bar, a usage-by-model comparison, a day-by-hour activity heatmap, and a daily trend chart. Near-black canvas, monospace type, orange accent, hairline borders.

Every number on the page renders from one typed payload. A raw API response, shaped like the Anthropic Admin API usage and cost reports, goes through a transform layer into view models; components are dumb and prop-driven. Each section is wrapped in an async wrapper with loading, success, empty, and error states, and a URL query param can force any section into any state for QA screenshots. The swap point to go fully live is a single function, getMockApiResponse().

Part of it is already real. A server route parses my local Claude Code transcripts (the JSONL files Claude Code writes per project), sums per-message token usage by model, and computes the heatmap, the trend, and the headline API-equivalent value from actual activity on this machine. The ops counters are openly stubbed until I wire in my other tools. Internal tool, no public URL.

## how Claude was actually used

  1. 01

    Wrote the design brief, not the code

    I gave Claude Code a specific visual spec (near-black grid canvas, monospace type with wide tracking, orange ember accent, thin borders, subtle glows) plus one architectural rule: raw API response to transform layer to view models, and nothing renders raw data directly. Claude scaffolded the Next.js app with the design tokens centralized in tailwind.config.ts. I kept the rule, it kept the structure.

  2. 02

    Typed the contract before anything rendered

    The schema lives in one file, lib/types.ts, with three layers: raw API types shaped like the Anthropic Admin API usage and cost reports, view model types for each component, and an AsyncState envelope. Claude produced the types; I treated that file as the integration contract for whatever backend eventually feeds this. It is the reason the mock-to-live swap is a one-function change.

  3. 03

    Put all business logic in one transform layer

    Claude wrote lib/transform.ts to aggregate token counts by model family, apply pricing, compute period-over-period deltas, and shape chart data. Components stayed prop-driven with zero logic. When something looks wrong on the dashboard, there is exactly one file to check.

  4. 04

    Made every async state testable from the URL

    I asked for per-section loading, empty, and error handling instead of one page-level spinner. Claude produced an AsyncSection wrapper plus query params (?state=loading, ?state=error, ?state=empty) that force every section into a given state. That made QA and screenshots trivial: every state of every section is reachable from the address bar.

  5. 05

    Turned the mock real with transcript parsing

    The plan was a mock-fed shell, but Claude Code already logs exact per-message token usage to JSONL transcripts on my machine. So Claude built app/api/analytics/route.ts, a Node route that scans those transcript files, sums tokens by model within the requested window, and builds the heatmap and daily trend from message timestamps. The headline number on my dashboard is my actual usage, not a placeholder, and it required zero API keys.

  6. 06

    Isolated the pricing model

    lib/pricing.ts holds per-model token rates in one table, and the Estimated AI Value figure is computed from tokens at those rates. It is explicitly a modeled number, what the usage would cost at metered API list prices, not an invoice. The README flags the table for manual verification against current pricing, because hardcoded prices rot.

  7. 07

    Made the fallback mock deterministic

    The embedded mock data uses a seeded PRNG and shaped activity curves instead of Math.random(), so the server render and client render produce identical numbers. Random mock data under SSR causes hydration mismatches; seeding the generator removes that whole bug class. The mock is also clearly labeled in the code as placeholder volumes, not real account data.

  8. 08

    README as the handoff document

    I had Claude write the README the way I would want to receive this project cold: the full data-flow diagram, exactly which numbers are real versus stubbed today, and the specific Anthropic Admin API endpoints to wire for org-wide usage later. It also documents why local transcript parsing is the right call for subscription usage, since a Claude.ai subscription has no usage API.

## stack

Claude CodeNext.js 14 (App Router)React 18TypeScriptTailwind CSSRechartsFramer MotionNode.js server route for transcript parsing

## results (the verifiable kind)

  • A working internal dashboard exists at dev/ops-console and runs locally with npm run dev. Internal tool, no public deployment.
  • The Claude usage views run on real data today: a server route parses local Claude Code transcript files and computes token usage by model, an activity heatmap, and a daily trend, with the embedded mock as fallback only.
  • The entire app is roughly 20 source files with five runtime dependencies (next, react, react-dom, recharts, framer-motion), verified from the repo.
  • Every dashboard section handles four async states (loading, success, empty, error), and each state is forceable from a URL query param for QA.
  • The raw data types mirror the Anthropic Admin API usage and cost report shapes, so wiring org-wide API usage later is a mapping job, not a rebuild; the README documents the exact endpoints.

## what I learned

  • I never ran git init. For someone building a site about showing receipts, that stings: I have file timestamps instead of commit history. Every project gets a repo from minute one now.
  • Treating the mock as the integration contract worked. Because the raw types were defined first and shaped like the real Admin API, business logic could not smear into components; it all had to live in the transform layer.
  • The fastest path to real data was not an API, it was files already on my disk. Claude Code logs every message's token usage locally; parsing those transcripts made the headline number real without a single credential.
  • Random mock data breaks server-side rendering. If the server and client roll different numbers you get hydration mismatches, so the mock uses a seeded PRNG that is deterministic on both ends.
  • Stubs are fine when they are labeled. The ops counters are placeholder values today and the README says exactly which numbers are real and which are not. Passing off placeholder numbers as real is the exact thing this site exists to call out.

$ follow --the-build

Watch it happen, don't take my word for it

Every build on this site gets documented as it happens — the prompts, the dead ends, the results. No course at the end of this funnel. There is no funnel.

follow on x →