Sunwoong Ha

AI agent engineer — production LLM agents that drive real browsers.

Montréal, QC · building agentic systems at Deck.co since April 2025

~$40k/moLLM run-rate removed from production, no quality regression
356tickets owned across 3 product teams
~100 / 134PRs merged / PRs reviewed
40public + private repos shipped

What I do now

AI Agent Developer · Deck.co

April 2025 – present · Montréal

Deck is an AI-native data platform: LLM agents log into third-party portals on a customer's behalf and return structured data and documents through an API. I work across the agent runtime — the loop itself, the browser tooling it calls, what it costs, whether it succeeds, and whether we can prove why. Three teams: reliability, throughput to new sources, and the v2 platform.

Cost — took the production LLM bill down by a ~$40k/month run-rate

  • Built the cost-attribution model first, because nobody knew where the money went. Modelled per-turn spend as the sum of context re-read across a run cache read = 0.1×, cache write = 1.25×, output = 5× — so a bulky tool result costs its size times the turns that follow it. Ran it over 34 real agent sessions and 1,424 deduped turns.
  • That found the actual bill: browser tool results were 28% of fleet spend — page snapshots 20.3%, JS-eval returns 8.1% — and up to 35% of a single heavy session. The two had opposite shapes (many mid-size snapshots vs. a tiny median with a 14k-token tail), so they needed different fixes.
  • Shipped the fixes and measured each on production data: payload trims −40% / −44% per result, stale-snapshot clearing, a tail cap on JS-eval, tool-schema and system-prompt trims −3.4–4.2k tokens/turn/agent, extended thinking off (that one alone killed a $150–200/day bump), prompt-cache checkpoints with high/low-water-mark eviction.
  • Then moved the fleet down the model tiers — Opus to effectively zero, then Sonnet to Haiku across the orchestrator, cold workers and every sub-agent. The Sonnet line went from ~$1,340/day to ~$5/day. Success rate stayed inside the normal production band and no incidents fired, on a path carrying ~166M input tokens a day.

Reliability — the failure modes of agents on hostile sites

  • Bot-detection handling: challenge detection at both probe time and run time (managed challenges, WAF interstitials, CAPTCHA vendors), including late-rendering challenges on heavy SPAs that a first-paint check misses. Collected WAF cookie names, block status codes and redirect counts as deterministic signals instead of guessing.
  • Built a proxy/browser rotation matrix — provider × tier × country × browser, run sequentially against a blocked source — to answer "which combination actually reaches this site" with data rather than folklore.
  • Fixed the misclassification bucket that made dashboards lie: MFA prompts and security questions reported as invalid credentials, internal errors reported as bad passwords, agents hallucinating a portal from the shape of a username. Wrong error categories mean wrong retries and wrong customer emails.
  • Crash and resource recovery: browser restart after renderer/COOP crashes, crash diagnostics (signal, shared memory, memory pressure) captured at the moment of death, per-call timeouts on JS eval so one stuck page can't burn a whole job budget, IPC-ceiling bugs in the browser extension bridge.

Determinism — making an agent's successful run repeatable and cheap

  • Record-and-replay of agent workflows, with the parts that make replay trustworthy: capture the post-login URL at record time and verify it at replay so a "successful" replay can't be sitting on a login page; stamp provenance on task inputs at fill time so a cached plan never replays yesterday's parameters.
  • Guided execution: per-sub-goal plans, parameter binding for task inputs and iteration variables, per-item iteration bodies, and in-session convergence so a run gets more deterministic while it is still running.
  • An inline tool-builder that writes a deterministic Python tool when the agent keeps improvising the same multi-step task — with a test-case oracle, a plan classifier, a build-until-it-passes loop, and a guard that refuses credential placeholders in generated tool bodies.
  • Agent memory, measured rather than assumed: login memory cut a real source from 84 steps to 10 — an 88% step reduction — while other memory paths turned out to do nothing, which is the more useful half of that finding.

