Skip to content

Method / Edition 01

A list you can keep.

The catalog is a YAML file, a database, and a page. Editing the first updates the other two through the same pipeline every time. Here is the contract and the moving parts.

01 / Source

One YAML file is the whole catalog.

data/apps.yaml is the source of truth. Every entry carries its name, logo, screenshot, official site, source repository, and description. No CMS, no admin dashboard, no hidden database edits.

data/apps.yamlread-only
- slug: t3code
  name: T3 Code
  tagline: The open-source control plane for coding agents.
  description: >-
    A control surface for the agents already on your machine.
  surface: web
  siteUrl: https://t3.codes
  repoUrl: https://github.com/pingdotgg/t3code
  logo: /apps/t3code/logo.png
  screenshot: /apps/t3code/screenshot.webp
  platforms: [web, macos, windows, linux, ios, android]
  agents: [claude-code, codex, cursor]
  license: MIT
  featured: true
  addedAt: 2026-09-18

The schema enforces HTTPS URLs, asset paths under /apps/, unique slugs, valid dates, and a non-empty surface type.

02 / Pipeline

Edit, validate, mirror, reload.

The sync is a full mirror inside one transaction. Add, edit, delete, or reorder entries; the database is rebuilt to match the file. An unchanged file writes no app rows.

01

Edit the list

Append an entry in data/apps.yaml. Keep the slug stable.

02

Add the images

Drop a logo and, when available, a 16:10 screenshot under apps/web/public/apps/<slug>/.

03

Validate and sync

bun run catalog:sync checks the schema and assets, then mirrors the list into the database.

04

Reload the surface

The API syncs on boot. The web reads /api/catalog once and filters locally.

shellread-only
$ bun run catalog:sync
Catalog valid · 8 apps · GUI 05 · WEB 01 · TUI 01 · IDE 01 · assets 16/16
Synced 8 apps from data/apps.yaml
  +8 added · ~0 updated · −0 removed · 0 unchanged
  database sqlite · rows mirrored · hash cd6fc1d4fb92

Idempotent

Sync twice and the second run reports zero changes. A hash of the normalized list is stored with the last sync time.

SQLite or Postgres

One Kysely schema, two dialects. Set DATABASE_DRIVER and DATABASE_URL; tables are created on boot.

03 / Contract

What every row has to answer.

The required fields match the question a reader asks before opening a product: what is it called, what does it look like, where does it live, and what does it do.

Field
Required
Notes
name
yes
The surface's public name.
tagline
yes
One line, under 160 characters.
description
yes
What it does, in 60–900 characters.
surface
yes
gui · web · tui · cli · ide
siteUrl
yes
Official https:// product page.
repoUrl
no
https:// source repository, when public.
logo
yes
Image under /apps/<slug>/.
screenshot
no
Image under /apps/<slug>/, when available.
platforms
yes
macos · windows · linux · web · ios · android
agents
yes
Harnesses it can drive.
license / status
no
Defaults: open source / active.
tags / accent
no
Up to eight tags; a hex accent.
featured / addedAt
no
Editorial flag and ISO date.

04 / Rules

Four rules, no leaderboard.

01

One entry, one surface.

Each app gets its primary form factor. Agent support is recorded as metadata, not used to inflate a category.

02

Official material only.

Logos and screenshots come from the product's own site or repository. They belong to the projects, not this index.

03

Fast is a feature.

The API sends one payload. Search, surface filters, and sorting happen in the client. No request per keystroke.

04

No paid placement.

This is a field guide, not a leaderboard. Curated order is editorial; it is not a score, and it is not for sale.

05 / Adding

Add a surface.

  1. 01

    Create apps/web/public/apps/<slug>/ and add logo.png plus a screenshot when available.

  2. 02

    Append the entry to data/apps.yaml. Keep the slug lowercase and stable; it is the URL.

  3. 03

    Run bun run catalog:sync. It validates the file and both assets before touching the database.

  4. 04

    Run bun run dev. The API re-syncs on boot and the web reads the new payload.

06 / Credits

What is borrowed.

The design language — warm monochrome, hairline rules, dense tabular type, and a restrained clay accent — follows the qualities of slopalytics.com. The type is DM Sans with DM Mono for labels. The stack is Bun, Next.js, NestJS, Kysely, Tailwind, and shadcn-style primitives.

Product names, logos, screenshots, and marks belong to their respective owners. They are used here to identify each surface. No endorsement is implied. Every screenshot links back to the product's official site.

Surface over scoreboard.