Skip to content

Projects

One evolution · three chapters

From services, to a template, to an agent platform

This is not a pile of projects — it is one line of work that compounds. Three production ML services taught the lessons; a governed template encoded them; and agent-local proves the same governance philosophy generalizes to a new domain — local LLM agents. Each chapter is the foundation of the next.

Why three repos, not one

Separate repositories with an explicit, bidirectional contract — not a monorepo. Each has its own lifecycle, audience and release line; agent-local reuses the template's IaC when it needs cloud, and the template documents it as a sibling. Knowing where to draw that boundary is the point.

Chapter 1 · The ML-MLOps Portfolio

The portfolio is not three models — it is one production system that happens to serve three of them. Each service ships with its FastAPI contract, test suite, Docker image and Kubernetes manifests; around them sits the shared MLOps surface: Terraform-provisioned GKE and EKS clusters, Kustomize overlays per environment, GitHub Actions CI/CD with quality gates, MLflow tracking, Prometheus + Grafana monitoring, and the incident writeups that prove the system was operated, not just deployed.

395+ automated tests and 18 architecture decision records hold it together — every non-trivial choice is documented with the alternatives it rejected.

How to review it

Pick one service and follow its evidence chain: metrics → serving path → deployment → incident. The debugging deep dive on BankChurn is the strongest 10-minute read.

Portfolio deployment walkthrough — full build, test and serve cycle

The three services inside the portfolio — each with its own deep-dive page. Hover to hold, drag to browse, or click a card to bring it to center:

churn classification

BankChurn Predictor

AUC 0.87 90% coverage FastAPI · K8s · SHAP

Cost-aware churn classification — and the serving incident that went from 81% errors to 0% at half the CPU.

BankChurn Predictor

financial nlp

NLPInsight Analyzer

80.6% accuracy 98% coverage CPU-only serving

Financial sentiment with an explainable, low-cost inference path — the heavier transformer documented as a rejected trade-off.

NLPInsight Analyzer

demand forecasting

ChicagoTaxi Pipeline

R² 0.96 6.3M rows PySpark · temporal CV

Demand forecasting at scale with strictly temporal validation — and the data leak that was caught before the metrics were published.

ChicagoTaxi Pipeline

All the infrastructure, testing, security and monitoring proof behind the portfolio lives in one place:

Chapter 2 · The Production Template

The second project is what the first one taught: an open-source starter system that encodes the portfolio's production lessons as reusable defaults. Scaffold a new ML service and it arrives with the serving and training patterns, deployment overlays and operating guardrails already in place — the mistakes the portfolio paid for once, prevented by default.

Inside the box: a FastAPI serving scaffold with the single-worker + ThreadPoolExecutor pattern, training pipelines with quality gates (metric, fairness, leakage), 6 env×cloud Kustomize overlays for GCP and AWS, Terraform modules, CI/CD that signs images and attests SBOMs (SLSA L2), closed-loop drift monitoring, 38 documented anti-patterns and 43 ADRs.

Its differentiator is the governed AI-assisted development layer: behavior rules, skills, workflows and an audit trail that keep agentic coding reviewable and bounded — engineered, not hidden.

Why it matters

The portfolio proves I can build and operate ML services. The template proves I can turn that experience into a system other teams can adopt.

Chapter 3 · agent-local — the LLM plane

The third chapter takes the template's governance philosophy — AUTO / CONSULT / STOP, eval-gated autonomy, policy-as-data, no fine-tuning until a written gate fires — and generalizes it to a new domain: local, multi-tier LLM agents. The hard-won logic (grammar-constrained routing, an adaptive reasoning loop, objective escalation, a deterministic policy gate) lives in a reusable core/; a new domain is a thin usecases/<name>/ folder, never a fork.

The shipped example use-case is a WhatsApp store assistant — but the point is the platform, not the store. It is a sibling of the template, not a copy: it reuses the template's Terraform and Kustomize when it needs cloud, and runs the template's day-2 maintenance lanes on its local model tiers.

The signal

Chapters 1–2 show I can build and systematize ML. Chapter 3 shows the system composes — the same governance generalizes to a domain it was never written for. That is the jump from "builds things" to "designs platforms".

This is an active build. Rather than rewrite this page each week, the status below tracks against the published plan (ACTION_PLAN_LLM_AGENT.md) — ✅ done · 🔨 in progress · ⏳ gated/next.

✅ Phase 0–1 · foundation

Runtime, router & policy gate

  • ✅ llama.cpp bench + tier contract (E4B router gate 20/20)
  • ✅ grammar-constrained routing with confidence
  • ✅ reusable core/ + thin usecases/ (ADR-001)
  • ✅ deterministic policy gate; all tools read-only

✅ Phase 2 · controller & verifier

Governed execution

  • ✅ ExecutiveController + per-tier circuit breaker
  • ✅ policies as versioned YAML + decision_id
  • ✅ cross-tier verifier + bounded self-consistency, reflection notes isolated from evidence (ADR-009)
  • ✅ 11 evaluation sets (incl. adversarial injection) + offline gate

🔨 Phase 3 · observability

Telemetry & learning loop

  • ✅ decision telemetry contract + PII redaction
  • ✅ shadow sampling
  • 🔨 retrieval growth loop (alias mining from logs)
  • 🔨 golden set + replay against real traffic

⏳ Phase 4 · gated / next

Scale & adapt

  • ⏳ SQLite queue + sagas (durable multi-day flows)
  • ⏳ live WhatsApp webhook + cloud overflow path
  • ⏳ comparative experiment vs portfolio datasets
  • ⏳ QLoRA / DPO — only when the written gate fires