Observability — you cannot fix an agent you cannot see

  • Built the task-run outcome metric the team now reads daily, with a per-source label, plus span attributes for source URL and task-run id, and tracking of which browser/proxy combination a session actually used.
  • Correlated LLM generations back to the browser session that produced them via baggage-stamped session ids, so a cost or quality question can be traced from a dashboard number to the exact prompt, tool result and screenshot.
  • Split token metrics by cache type and emitted cost, so the model-tier decisions above were arguments with numbers attached.
  • A failure-category taxonomy and classifier over the whole session population — e.g. errors as 13.7% of ~4,000 sessions, broken down by cause — turning "it's flaky" into a ranked list.

Models and platform

  • Fine-tuned Qwen3-4B (thinking) on collected Opus/Sonnet/Haiku agent traces on Vertex AI — distilling a frontier-model agent loop toward a small owned model. Built the trace-collection pipeline and training infra.
  • Ported the agent onto Bedrock Converse: structured output, streaming, cache checkpoints with client-side eviction, run guards and retries, plus routing judge/verifier services off direct vendor APIs. Evaluated alternative reasoning models on Bedrock.
  • Sub-agent architecture — hierarchical account discovery, mapper and procedure-writer sub-agents, per-source strategy prompts, and agent-generated per-source scripts that replaced hand-written per-account loops.
  • Internal automation nobody asked me to build: eight Slack/Notion/Linear/Pylon bots on Cloud Run with shared object-store state and Secret Manager wiring — new-client onboarding war-rooms, churn sync, ticket intelligence, an escalation bridge, and a daily digest.

This code is proprietary, so none of it is linkable. The open-source work below is the public analogue of the same expertise — agent tracing, failure classification, provider benchmarking — written from scratch, on my own time, against the same problems.

Open source — agent infrastructure

Playwright traces tell you what the browser did. Agent logs tell you what the model said. Neither tells you, across ten thousand runs, what fraction failed because of bot detection versus stale selectors versus bad credentials. That gap is what these repos are about.

agent-stack

Local-first toolkit for building, debugging and observing web-browsing agents. Four composable repos, MIT.

umbrella · schema + viewer + debugger + capture

agent-trace

Trace schema and Python tracer for agent browser sessions. Replay a run step-by-step; classify failures as agent decision vs. site change vs. antibot vs. credentials. On PyPI.

python · jsonl · pip install agent-trace

agent-debugger

Breakpoints for agent runs. Drops into pdb — and pauses the real browser — the moment a semantic event fires: antibot detected, login failed, MFA prompt, or your own predicate.

python · pdb · playwright pause

agent-viewer

Zero-dependency single-file HTML viewer. Drag in a trace, get the step timeline, screenshots and an antibot heatmap.

html · no build step

agent-browser

Agent-native browser. Shipping today as an MV3 extension that captures real sessions into the trace schema; an RFC for the engine-level fork it wants to become.

chrome mv3 · rfc

agentic-engine

One interface over autonomous agent-browser providers, with routing, fallback, a confidence gate that catches an engine claiming success on a login-failed page, and a graduation log.

python · 4 providers · pluggable

browser-bakeoff

The same authenticated task — log in, download the statement — run head-to-head across three AI-browser providers. Success is a real PDF on disk, not a claim.

typescript · benchmark · apples-to-apples

zero-browser

A browser capability where the method name is the trace event type — bridging compile-time effect declarations and run-time semantic events. Read a signature, know what its trace will contain.

python · effects · design experiment

Things I built and shipped

Matcha Scout web app: a search bar reading "quiet matcha near Mile End", a map of Montréal with pins, and a list of café entries with neighbourhood, distance and age.

Matcha Scout

A Montréal café guide assembled entirely out of text messages. You text an agent, it saves the place or searches what others added; photo-first, any language, self-correcting. Drafts stay private and publish an hour after you stop texting.

screenshot · running locally

cloudflare workers · d1 · twilio mms · agent loop
mtlpothole map of Montréal with orange traffic-cone markers showing vote counts, green cones for filled holes, and a sidebar ranking streets by votes.

mtlpothole

Montréal's community pothole map — report one, vote the worst up, watch them get filled. Cone markers carry their vote count, filled holes turn green, and the whole app talks to one store interface. Leaflet, no API keys.

screenshot · running locally

