Skip to content
HARBAN AI LABS

Project

The HARBAN platform: a research and evaluation publication built around provenance

This website, written up as an engineering project: content as code, schemas that reject unsourced facts, server-rendered pages, local-first bookmarks and a deliberately small Postgres footprint for enquiries and the newsletter.
Published
Reading time
6 min read

At a glance

Status
ActiveIn active development; details on this page may change.
Topics
AI engineering, Evaluation, Tooling
Source code
Not published

Stack

  • Next.js 16 (App Router)
  • React 19
  • TypeScript 6 (strict)
  • Tailwind CSS 4
  • Zod 4
  • unified 11 (remark / rehype)
  • Shiki 4
  • KaTeX 0.18
  • Drizzle ORM 0.45
  • PostgreSQL via node-postgres 8
  • PGlite 0.5 (local development)
  • Vitest 5
  • Playwright 1
  • ESLint 9

Overview

This page describes the HARBAN AI LABS website itself — the platform that publishes our paper breakdowns, benchmark and model data, and engineering guides. It is the first project we publish because it is the one we can describe completely: the code exists, and every statement in the "Results" section below is true of the codebase as it stands. The repository is not public yet, so for now readers cannot check those statements themselves; when it is published, we will link it from this page.

There are no usage, traffic or performance figures on this page. We have none that we are ready to publish, and we will not estimate them.

The problem

A publication about AI research and evaluation is only as trustworthy as its numbers. We designed against five specific failure modes:

  • Unsourced numbers. A benchmark score or model specification copied without a source cannot be checked and is easy to get wrong.
  • Mixed provenance. A vendor's own result, an independent evaluator's result and a result we ran ourselves are different kinds of evidence. Putting them side by side without labels misleads.
  • Blank read as zero. An empty cell is easily read as "none" or "0" when it really means "we could not confirm this".
  • Claims ahead of reality. A company that plans to offer services can easily describe them as available before they are.
  • Vocabulary drift. Free-text tags and hand-maintained lists slowly fill with typos and near-duplicates.

The goal was to make these mistakes hard to publish by construction, rather than relying on review alone.

Approach

Schema-enforced provenance

Every dataset (models, benchmarks, results, tools, services and more) and every Markdown front-matter block is validated against Zod schemas in src/lib/content/schema.ts. The schemas encode the editorial rules directly: a model fact cannot have a value without a source URL, an external benchmark result must cite its source, and a result labelled as our own must link to run logs. Facts we could not confirm are stored as null and shown as "Not verified" — never as a blank, a dash or a zero.

Content as code

Research breakdowns, articles and projects are Markdown files; structured data is JSON. Both live in the repository and change through the same review as code. npm run content:check validates every file, checks cross-references (for example, that every result points at a known model and benchmark) and renders all Markdown once. Tags come from a controlled vocabulary in src/lib/content/taxonomy.ts.

Server-rendered by default

Pages are React Server Components. Client-side JavaScript is reserved for small interactive pieces such as navigation menus, the theme switcher, bookmarks, copy buttons, the table-of-contents scroll-spy, the search palette and the forms. Filters are ordinary links with query parameters, so they work without JavaScript and can be shared. Our convention for charts is SVG rendered on the server, with an accessible name and description and a data table alongside — never a screenshot of a chart.

Local-first bookmarks

Saved items live only in the visitor's browser (localStorage). There is no account and nothing is stored on our side. Stored data is parsed defensively, because other scripts or the user can edit it, and the list is capped.

A small Postgres footprint

The database holds only what visitors submit: enquiries (with attachment metadata and an event history), newsletter subscriptions, correction reports and rate-limit counters. Everything we publish stays in the repository. The schema uses Drizzle ORM against PostgreSQL; in development, when no DATABASE_URL is set, an embedded PGlite database runs the same SQL dialect with no setup.

Architecture

There are three data paths. Markdown and JSON content passes through the Zod schemas and the controlled vocabularies before anything uses it; the validated content then feeds the server-rendered pages (with their metadata and JSON-LD), the /api/search index and npm run content:check. Visitor form submissions go through server-side handlers — validation, spam and rate-limit checks — into server-only modules and Postgres. Bookmarks never leave the browser. The diagram shows the same paths:

