Where it all started

Earlier in the year, I came up with an idea to make a Twitter-like interface for interacting with LLMs. I noticed that with the turn-by-turn design of typical LLM chat interfaces, I couldn't dive deeper into specific sections of the LLM's response.

But, I shelved the idea because I didn't want to take on more side projects without finishing the ones I'd already started.

Fast forward 5 months later, I saw delve: <max's thread>

It wasn't exactly what I had envisioned in my head - but it was close. It almost had an internet-surfing vibe to it. But of course, I thought my idea was better. delve needed more structure and interactivity. Clicking through links is nice and all, but what if I want to chat with a specific section of the response? My idea for a Twitter-like interface would maintain the clickability of delve without sacrificing the interactivity of normal LLM applications.

But that wasn't my primary reason for wanting to suddenly pursue my idea.

More "importantly", delve got a huge reaction on X and HackerNews. And I wanted a piece of that.

So I stayed up until 3AM on a weekday coding it up, and at the end of the sprint, I posted this: <twitter thread>

I didn't get the sexy virality I was hoping for. But I thought to myself: "Okay, I'll just have to make it into something that people can actually get some use out of." I spent the next couple weeks figuring that out.

I first went into the maze of auth. "My application needs user accounts!", I thought. But I quickly realized that it wasn't even an idea that had even proven its worth - not worthy enough of user accounts, anyway. I gave up and decided to release the raw version with no user accounts: just the pure interface. If the website got a lot of traffic, then I would know if it was an application worthy of further pursuit.

Two weeks later, the re-release was ready, under a new name: Lapin. This time, I was determined to get social validation.

I downloaded Screen Studio so that I could post a sexy demo video, complete with the stereotypical, nauseating zooming effects. I drafted multiple versions of X threads. Needless to say, it really felt like a "product launch" at the time.

I posted this: <lapin thread>

I got a couple views and likes. More than I had ever gotten on any of my posts or threads, anyway.

But still, I was disappointed. People just stopped using it after a couple hours. I had more ideas for features though, and I already knew of Lapin's shortcomings. It was prone to repetition; it didn't handle emotional threads very well; it misinterpreted the mini-prompt buttons, particularly the Give example button; and it wasn't multi-modal like a human-crafted X thread might be (like Cultural Tutor's threads).

"It's okay. I can just add the features that I want, and people will start to see what I see in Lapin," I thought. More lies, more lies. I was really chasing social validation, not a vision.

I spent the next weeks in fullf R&D mode, coming up with different prototypes for features. I made a model router to better serve different kinds of user messages. I collected portraits, images, and videos for a query service, and I crafted an online XML parser to support Lapin's multi-modal features.

But after making these prototypes and experimenting, I realized I had zero clue Lapin was actually, uniquely good at. I didn't really know where I was heading with Lapin. I soon called it quits.

Solving non-problems.

I struggle with this problem pretty often. I'll see a case where a feature doesn't work for a particular use case, and I'll have this huge urge to make a version that has my particular solution to the "problem". But in reality, it's just all tradeoffs.

The first thing I typically ignore about tradeoffs is context. Context is everything for tradeoffs, and in my case, I often miss the context in which products and features are built. I will see one particular feature, and think about why it's shitty in isolation. But the feature likely makes sense in context of the product's goals and mission.

Lapin was a classic mistake that fits into this category. I saw 1 thing that didn't fit my extremely niche use case, and decided to make a complete replacement.

Lapin's interface - with some refinement - might be useful for more niche problems. But I did things backwards: I went solution-first, then went searching for a problem that it could address.

An honest assessment of Lapin's features

There are two main components to Lapin's interface: modularity and tree-like explorability. The model's response is broken down into modular "tweets" - each of which can be the starting point of another thread.

Tree explorability is almost useless for most cases. I'd even wager that tree explorability is least needed when you want to situate yourself. This is why most messaging applications allow you to go only two levels deep. Slack, Messenger, Messages - they only allow you to go down into a sub-conversation. No (sub)^n conversations allowed.

It's definitely nice when you can remember where you are in the tree - which is almost exclusively when you're traversing it for the first time and creating it as you go. But it's a nightmare to traverse the tree again when you've forgotten the context of your initial exploration. In other words, finding things inside trees with multiple children is absolutely horrible when you're looking for a path instead of a specific node.

Since every piece of software fits into a larger system, you're most certainly not going to be spending all your time in one application. If you have 4 applications in your software toolkit, and you spend an equal amount of time in each application, you're spending 75% of your time outside of the application. Hard to sacrifice findability for explorability when you don't even spend that much time in the application.

Despite being the symbol of nature, trees are so horribly unnatural. Christopher Alexander touched on this in his 1965 essay A City Is Not A Tree.

So tree explorability is a pretty awful tradeoff for most software applications. What about modularity?

Modularity is more useful (and ubiquitous) throughout software. Notion blocks are the canonical example.

Virality != Usefulness

Virality and usefulness are negatively correlated in the space of software products.

Useful software is mundane because it fades softly into the context. It just becomes something you use without thinking.

The interface is not the product.

Not unless you know you have supreme execution power and quality.

A fantastic interface can make a good product great. But no interface can make a bad product good.

But not everything about Lapin was bad.

I decided to salvage what I had. After all, not all parts of Lapin were bad. In particular, I thought one part of Lapin could be useful: an online XML parser-interpreter that executes commands on the fly.

Lapin's multi-modal demands, combined with the necessity for streaming for LLM applications, meant that I couldn't leverage function calling from popular model providers. I needed to seamlessly process video, image, and text from a model's response - and there wasn't a simple way to do this.

I worked on the parser library for a few weeks. I slapped a name on it, released it to NPM, and dusted off my hands.

What's the library called?
It's called SaxaMLL. You can find the docs here, and the Github repository here. Start using it with npm install saxamll.

I closed the chapter on Lapin.