typescript · next · leaflet
claude-live viewer: a dark terminal-style feed of session events — prompt, Read, Grep, Bash, Edit — each with a timestamp, and a prompt box at the bottom to type back into the session.

claude-live

Live-streams a coding-agent session to a web page over SSE — prompts and tool activity, redacted by default (keys, tokens and JWTs scrubbed; never file contents). Optionally type back into the session from the browser.

screenshot · synthetic session, real UI

node · zero deps · hooks + sse
OPEN ISSUES MODEL SCORES budget relevance specifics composite 0.72 THRESHOLD 0.55 DISCORD shipped rest dropped

problem-bot

Lead-hunter for people selling agent work. Polls the repos where the buyers congregate, has a model score budget signal, relevance, specificity and archetype, and delivers only what clears the threshold — to a webhook you own, not a bot you have to host.

diagram

python · llm scoring · cron
DIRECTORY (STALE) LIVE CHECK 3.1 ★ · 2 sources 4.7 ★ corrected +1.6 4.4 ★ · 1 source 4.5 ★ confirmed 2.8 ★ · alias of row 1 merged · duplicate operator no phone listed unknown — never guessed

data-enrichment-skill

Turns "give me every X in area Y with contacts" into a sourced CSV. The value is reconciliation plus live verification, not scraping: aggregators copy each other's stale rows, and the live browser pass corrected paid directories by more than 1.5 stars on real businesses. Every gap is marked unknown rather than filled in.

diagram

agent skills · research fan-out · live verify
CALENDAR 14:00 standup next up in 5 min POLL 1/min CRON WORKER it rings KV: already called about this one

gcal-call-reminders

Your phone rings a few minutes before a calendar event and a voice tells you what's starting. One cron worker, nothing to keep alive, no inbound webhooks — and a key-value note per event so it never double-calls you.

diagram

cloudflare cron · twilio voice · kv
NARRATION every word lands on its beat RENDERED FRAMES OUTPUT 16:9 9:16 no after effects — pil + ffmpeg

mograph

Word-synced kinetic typography and deep-glow motion graphics from PIL and ffmpeg — no After Effects — plus three repair recipes: fill a dead gap with narration-synced animation, remove a person from a screen recording, and cut a 16:9 demo into vertical.

diagram

python · ffmpeg · agent skill
AGENT A for her human AGENT B for his human free thursday, likes small rooms thursday works, no loud bars agreed — thursday, 7pm, quiet place

a2a-date

Agent-to-agent dating: two agents negotiate on their humans' behalf and hand back a plan. An experiment in what happens to a conversation when the other side of it is also an agent.

diagram

python · multi-agent

Client and earlier work

Health-tech startup — contract Authentication, protected-health-data handling and payments on the backend, wired to the front-end signup funnel, shipped behind default-off flags.
2026
Wellness practitioner — site, payments and booking Static site on Cloudflare Pages with Stripe Checkout via Functions for recorded sessions, scheduling for live ones, transactional email — then handed over with a plain-language manual so the owner can change anything herself with an AI assistant.
2026
Co-founder — prod-accurate sandboxes for third-party integrations Two-person pre-seed effort: brand, GTM and accelerator applications alongside the product.
2026
Bliinx — software developer Montréal startup, 6 months. Analytics for revenue teams, embedded in the CRM and chat stack; measuring activation and adoption.
2021–22
Allema Global / Jungle — web developer 10 months. Client projects from brief to delivery, dealing with the clients directly.
2021–22

What I can build for you

Available for contract work alongside the day job — remote from Montréal, or on site if you're here. Fixed price and fixed scope, so you know what you're buying before you commit. The scoping call is free and I'll tell you if it's not worth doing.

Cut your LLM bill

$7,500 · ~2 weeks

I attribute your spend per tool, per turn and per model, ship the cuts that survive an eval, and hand you the attribution script so you can keep doing it after I leave. On the production fleet at work this took out a ~$40k/month run-rate with no drop in success rate.

Ship an agent that finishes the task

from $12,000 · ~4 weeks

One workflow end to end: log in, navigate, extract or download, with retries, failure classification and traces you can actually read. Playwright or CDP, MCP tools, your model of choice — plus an honest report on what it still can't do.