content/*.md ──┐
               ├─► Zod schemas ──► validated, typed content
data/*.json ───┘   schema.ts             │
                   taxonomy.ts           ├─► Server Components:
                                         │   pages, metadata, JSON-LD
                                         ├─► /api/search (BM25 index)
                                         └─► npm run content:check

visitor forms ──► server-side handlers ──► src/server/* ──► Postgres
                  validation, spam and     database, email,
                  rate-limit checks        storage

bookmarks ──────► localStorage (never leaves the browser)
ModuleResponsibility
src/lib/content/schema.tsZod schemas that encode the sourcing rules
src/lib/content/taxonomy.tsControlled vocabularies: topics, service statuses, source types, benchmark health
src/lib/content/data.tsLoads the JSON datasets, validates them and checks referential integrity
src/lib/content/documents.tsLoads Markdown collections and validates their front matter
src/lib/content/markdown.tsMarkdown pipeline: GFM tables, maths (KaTeX), syntax highlighting (Shiki), heading anchors, link hardening
src/lib/search/Dependency-free BM25 search over every content type
src/server/Server-only code: database, email, spam and rate-limit checks, uploads, storage
next.config.tsStatic Content-Security-Policy and other security headers

A few decisions worth recording, each documented in the code:

  • Front matter is parsed as YAML only. There is no JavaScript front-matter engine, so a content file cannot execute code at build time.
  • Raw HTML in Markdown is disabled. Link protocols are allow-listed; anything else is neutralised.
  • A static Content-Security-Policy. Per-request nonces would force every page to render dynamically, so the policy is set once in next.config.ts.
  • Search without a search library. The corpus is small, so an in-memory BM25 index with field weighting and prefix matching keeps ranking deterministic and easy to reason about.

Stack

LayerChoice
FrameworkNext.js 16 (App Router), React 19
LanguageTypeScript 6, strict mode with noUncheckedIndexedAccess
StylingTailwind CSS 4 with semantic colour tokens; light and dark themes
ValidationZod 4
Contentunified 11 (remark / rehype), Shiki 4, KaTeX 0.18, yaml 2
DataDrizzle ORM 0.45, PostgreSQL via node-postgres 8, PGlite 0.5 for local development
ToolingESLint 9, Vitest 5, Playwright 1
RuntimeNode.js 22.12 or later

Results

These are the things we can state as verifiable facts about the codebase today. They describe what the system enforces — not traffic, adoption or performance.

  • A model fact without a source is rejected. If a model entry gives a value such as a context window or release date without a matching source URL, validation fails: npm run content:check exits with an error, and pages that load the dataset throw instead of rendering, so the build fails too.
  • Benchmark results need provenance. An external result without a source URL, or a result labelled as our own without a link to run logs, fails validation.
  • Impossible numbers are rejected. A percentage outside 0–100, or a confidence interval that does not contain its value, fails validation.
  • References must resolve. A result that names an unknown model or benchmark fails the integrity check.
  • Tags cannot drift. A topic outside the controlled vocabulary fails validation.
  • Paper breakdowns carry their source. Each needs the paper's https URL and the date its details were checked; arXiv IDs must match arXiv's format.
  • Placeholders do not ship. The content check fails on a Markdown body that still contains to-do markers or filler text, or one shorter than 50 words.
  • Services are not over-claimed. Service statuses come only from data/services.json, and every service listed there is currently marked "planned".
  • Production refuses unsafe configuration. In production, configuration validation fails without a database URL, a security secret of at least 32 characters, and the public site URL.
  • Search is read-only and bounded. /api/search truncates queries to 200 characters and clamps the number of results to between 1 and 50.

Not built yet

  • Accounts. There are none. The bookmarks module documents the plan: when accounts exist, the local store becomes an offline cache that syncs to the server.
  • A client portal. The enquiries table reserves optional organisation and client-user columns for one; nothing uses them yet.
  • Our own evaluation results. The schemas support results we run ourselves, with required run logs, but none are published yet. Every benchmark result in the data today is labelled as either vendor-reported or third-party.
  • Public source code. The repository is not public yet.

Status

Active. We will update this page as the platform changes.

Statements on this page describe the project as it stood on 28 Sept 2026. If something here is wrong or out of date, tell us and we will correct it.

Report an issue with this page

Spotted a wrong number, a broken source or something out of date in “The HARBAN platform: a research and evaluation publication built around provenance”? Tell us what and, if you can, link the correct source.

Required. At least 10 characters.

Model registry/models
Benchmarks/benchmarks
Paper breakdowns/research
AI tools directory/tools
Work with us/work-with-us