SOUNDTRACK // IRON UNDER PRESSURE
JEZWEB // GRID OSv2026
JEZWEB

> product // l2chat // the making of

L2Chat
how it was made.

L2Chat started life on 9 December 2025 as Agentflow Chat Widget: an initial commit that crashed on undefined config and focus loss before the day was out. Two days later it had a rebrand plan. Five months and 326 commits later it is a live, multi-agent platform with its own content engine, admin dashboard, evaluation harness and fleet of deployed clients. The first week was all widget. Everything after that was infrastructure.

326
commits
154
calendar days
21+
agents deployed
50
active build days

The short version

It started as a floating chat bubble: a thin wrapper that streamed responses and rendered markdown. By end of December 2025 it had rich UI components: carousels, product cards, date pickers, star ratings, countdown timers, file upload, QR codes and a dozen more, all rendered inline in the chat. The name changed from Agentflow to L2Chat on day three. Then in January and February the product changed shape entirely: per-client agent architecture, Anthropic tool calling for UI components, a switch to AI SDK v6 multi-step tool calling, and the migration of nine previously ElevenLabs-hosted agents to the new self-hosted stack in a single commit.

February was the densest month: 157 commits, 24 active days, a content engine that scraped and indexed client websites into R2, a CRM module, a full admin dashboard with conversation analysis and Google Chat notifications, an interview-based quality framework that graded agent answers against ground truth, and a smart nudge system personalised from the content engine. By the time the commit log was written it had documented 21 deployed agents and a fleet MCP server at mcp.l2chat.au. The story of L2Chat is the story of a widget that became a platform, steadily, commit by commit.

● Dec 9–12 2025: first light

Widget to product in four days

Initial commit was 'Agentflow Chat Widget', and the same day brought three bug-fix commits for input focus loss, stuck thinking indicators and undefined config crashes. By day two the widget had star-rating feedback, copy-on-hover, extended markdown, keyboard shortcuts and quick prompts with emoji icons. Day three: a rebrand plan and the commit 'Rebrand Agentflow to L2Chat.' Day four: a multi-SDK provider architecture for AI SDK 5 and n8n, a welcome-state fix and dark-mode code block styling.

● Dec 10–12: the component sprint

Rich UI components in 72 hours

Product cards, carousels, date pickers and video embeds landed in one commit. Then countdown timers, sliders, file upload, QR codes and signature fields. Then stepper, review and comparison components. Then image, alert, link and divider. Then location, contact and pricing cards. The L2Chat custom block syntax was named, documented and iterated through triple-dash then quote-free formats across January: the parser was rewritten twice to get the LLM-authoring experience right.

● Jan 2026: infrastructure layer

Theming, STT/TTS, per-client architecture

Audio speech-to-text and text-to-speech via Cloudflare Workers AI arrived in early January. A CSS variable theming system replaced hardcoded colours. Visual style presets landed January 5. The big structural shift was the per-client agent architecture committed on January 31: each client gets their own Cloudflare Worker, their own R2 KB bucket and their own configuration: the monolith became a fleet.

● Feb 2026: the platform build

157 commits: CRM, admin, content engine, evaluation

February was transformative. AI SDK v6 multi-step tool calling replaced the older provider model on the 4th; the widget migrated to tool-only architecture the same day. Nine ElevenLabs-hosted agents were migrated to the self-hosted stack on the 6th. The admin dashboard with auth arrived on the 11th alongside a CRM module and email alert system across all 11 agents. An interview-based quality framework graded agent answers against ground truth. The content engine, website scraper, R2 storage, image classifier, semantic Vectorize search, landed across 20–28 February. The smart nudge system and exit-intent CTA shipped 26 February.

● Mar 2026: hardening and fleet expansion

Refactor, accuracy audit, MCP gateway

March opened with ChatWidget.tsx split into 13 extracted modules: the widget had grown large enough to need it. A content trust architecture and accuracy audit landed on the 27th, alongside a fleet MCP server at mcp.l2chat.au and per-agent invite links. New agents were added across the month. By 27 March the agent count in the docs stood at 21 deployed.

● Apr–May 2026: steady expansion

New agents, multimodal, model migrations

April brought native PDF and image attachment handling from tool results, a Clarky persona with worked-example email quality guidance, a paused mode for agents, and the evidence-report evaluation variant. Model migrations tracked Anthropic releases, Haiku 4.5 standardised across the fleet in February, Sonnet 4.6 rolled out in March with verify-before-speaking guardrails, Opus 4.7 migration merged in May. Each model upgrade is documented in the log.

git log: “feat(agents): migrate 9 ElevenLabs agents to L2Chat self-hosted”

6 February 2026. The platform had been built to replace a dependency. On that day it did.

Tried, measured, set aside: the judgement lives here as much as in what shipped.

● rebuilt

Delimiter and quoted syntax for UI components

The original L2Chat component syntax went through delimiter format, then triple-dash, then a quote-free text format, each iteration driven by how well the LLM could author it reliably. Legacy provider and delimiter syntax remnants were cleaned up on 3 March 2026.

● pivoted

ElevenLabs for agent hosting

Nine agents previously hosted on ElevenLabs were migrated to the self-hosted L2Chat stack on 6 February 2026. A backend options analysis was committed the week before: the log shows the decision was made deliberately, not because the old stack broke.

● rebuilt

Heavy markdown parser

marked plus DOMPurify was replaced with a lightweight custom markdown parser on 27 March 2026. The bundle had grown; the dependency was doing more than the widget needed.

● dropped

rbrmoving agent

Added March 2026 for a removalist client, removed April 9 with the note 'replaced by bestremovalists'. One slug, one business: the consolidated agent kept the work.

Want something built like this?

This is how we work: in the open, measured, honest about the dead ends.