Hugo — Fund Formation Platform
Side letter management, MFN tracking, clause library, and investor lifecycle for fund formation lawyers.Hugo is a Cloudflare Workers application that helps fund formation teams manage the side letter negotiation process across multiple funds and investors. It tracks clauses, MFN elections, document parsing, and the full LP onboarding lifecycle from first close through final close.
Key capabilities
Per-fund and cross-fund clause management with version history, genealogy trees, and materially equivalent clause grouping.
Commitment tracking, side letter status (draft → in negotiation → signed → countersigned), KYC, sub-doc status, LPA status.
Configurable most-favoured-nation eligibility rules (basic rules, general rules per category, individual rules per LP, clause exclusions) with automatic cascade detection.
Upload .docx side letters, AI-powered clause extraction and classification via Claude through the AI Gateway.
Structured event emission for every mutation with MFN eligibility cascade diff, feeding a per-fund intelligence system.
Per-commitment follow-up tasks with priority, due dates, and completion signals.
At /intelligence: pick a clause, filter by LP profile (category, country — multi-select, size band) and fund profile (type, vintage range, min commitment), see every variant we have on record. Built on the shared parseComparableFilterFromQuery + loadClauseVariantsInScope engine in src/services/comparables.ts. Replaces the legacy /statistics dashboard and Negotiation Brief.
Generate side letters, election forms, and master side letters as .docx.
Architecture
| Layer | Technology |
|---|---|
| Runtime | Cloudflare Workers (single worker) |
| Framework | Hono 4.x (routing, middleware, JSX SSR) |
| Frontend | HTMX 2.0.4 (SPA-like navigation, partial swaps) + Tailwind CDN JIT |
| Database | Cloudflare D1 (SQLite) — 46 tables, 55+ migrations |
| Object storage | Cloudflare R2 — side letter .docx files, generated exports |
| AI | Cloudflare AI Gateway → Heimdall (Claude proxy) for clause classification |
| Queue | Cloudflare Queues — async document parsing (3 concurrent, 2 consumers) |
| Auth | Cloudflare Access (JWT) with mock-user fallback for local dev |
Worker shape
Hugo is a single Cloudflare Worker deployed at hugo.nordiclawfirm.com. It handles HTTP requests (Hono router), queue consumption (document parse jobs + dead-letter queue), and scheduled events (orphan sweep, cache pruning, R2 cleanup). All three entry points live in src/index.tsx.
Bindings
| Binding | Name | Purpose |
|---|---|---|
| D1 | DB | All application state — funds, commitments, clauses, MFN rules, events. Always accessed through the retry-wrapped c.var.db proxy (src/lib/db.ts). |
| R2 | DOCUMENTS | Side letter .docx files, generated exports. Keys built via src/lib/r2-keys.ts central helper. |
| AI | AI | Workers AI binding currently commented out in wrangler.toml — embeddings backfill is killswitched. Kept in src/lib/types.ts for the dormant code path. |
| Queue | PARSE_QUEUE | Async document parsing jobs. DLQ max_retries bumped to 5. |
Performance architecture
Hugo uses a shell-first rendering pattern on its highest-traffic pages (investor-detail, fund-detail, intelligence, library, cross-fund-library, global investors): the initial response returns the chrome + toolbar immediately, and a follow-up HTMX request streams the data-heavy body. This drops time-to-first-byte from ~500ms to ~30ms on those routes.
D1 queries are wrapped in a retryableDB proxy that retries transient errors (overloaded, locked, timeout) with exponential backoff. Always use c.var.db in handlers, never c.env.DB directly — the wrapper is installed by global middleware before any route runs. Queries exceeding 150ms are logged to Workers Observability for profiling. A D1-backed search_cache table with 5-minute TTL caches the cross-fund library aggregate. The MFN bundle is cached per-fund for 60 seconds.
Layered architecture
| Layer | Location | What lives here |
|---|---|---|
src/index.tsx | 1275 LOC | Hono router, global middleware, queue + scheduled handlers. Used to be 2200+ — chat / clause-search / lp-profile extracted to services. |
src/pages/*.tsx | ~30 files | Route handlers + JSX. Should be leaves — no cross-page imports. |
src/services/*.ts | ~20 files | Business logic: MFN engine, parse, export, MSL, chat-router, clause-search, lp-profile, lp-tasks, etc. |
src/db/*.ts | 16 files | Typed query helpers with LIMIT defaults. queries.ts holds canonical fund-level helpers; per-feature modules (admin.ts, mfn.ts, lp-tasks.ts, investor-import.ts, review.ts, funds.ts, commitments.ts, clause-tags.ts, etc.) absorb repeated SQL shapes. |
src/components/*.tsx | shared JSX | Layout, Sidebar, SearchModal, HelpModal, FullBleedShell, FormControls, LpSidebar, SideLetterRow, OpsTagsSection, ClauseDetailCards, etc. |
src/lib/*.ts | utilities | db (retry proxy), format, country, r2-keys, cache-headers, api-responses, log, htmx, etc. |
src/middleware/*.ts | 2 files | auth.ts (fail-closed CF Access JWT), fund-access.ts (per-fund grants). |