Skip to main content

A semantic type system for SQL applications

The model proposes. The type system decides.

A language model writes SQL and stops there. A deterministic analyzer reads that statement against the meaning your schema declares, and only a certified result reaches the interface.

Nothing here scores the model’s output or asks it to behave. A statement either satisfies the contract or the type system refuses it, and the answer is the same on every run.

Ordinary SQLIncremental adoptionIndependent of any model

The chain

Every link checks the one after it.

Secure boot, applied to a query. The schema and your accepted declarations are the contract, the model only proposes against it, the analyzer verifies, and the interface renders what was certified. Four of the five links run today; the actor universe is designed and not built, and it says so where it stands.

  1. Typed contractlive

    Your schema and the declarations you accepted. A column carries money because someone accepted that claim, never because its name looked like money.

  2. Untrusted proposallive

    The model writes SQL and stops there. Nothing it produces runs, and nothing it claims about the data is taken as true.

  3. Deterministic verificationlive

    The analyzer reads the statement against the contract in milliseconds, and refuses it under a published code when it cannot hold.

  4. Actor universedesign

    Analysis, proposal and execution held inside the rows and columns one actor may see. This link is a design. Nothing on this page runs it.

  5. Typed presentationlive

    The certified result type selects the component. Every combobulet declares the result shape it can display, and only a match renders.

01Typed contract

Semantic types over your own schema.

Combobula refines PostgreSQL types with meaning, the way TypeScript refined JavaScript: full compatibility, incremental adoption.

A refined type can depend on another column. The invoice amount is not money in one fixed currency: it is Money<invoice.currency>, so every row reads its code from its own currency column, and the analyzer carries that dependency into the queries below.

None of it is guessed. A key or a foreign key means identity, an enum means a finite set, and a currency arrives because someone accepted the claim that it is one. What nothing declares keeps its physical type and says so.

Reading the schema…

starting the local PostgreSQL contract…

02Deterministic verification

Write ordinary SQL. Keep the declared meaning.

No new language. The analyzer reads the statement as you type and answers in milliseconds: the pin WHERE currency = 'PLN' narrows the dependent currency, so sum(amount) is legal and certifies as Money<PLN>.

Two authorities speak here, and the page never confuses them. The analyzer answers per keystroke and its answer is provisional. A certificate comes from PostgreSQL itself, and only a certified result reaches a combobulet.

Every example is editable. Break one, and the repair the analyzer publishes stands beside the editor.

No provisional diagnostics.

Draft · WaitingContract · Waiting

Starting the local PostgreSQL contract…

result typeanalyzing…

03Typed presentation

The result type picks the component.

A combobulet is a finished interface component: a chart, a table, a card you could drop into your own product. It renders certified data, and none of the type machinery shows inside it.

Every combobulet declares in its contract the shape of data it can honestly display. The certified result type selects, from the whole catalog, the ones whose contract it satisfies, and one of those takes the stage.

The opening example pins the currency with WHERE currency = 'PLN', so revenue certifies as Money<PLN> and the chart prints its amounts in złoty. Drop that pin and the currency varies by row again: the analyzer refuses the total with E217, and no combobulet renders until the statement pins one currency or groups by the currency column.

A refusal is as informative as a match. A greyed combobulet names the role this result leaves unfilled, and the band below it names the capability the type system cannot express yet, which is what makes the catalog readable as a roadmap.

Waiting for a checked presentation…

the catalog10 combobulets

Every combobulet, and what each one needs.

The lamp on a card says whether this result may take it. What a dark lamp is waiting for is written on the card when you reach it, by pointer or by Tab.

Installed here

Waiting for a certified result type…

Not installed yet10 unavailable

The type system cannot describe what these need yet. Every preview draws sample data.

  • Timelineneeds events with a durationLays dated events along one axis, so bursts and quiet stretches are visible without reading rows.
  • Calendar heatmapneeds a value per calendar dayColours each day of a calendar by how much happened on it, a year to a block.
  • Choropleth mapneeds geographic regionsShades a map by region, so one value per country or district can be compared across the map.
  • Image galleryneeds image URLsShows rows as their pictures with a caption under each, instead of as a table of links.
  • Multi-currency totalneeds currency conversionAdds amounts held in several currencies into one total, and states the rate it used.
  • Gaugeneeds percentage meaningReads a single number against the range it belongs to, from its target to its limit.
  • Funnelneeds ordered stagesFollows a count as it falls through ordered stages, and names the stage where it drops.
  • Invoice cardneeds entity linksRenders one row as the document it stands for, with its customer and lines reachable from it.
  • Audit logneeds event meaningReads a table of changes as what happened, who did it, and what the value was before.
  • Kanban boardneeds workflow statesSorts rows into the columns of the workflow they are moving through.

Catalog order: there is no certified result to rank them against.

What it refuses

Statements PostgreSQL runs and the type system will not.

Every published code arrives with its own prose and a statement to read it on, so this section is the registry rendered rather than a page someone wrote about it. 10 codes are published today. The catalog grows the day the next one ships.

diagnostic registry10 published

E217

A total whose currency varies by row

An invoice.amount reads its currency from invoice.currency, so each row carries its own code. One total over that column would add złoty to euro and print a single number that is true in neither. The type system refuses it until the statement says which currency it means: pin one with WHERE currency = 'PLN', or group by the currency column so that every output row carries one code.

showcasewaiting for the analyzer

No provisional diagnostics.

Run this case in the sandbox →

Nothing here is refused. This is the statement the type system accepts.

Try it yourself

This page is not a video.

PostgreSQL itself runs in your browser beside the analyzer, over the same demo schema the stages above read. Write anything: what the type system can certify, it renders, and what it cannot, it refuses in the editor while you type.

Database

commerceConnecting

PostgreSQL

PGliteRead-only

Schema is not inspectable yet.

SQL

No provisional diagnostics.

Combobulet

Starting PostgreSQL in this tab…

Move fast without shipping blind.

Early access is not open yet. The analyzer and the type system above run in your browser: what you see is what exists today.

Types that survive SQL.

So human intent survives AI-generated code.