Internal AI tooling

from $4,500 · 1–2 weeks

MCP servers, agent skills, and bots that live where your team already works — Slack, Notion, Linear — deployed with proper secret handling and shared state. I run a fleet of eight of these at work.

Site with payments and booking

$2,500 · ~1 week

Static site, Stripe Checkout, scheduling and transactional email, live on your domain — plus a plain-language manual so you can change anything yourself with an AI assistant instead of paying someone every time a price moves.

Something else AI-shaped

let's talk

Evals, fine-tuning and distillation, scraping that keeps breaking, data enrichment, video and motion graphics, a prototype you need by Friday. If it's AI and it has to survive production, describe the problem and I'll tell you honestly whether I'm the right person for it.

sunwoongha1@gmail.com — tell me the problem, not the spec.

Outside the editor

Two reasons this is on the page: shipping a product needs the same nerve as filling a room, and a phone that doesn't scare you is a real engineering asset when you have to go ask a stranger why their portal broke.

Event host and organizer, Montréal A wine-and-cheese speed mixer (25 guests) and the Unemployed Builders Club at a gallery (14 guests, co-hosted). Format, venue, promotion, ticketing, hosting — filled both rooms myself.
2026
Telemarketing 300+ cold calls a day on a dialer to business owners. Opening, first objection, close for the next step. The phone stopped being scary.
2024
Event crew and service Kitchen, setup, security and green-team work across festivals, tastings and restaurants.
2022–25

Stack

Agents & LLMs — Claude Agent SDK, Bedrock Converse, MCP servers and tools, sub-agent architectures, prompt-cache economics, structured output, LLM-as-judge, fine-tuning (Qwen on Vertex AI), token-cost attribution.

Browser automation — Playwright, CDP, Chrome extensions/MV3, bot-detection and WAF signals, proxy strategy, agent-browser providers (Browser Use, Browserbase/Stagehand, Anchor, Bright Data).

Languages — Python, TypeScript/JavaScript, C# (production), Java, Swift, C++.

Platform — GCP (Cloud Run, Pub/Sub, Vertex AI, Secret Manager, BigQuery), Azure (AKS, Blob), AWS (Bedrock), Cloudflare (Workers, Pages, KV, cron), Docker, RabbitMQ, Redis, Terraform.

Observability — OpenTelemetry, Grafana, Loki, Prometheus/PromQL, LLM trace tooling, Metabase, BigQuery.

Ways of working — Linear, agent-assisted development end to end, and a habit of building the measurement before the fix.

Education

B.CompSc, Computer Science — Concordia University, Montréal Paused to build AI agents in production.
2023–26

Repository index

RepoWhat it is
agent-traceTrace schema + Python tracer + CLI replay for agent browser sessions
agent-debuggerpdb breakpoints on semantic agent events
agent-viewerSingle-file trace viewer with antibot heatmap
agent-browserMV3 capture extension + RFC for an agent-native browser
agent-stackUmbrella for the four above
agentic-engineProvider-agnostic agent-browser engine, routing + fallback + confidence gate
browser-bakeoffThree AI-browser providers on one authenticated task
zero-browserEffect-declaration ↔ trace-event bridge
claude-liveStream a coding-agent session to the web over SSE
problem-botLLM-scored lead-hunter over GitHub issues
data-enrichment-skillSourced, live-verified local-market CSVs
mtlpotholeCommunity pothole map for Montréal
sf-trip-skillStructured city reconnaissance dossiers
a2a-dateAgent-to-agent dating experiment
matcha-scoutSMS-native city guide (private)
gcal-call-remindersPhone call before your calendar events (private)
mographKinetic-typography + video repair recipes (private)
better-claude-rcDrive a desktop coding agent from an iPhone over Tailscale (private)
teach-yourself-csSelf-study notes
portionifyGrocery portioning app (Svelte)
openplayerOpen-source music player (React)
halbertNode scraper for a copywriting archive
covid-tweets-data-crawlingTweepy + Firestore ingestion pipeline
stay-hydratedArduino tilt-sensor hydration nag
simplecalAndroid calendar