Inspiration
It started with a hoodie. One Black Friday I spent hours looking for one specific thing: high quality, a lot of personality, worth paying a bit more for. I found it at a small streetwear label whose whole world was gardening. That hit something. In high school I was treasurer of the gardening club, and we met after class to work the school's garden. A hoodie had that memory in it.
That's what people want from clothes now, I think. Something that feels like them. The problem is there's no good way to search for it. You can search "hoodie" or "streetwear" anywhere. You can't search "reminds me of a garden."
What it is
trenchcoat is a place to discover smaller apparel brands by what they're about. Every brand has a profile: what it makes, what it values, the styles and themes it works in, the vibe. Search takes any words you'd use to describe a feeling, and every brand page shows the brands that sit closest to it.
Save a brand to your closet as something you want or something you have. Make edits, which are lists you curate and can share. The more your closet fills up, the more the explore feed shapes itself around you.
How it works
The catalog started as roughly 900,000 Shopify apparel stores from an index of Shopify merchants. Ninety-two percent were rejected before a person or a model ever looked at them: too small, too many vendors, too few products, or no real brand behind the domain. The rest went through a classifier that asked one question, is this a real apparel brand, and then a second pass that wrote each brand's identity: a short description, six to ten key terms, values, styles, themes, and vibes. Around 60,000 brands made it into the database, and about 41,000 of them have a hero image and show up in feeds.
Images were their own project. A crawler visited each brand's homepage, lookbook, and collection pages, and a vision model scored the candidates for editorial quality, brand relevance, and no logos or text overlays. Sixty percent of brands got a usable image on the first pass.
Recommendations run on embeddings. Each brand's profile text, deliberately without its name, is turned into a vector and stored in Postgres with pgvector. "Similar brands" pulls the thirty nearest by cosine similarity, then re-ranks them by how many key terms they actually share, so two brands that are close in the abstract but describe themselves differently drop down. The explore feed takes the average of the vectors of everything in your closet and ranks the catalog against that point.
Search is hybrid. A query runs three ways at once: a fuzzy match on brand names, a full-text match on the profile text, and a vector match on the query's embedding. Names win if they hit, then text, then meaning, so "boho chic" finds brands that never used those two words.
The hardest problem
Design, and specifically understanding what the app was for. I went through several versions before it clicked that the brands are the product, not my interface. What people needed was fast: get to the brand's site, learn what it's about, save it somewhere, and slowly build up a set of brands that feels like an identity. Every version that added more of my own chrome between the person and the brand got worse. The current one gets out of the way.
The second hardest was the data. Descriptions, key terms, images, and filtering for 60,000 brands is a pipeline, not a script, and most of the work was deciding what to leave out.
What broke
The home feed sorted every brand by estimated sales to pick the top few thousand, which meant a full scan and sort of the table on every visit. Cold, that took five seconds. A partial index on the rows the feed actually uses took the warm query from around 170 milliseconds to 5, a 34× change, and cut the cold path by about five times. The same day I added a trigram index for name search and a cache for query embeddings. Most of the speed on the site comes from three indexes and one cache.
Two others I still think about. A sales-floor filter was written in cents but read as dollars, so for a while the minimum to get in was fifty thousand dollars a month instead of ten. And an enrichment update overwrote the country of origin on a fifth of the catalog with nothing, which I only caught because the origin filter went quiet.
The brand is the product. Every version that put my interface in front of the brands made the app worse.