Skip to content
Buse Turgay Sönmez

Design Engineer, Belgrade

Hub

Hub is where my projects start. I choose the decisions for a new build, from stack and design system to motion and depth of UX work, and it composes a setup contract agents can follow. The same data is open to agents through an MCP server with 13 tools. One pure function serves the app, the server and the tests.

  • 2026
  • MCP
  • Agents
  • Next.js
  • Tests
  • Self-hosted

In short

My part
Product, interface, architecture and review. Built with Claude Code.
Stack
Next.js 16, React 19, TypeScript, Tailwind v4, Base UI, Drizzle, PostgreSQL
MCP server
Streamable HTTP, stateless, bearer tokens, 13 tools
Prompt library
60 blocks in 9 categories, 20 cross rules, 16 contract sections
Tests
203 cases in 15 files, 51 of them on the compose engine
Data
12 tables
Hosting
Docker, on my own server

What it does

A new project starts with the same questions. Which framework, which design system, how much motion, is there 3D, how deep does the UX work go, what is the accessibility bar, which browsers. In Hub each answer is a block, and there are 60 of them. I pick, and the composer writes a setup contract in Markdown: the stack, the install commands, the skills to load, what not to do, and the acceptance criteria.

Around the composer sit the things I kept reaching for while working: brand palettes in OKLCH with their contrast results, notes, tasks with due dates, the tasks assigned to me in ClickUp, and a usage panel built from my own Claude Code transcripts.

One engine, three callers

The composer is a pure function. It takes a selection and returns Markdown, and it touches neither the database nor the request nor the browser. That is why the web interface, the MCP server and the tests all call the same code and get the same output. The rules between blocks are data as well: 20 of them say which block implies or rules out another, and an integrity test checks every reference.

Blocks live in code, not in the database. They show up in a diff, and a slug that does not exist is a type error.

What the agents may not do

The MCP server has no delete tool, on purpose: a misunderstood sentence in a chat should not be able to lose data. Closing a task works the same way. If the words match more than one task, the tool closes none and returns the candidates.

ClickUp is read only. The code sends it nothing but GET requests, and tasks are not copied into Hub, so the two lists cannot drift apart. There are two tokens, one for Claude Code and one for the remote agent, so either can be replaced without cutting off the other. With no token set, nothing gets in.

What the agent is handed

A contract pasted into a chat is read once. So the composer can also produce a package: a CLAUDE.md, a settings file with no destructive commands allowed, a setup script and a copy file. CLAUDE.md is read in every session, which means the rules are still there on the second day.

Controls

Speed
1.00×
--ground
oklch(0.985 0.003 85)
--surface
oklch(0.958 0.005 85)
--raised
oklch(1 0 0)
--ink
oklch(0.2 0.006 85)
--muted
oklch(0.43 0.008 85)
--faint
oklch(0.5 0.008 85)
--line
oklch(0.9 0.004 85)
--line-strong
oklch(0.6 0.006 85)
--accent
oklch(0.66 0.22 38)
--accent-ink
oklch(0.52 0.19 38)
--stage
oklch(0.152 0.004 85)
--radius-stage
36px
--radius-stage-sm
28px
--radius-media
24px
--radius-panel
16px
--radius-field
10px
--ease-out-expo
cubic-bezier(0.16, 1, 0.3, 1)

This week · W39One WebGL context, three leaksGeometry · 2026