A painter at an easel outdoors, brush touching a half-finished landscape

Don’t write,
be Written.

Our Thesis

You don’t need
more swipes

you need
better
representation.

When someone swipes left on your profile, they’re not saying no to you; they’re saying no to the version of you they saw.

But you are more than that. We need a better way of representing you—

We believe the solution is ontology.

Our Methods

Discover through ontology.

By mapping your interests and experiences, we show you exactly where connections could begin.

  1. Learning about you

    We learn about you through the apps you already use—your music, videos, games, sports, and more. You can review, edit, or remove any detail at any time.

  2. Mapping your interests

    We identify recurring themes in what you watch, listen to, and do, then create a map that best represents you.

  3. Discovering connections

    We compare your map with those of your potential matches. The overlaps reveal the common interests and experiences that could spark something meaningful.

  4. Making the introduction

    For each potential match, we create a personalized introduction that highlights your common ground.

Our standouts

Why Written?

  • Fast Onboarding

    No more typing. Connect your apps to Written and sit back. We learn what you like to build your profile.

  • Full representation

    Written learns about you beyond a handful of random facts. The more apps you connect, the more vividly we can bring your personality to life for your potential matches.

  • Relatable profiles

    Connection begins with common interests and experiences. Written’s ontology-based algorithm highlights the language you share with each match, so you don’t miss out on someone worth knowing.

  • Meaningful Icebreakers

    Our research found that the first three exchanges can make or break a connection. Start with what you’re both passionate about and skip the small talk.

  • No Pay-to-Play

    Everyone deserves a fair chance at connection. Nobody should pay to be seen. Subscription offers extra conversation hints, not visibility.

  • Anti-Fraud Detection

    Written is obsessed with safety. Our system analyzes signals across connected apps to detect inconsistencies, flag malicious accounts, and make fake profiles harder to create.

  1. Written

    How the machine works

    A working description of the product and the system behind it, written for the people who build companies and fund them.

    It is deliberately plain. Every section names a mechanism, says what it takes in, what it refuses, and what comes out. Where a number appears it was measured on the system as it stands, not projected.

    Second draft, September 2026.

  2. Contents

    1. What the app does4
    2. Distillation: the connectors5
    3. The record and the sync6
    4. The vault7
    5. Capture against promotion8
    6. The resolver9
    7. The model lane on A100s10
    8. The ontology grammar11
    9. Predicates and propagation12
    10. Where the dictionary came from13
    11. How a term is minted14
    12. Scoring and the revision15
    13. Reciprocal editing16
    14. Introductions17
    15. Icebreakers18
    16. Privacy as structure19
    17. What has been measured20
  3. 1

    What the app does

    Written is an iPhone dating app with one idea: a profile should be extracted, not typed. A person connects the apps they already use and the system builds a representation of them from what those apps hold.

    Four tabs. Explore is the feed: a person appears repeatedly with different photographs and different lines, and the line is chosen for the reader. Chat holds invitations and conversations; every thread opens with an icebreaker built from what the two people share. The garden is where sources are connected, one tap each, and it grows a stage per source. Memories is the person's own page of terms, where each can be kept, edited or struck off.

    Around those: a dynamic profile a match may read, bookmarks, and blocking that the blocked person is never told about.

  4. 2

    Distillation: the connectors

    Every Apple source is one system sheet and no password: MusicKit for the library, EventKit for the calendar, HealthKit for activity, the media library for podcasts. YouTube is OAuth with PKCE and no client secret in the binary.

    Each connector reads everything the granted permission reaches and nothing it does not. Apple Music yields library songs, albums, artists, playlists and their contents, recently played, heavy rotation, recommendations and ratings. YouTube yields subscriptions, liked videos and playlists; watch history is not reachable and is not claimed. Calendar yields five years either side, walked outward from today, so a ticket bought for November exists. Health yields workouts, daily activity and a 24-row profile of which hours a person is active.

    Independent requests run concurrently, every pagination is capped, and a per-item fetch that cannot be capped is treated as a defect.

  5. 3

    The record and the sync

    Every source normalises into one row shape: source, data type, item id, name, creator, detail, a key=value string for platform quirks, and the time collected. The schema does not widen for a new source; the quirk string does.

    The device replaces its copy per source on each run. The server appends. A second distillation of a 1,208-row music library appended 100 rows and no duplicates, because the append compares each item against its latest stored version, excluding the timestamps.

    Transport is PostgREST over Postgres with row-level security as the authorisation layer: every table's policy is the account's own id, and reads go through views that return the latest row per item across runs, a union rather than a sum. The server is the source of truth; the phone keeps a cache and rehydrates from the server on a new device.

  6. 4

    The vault

    Beside the legacy record, each connector run also writes a typed envelope to an encrypted vault. The write goes through one function that the ingestion identity may call and nothing else; that identity holds no table privileges at all, so leaked, it could put rows in and read none back.

    Encryption is envelope encryption under AWS KMS: a data key generated per call, wrapped under a rotating key-encryption key, with a separately keyed HMAC for lineage. The ingestion role may generate keys and encrypt and cannot decrypt. The worker role may decrypt and cannot generate keys. Neither can schedule a key's deletion. The key and the rows travel in one statement so ciphertext never exists without the key that reads it.

    Erasure in the vault redacts rather than deletes: state set to deleted, both payload columns nulled, the evidence chain intact. Crypto-erasure of a person deletes their wrapped-key row, never the master key.

  7. 5

    Capture against promotion

    Capture broadly; promote narrowly. A run captures whatever a source returned. A scope is a triple of source, data type and action, and a row with no action belongs to no scope and is never promoted. Every capture is stamped partial, never complete, because every read is capped and a complete snapshot would let an item's absence be read as its removal.

    Evidence is written by ingestion while the run is open; a trigger refuses an observation whose run has closed. Finalisation enqueues the worker after the run closes. The queue is Postgres itself: leased jobs claimed with skip-locked selects, lease tokens, attempt limits, and a fail-closed default that marks an unknown job dead rather than done.

    The worker is a Lambda in the same region as the database. It reads ten tables and writes two, enumerated and asserted from the catalogue by migration, so a table added later gets nothing until its own migration grants it.

  8. 6

    The resolver

    Before any model runs, a deterministic resolver maps each observation against the catalogue: concept labels, aliases, stable identifiers such as a YouTube channel id, and authored imports. A match at this stage costs nothing and is reproducible, which is why the model is only asked what the resolver missed.

    An ambiguous name resolves from its entry's context in identity-strength order. First, a relation stated in the entry itself: a member of a group, a performer of a song. Second, a catalogue join against the terms already resolved in that entry. Third, the shape of the source: a music row's title is a song and never a television series. Fourth, the person's own library ranks survivors and never decides. What is still ambiguous holds as a user-scoped provisional identity: evidence attaches, the person may keep or strike it, and nothing global is minted from it.

    Within an entry the person anchors; failing a person, the franchise; failing that, the work.

  9. 7

    The model lane on A100s

    Open-vocabulary discovery runs on Qwen, served by vLLM on AWS A100 80GB GPUs behind an asynchronous SageMaker endpoint. Its only job is to recognise a meaningful term absent from every existing route. Extracting something the catalogue already knows is a regression, never the success criterion.

    One request carries up to eight items and an allowlist of fields: title, channel label, a description excerpt, tags, performer, composer, album. It carries forty candidate parents as id and label pairs and nothing about whose request it is. Decoding is grammar-constrained by a JSON schema with no optional properties, no pattern and no null inside an enum; the shapes outside that set slowed generation to minutes per prompt and were removed.

    The model may never emit an identifier, an authority state, SQL, a URL or a tool call. Its offsets are code points, repaired against the source text before validation. Measured: 7.3 to 8.0 items a second per card, 90 percent accepted.

  10. 8

    The ontology grammar

    Closed grammar, open nouns. The model invents strings and selects everything else from fixed vocabularies.

    Eight cardinal roots, immutable by check, by trigger and by a migration that proves a ninth is refused: person, group, organization, work, franchise, activity, concept, event. Seventeen wire families the model may name, twenty-three the store may hold, and a pinned map between them; a family and a root that disagree are refused as one surface telling two stories. Fifteen mention roles. Twelve relation predicates on the wire and a thirteenth, broader, in the store. Five user predicates. Five reasons to abstain.

    The grammar lives in four artifacts pinned to each other: the authoring workbook, the wire schema, the Python validator, and the database's check constraints. A build refuses unless they agree, which is what keeps the vocabulary from forking.

  11. 9

    Predicates and propagation

    A relation is typed. The registry holds fifty-five predicates with subject and object families, the authority a relation must reach before it may be walked, and whether the model may propose it. The model may verify none of them.

    Each predicate carries a propagation weight, λ. Evidence on a term conducts along promoted edges scaled by λ, so a person holding two films of one franchise trickles weight to the franchise from both at once; part-of-franchise conducts at 0.45. The registry is versioned and a change is a migration.

    Source-action integrity is absolute: a like is not a watch, a library item is not a play, a subscription is not interest in every member of a channel, a booking is not attendance. A stated relation is grounded if its object appears in the source entry, corroborated if an external catalogue connects the two, and otherwise a candidate that conducts nothing. A model repeating itself twice is one witness, not two.

  12. 10

    Where the dictionary came from

    No vocabulary is typed in. Every term arrives from a rule, and named examples are acceptance tests for the rule rather than rows.

    Whole domains are imported from Wikidata under CC0: a class is walked by instance-of and subclass-of, depth governed by a sitelink floor that states notability as a number the source itself gives. Identity fences keep a walk honest; countries as cultures need an ISO code or a literal instance statement, or a Roman province arrives as a culture. Official short names are read through statement nodes so "China" is not hidden behind a preferred-rank label.

    Creators are minted from music libraries as they are met. Authored imports carry the decade-by-genre grid whole. YouTube channels enter as stable identities from their ids. Every term enters one dictionary with a family, an origin and, per hub, at most one placement, and any number of hubs: genre and a person's world, a work and a movement.

  13. 11

    How a term is minted

    The authority order is structural, never arithmetic: model-proposed provisional, displayable suggestion, the person's keep or edit, catalogue mint, confirmed mapping evidence, scorer, assertion.

    A kept term enters the governed minting transaction. It is checked for collision against existing concepts and aliases, allocated one global identity, given redirects from the labels that reached it, and thereafter resolved deterministically. Future occurrences never make a second model call and never produce a duplicate concept.

    When the system sees a work it asks first whether there is a franchise: registered, it links; clearly present and absent, it mints through the franchise lane. Most works have none and the answer is usually no; the ask is mandatory. Identity mints; weight measures. A term whose identity is still ambiguous is never minted globally and never merged across people.

  14. 12

    Scoring and the revision

    The scorer computes, per person, an assertion per concept from accepted mapping evidence. Weights depend on source and action, and independence is counted by group, so two calendars agreeing is one diary reached twice, not two witnesses. Four confidence domains are kept apart and never collapsed into one number.

    A run's identity is the person, the revision, the ontology version, the resolver and the scorer. Deploying code re-scores nothing; a new distillation, a new ontology version or a new model id does. The revision means which version of the inputs the scores were computed against. It moves when the inputs move, when a suppression redistributes weight, and not when a state changes. It is monotonic and never walked back, so a page goes blank rather than stale.

    Inferred assertions retire on disconnect and revive on reconnection. What a person typed is a declared assertion and survives.

  15. 13

    Reciprocal editing

    Every term on a person's page can be kept, edited, or struck off with a reason. The tap is immediate: a strike suppresses the proposal for that person now. It is also an append-only event, and the event teaches the system.

    A review is priced in log-odds across six supervision domains: the person's affinity, the identity route, the classification root and parent, the predicate route, and the source-action route. A keep is +2.00 on affinity and +1.20 on identity. A strike for wrong entity is −2.00 on identity and only −0.50 on affinity. An edit counts the original proposal as a negative and is never a model success. Restore re-pends and erases nothing.

    Labels aggregate per stratum, most specific first, backing off until support is met, one vote per person per revision. A Beta(4,4) posterior becomes a multiplier clamped to 0.5–1.5, active only past five distinct people and ten labelled cards, and released as an immutable versioned calibration.

  16. 14

    Introductions

    Who a person sees is decided by a server-owned function, not the client. It filters on eligibility and on the viewer's own preferences, is rate-limited, and returns each card with the terms permitted on the matching surface. Any client holding the same anonymous key would get the same answer, which is the point.

    The matching surface may use a term and may never name it; naming a person's term to another person is a separate surface with its own grant. A term inferred from one source alone never crosses to another person on that source's strength alone.

    The dynamic profile is the same representation read against the reader: a person with many interests is shown to a violinist with the violin first. The line on a card, the profile a match reads and the icebreaker in a thread are three surfaces over one representation, each with its own gate. School and bio sit behind a function that returns nothing to anyone without a live invitation or a conversation.

  17. 15

    Icebreakers

    An icebreaker has three parts: a bridge, a specific, and a verb. The bridge is a concept both people reach. The specific is the partner's own term under that bridge. The verb is chosen by the app in the reader's language. You both like anime; she is the one who loves One Piece.

    The bridge is computed as a dyad alignment between two people's assertions: for each shared parent, the viewer's term under it and the partner's, with graph distance, relation distance, embedding distance, transported mass, specificity and information value recorded alongside the path that reached it. Specificity and information value rank a named artist above a container, and stop a bridge so general that agreeing on it says nothing.

    A dyad is computed only for an authorised pair. The sentence differs per reader and the version shown to one is never shown to the other. It is generated once at match time and never recomputed behind a conversation.

  18. 16

    Privacy as structure

    Rules live in Postgres, not in which buttons exist. The semantic schema has row-level security on and no policies; access is decided by role grants and security-definer functions. Only three tables are readable about another person, and each has an argument.

    Health takes the same path as every source, but biological sex is refused at the wire by a per-row rule and never leaves the phone. Calendar titles are evidence and never appear in any projection another person can reach. Filed evidence expires at thirty days for every source, by a daily sweep. Blocking is enforced in triggers and functions rather than policies, because the blocked person must not be able to ask whether they are blocked.

    A deletion names both schemas or it is not finished. Account deletion is verified by running it, not by inspection, because a guard that refuses a cascade is invisible until the day someone leaves.

  19. 17

    What has been measured

    90%
    of model extractions accepted after offset repair; 9% without it.
    7.3–8.0
    items a second per A100, prefix cached, one call per item.
    14,501
    mentions from 5,387 items in about three minutes per shard.
    4.7% → 3.0%
    misassignment on a 200-term authored holdout after cross-hub placement; anchor incongruence 8.2% → 2.2%.
    100 of 1,208
    rows appended on a real second distillation, zero duplicates.
    629 of 649
    mentions misfiled in the release that taught the family-root rule; zero after the map was pinned.
    0.5–1.5
    the bound on any calibration multiplier, so feedback alone cannot silence or amplify a stratum into a different product.
  20. Don’t write, be Written.