HNHacker News
TopNewBestAskShowJobs

wim

732 karma · joined October 2, 2008

Building https://thymer.com - a new IDE but for notes and tasks (local-first, encrypted and multiplayer)

Co-founder Papyrs. Wrote hobby OS, TriangleOS.

Feel free to contact me, wim at stunf.com or https://x.com/wcools/

submissionscomments
wim··on Air Conditioning Is Not a Luxury, It Is a Necessity
And AC can heat too! For example, in some EU countries gas boilers are still a huge thing, even though increasingly archaic. At the same time many of its users denounce AC because of reasons, apparently missing the fact that an AC is an (air-to-air) heat pump. Incredible how Big Boiler somehow convinced people to keep heating their houses by burning gas in these contraptions while ACs could do the job with much higher energy efficiency while also cooling the house in summer (and yes many places with these gas boilers have _hot_ summers these days)!
wim··on How Europe is killing makers and micro-entrepreneurs
This is par for the course when it comes to EU regulation unfortunately. The EU should really make a choice here: either there can be EU-wide regulation but Member States can't impose their own implementations or overlapping/competing national laws, or regulation should be left to Member States. You can't have both and pretend to be a single market.
wim··on Extensible Software in the age of LLMs
We're building a collaborative IDE but for notes/tasks as a local-first web app [1], built to be malleable with plugins. In terms of tradeoffs we're taking a middle road I guess: the app is malleable, but plugins stay contained within the web app.

Because of end-to-end-encryption and privacy/ownership concerns, we can't run plugin code on a server node somewhere. But for some types of apps, server-side extensions alone also feel too restrictive. An advantage of a malleable app over just one-shotting a completely custom app (and to be clear I think both will be popular!) is that extending and customizing something is often exactly what you want vs starting over, but you can't really do that when you can't do things like deeply customizing the UI. So you can just ask a (local) agent "add me this functionality" and it will likely be possible.

It's still sandboxed inside the browser though, so this way you can do things like permissions, allowing admins to restrict who installs team plugins and so on (which is also important for malleable multiplayer apps).

[1] https://thymer.com

wim··on Convergence is not enough
That's right, they become part of the replay and rejected using the same path, otherwise things like cycles might still happen. Rejected ops do stay part of the log though, so there's always ways to build time travel/version history or conflict UIs on top when needed.
wim··on Convergence is not enough
We're building a multiplayer IDE [1] but for docs/planning where docs needs to be trees/graphs (to support outlining, refs, transclusions and so on)

We can't just merge any type of operation by replaying unconditionally, because that can cause tree cycles for example. Like the linked list certain operations can be valid locally for an offline client, but not globally in the converged order.

Our sync engine distinguishes between different types of operations: unconditional operations and guarded operations.

Unconditional operations can't violate structural/data-model invariants. For example SetCompleted(task_guid, true). Simple last-writer-wins.

Guarded operations can mutate topology, like InsertMove(node_guid, parent_guid, after_guid). These are checked against the current state, not the state when they were created. During replay we first revert optimistic local operations and replay the incoming canonical operations in order. The mutator function for each operation validates the current state before applying it and if it would violate a condition (for example by creating a cycle because another client made another move in the meantime) it is deterministically rejected. In our case we also have an authoritative server so we can also use the same guarded operations for conditions beyond data structure, like permissions, so the AddUser(workspace_guid, user_guid) mutator function can check permissions state first for example.

[1] https://thymer.com

wim··on Original Apollo 11 Guidance Computer source code for command and lunar modules
This is such an interesting peek into the engineering of these sort of systems with very constrained resources at the time. Like any random file you open contains little pragmatic design decisions like this

https://github.com/chrislgarry/Apollo-11/blob/master/Comanch...

# THE POSITION OF THE MOON IS STORED IN THE COMPUTER IN THE FORM OF # A NINTH DEGREE POLYNOMIAL APPROXIMATION WHICH IS VALID OVER A 15 # DAY INTERVAL BEGINNING SHORTLY BEFORE LAUNCH. THEREFORE THE TIME # INPUT BY THE USER SHOULD FALL WITHIN THIS 15 DAY INTERVAL.

Better be back home in 15 days! ;)

wim··on Litestream VFS
I noticed the new release also includes "directory replication support for multi-tenant databases", great addition as well!
wim··on I built a faster Notion in Rust
We're building a new multiplayer IDE but for docs/tasks [1]. Local-first, real-time collaborative and end-to-end-encrypted sync. Not open source but self-hostable with a single binary and hackable with plugins (custom properties, views, code, etc).

[1] https://thymer.com

wim··on EU funds are flowing into spyware companies and politicians demanding answers
It's good they look into this, but if we're talking about spyware, I'd like to see more MEPs urging the Council to oppose ChatControl.

If that passes that's not just EU funds being misused but the EU directly mandating spyware on a continental scale!

wim··on GDPR meant nothing: chat control ends privacy for the EU [video]
Drop the “chat” and just call it “control”. The current proposal is so vague it would cover anything with online sharing/syncing people can sign up for. Any SaaS, any app, any service. Chat, email, file syncing, todo lists, doesn’t matter.
wim··on QNX: The Incredible 1.44M Demo
This was such a cool demo back then. There were many systems that could boot from a floppy, of course, but booting into a GUI with TCP/IP stack showing a real internet browser was really something!
wim··on I tried every todo app and ended up with a .txt file
Combining the feel of plain text with real structure is also exactly why we're building an "IDE but for tasks/notes" [1].

With structured apps (task managers, outliners) you lose the illusion of editing plain text, but plain text alone lacks things like structure, links, dates, and collaboration. We've spent the last few years building an editor completely from scratch to keep the ease of text editing while adding planning and structure.

[1] https://thymer.com

wim··on Linear sent me down a local-first rabbit hole
Funny how reasonable performance is now treated as some impossible lost art on the web sometimes.

I posted a little clip [1] of development on a multiplayer IDE for tasks/notes (local-first+e2ee), and a lot of people asked if it was native, rust, GPU rendered or similar. But it's just web tech.

The only "secret ingredients" here are using plain ES6 (no frameworks/libs), having data local-first with background sync, and using a worker for off-UI-thread tasks. Fast web apps are totally doable on the modern web, and sync engines are a big part of it.

[1] https://x.com/wcools/status/1900188438755733857

wim··on Copyparty – Turn almost any device into a file server
This is awesome! The demo is really fun, nostalgic 90s vibes, it even lets me play chiptunes :). Keeping all dependencies optional and just making it a single file is great too!
wim··on Local-first software (2019)
A backend can be part of the functionality though, such as for real-time collaboration and syncing. But you can have ownership and longevity guarantees for both the data and the service as long as you can eject [1] from the cloud and switch to self-host or back at any time, which is what we do for our notes/tasks IDE

[1] https://thymer.com/local-first-ejectable

wim··on Knowledge Management in the Age of AI
We’re working on a new IDE but for tasks/notes [1] which is end-to-end-encrypted and optionally self-hostable

[1] https://thymer.com

wim··on Litestream: Revamped
Very cool! This is so clever and makes deploying it so simple. I just wasn't able to use it yet because we'd have (many) thousands of SQLite DBs to backup. I quickly hacked something together using fanotify + SQLite's Backup API to have some copies at least, but I'm going to try to switch to Litestream if this amount of files would be supported by the wildcard replication.
wim··on Ditching Obsidian and building my own
Depending on the threat model you want to protect against, yes. For example, although a revoked user doesn't have direct access to data anymore, they could technically collude with us to get future encrypted messages and then decrypt them. At the moment rekeying is only possible by exporting a workspace, changing its key (with a command line tool), and then reimporting it.
wim··on Ditching Obsidian and building my own
The workspace data is encrypted with a (symmetric) workspace key. Each user gets hteir own encrypted copy of that key, using the user's public key. By wrapping the data-encryption key for each user the content is only encrypted once but each authorized user can decrypt it.
wim··on Ditching Obsidian and building my own
We're building https://thymer.com/ to do this. Real-time collaboration, local-first + end-to-end-encrypted (and optionally self-hosted).
wim··on Plain Vanilla Web
We're building a collaborative IDE for tasks and notes [1] from scratch without frameworks/dependencies.

Not saying frameworks are never the right answer of course, but it's as much a trade-off for complex apps as it is for blogs. Things like performance, bundle size, tooling complexity, easy of debugging and call stack depth, API stability, risk of hitting hard-to-work-around constraints all matter at scale too.

[1] https://thymer.com/

wim··on Stop syncing everything
Looks impressive! Using the VFS is such a fun "hack" :)

We developed our own sync engine for an offline-first IDE for notes/tasks [1] we're building, where the data structure is a tree (or graph actually) to support outlining operations. Conflict resolution is always the challenge, and especially with trees multiple offline players can optimistically commit local changes which would result in an invalid tree state once globally merged.

The way we handle this is by rolling back tree inserts when a client comes online and receives other tree insert deltas. From what I understand from the description of SQLSync, the best way to handle this would be to pull in a latest snapshot and then replay. Pulling in a full snapshot sounds rather expensive though. We have some sort of heuristic where we can do this if the number of incoming deltas would be very large, but for most offline syncing we never need it. Just curious how SQLSync defines these snapshots? Sticking with the note-taking example, in our case we can't really have a snapshot of a single "note" because of graph features like transclusions. Does SQLSync have some clever way to avoid having to send all state in order to "reset and replay"?

[1] https://thymer.com

wim··on Sync Engines Are the Future
We've built a sync engine from scratch. Our app is a multiplayer "IDE" but for tasks/notes [1], so it's important to have a fast local first/office experience like other editors, and have changes sync in the background.

I definitely believe sync engines are the future as they make it so much easier to enable things like no-spinners browsing your data, optimistic rendering, offline use, real-time collaboration and so on.

I'm also not entirely convinced yet though that it's possible to get away with something that's not custom-built, or at least large parts of it. There were so many micro decisions and trade-offs going into the engine: what is the granularity of updates (characters, rows?) that we need and how does that affect the performance. Do we need a central server for things like permissions and real-time collaboration? If so do we want just deltas or also state snapshots for speedup. How much versioning do we need, what are implications of that? Is there end-to-end-encryption, how does that affect what the server can do. What kind of data structure is being synced, a simple list/map, or a graph with potential cycles? What kind of conflict resolution business logic do we need, where does that live?

It would be cool to have something general purpose so you don’t need to build any of this, but I wonder how much time it will save in practice. Maybe the answer really is to have all kinds of different sync engines to pick from and then you can decide whether it's worth the trade-off not having everything custom-built.

[1] https://thymer.com

wim··on BYD says new fast-charging system could be as quick as filling up a tank
The car industry in Germany is being Nokia'd. The iPhone didn't win because the US had central planning.

I'm not convinced at all free market economics are holding us back. Rather other parts of the world are leapfrogging us despite not adopting it.

It was always obvious EVs would be the future. I remember being at a friend's party in Germany more than a decade ago, talking to some guests who worked in the auto industry. Told them about this new upcoming car company called Tesla and how it would transform the entire transportation sector and eat their lunch. The entire group laughed me out of the room and talked about the amazing research they were doing on "clean diesel" or something, I kid you not.

It's simply a combination of innovator's dilemma, complacency and no appetite for risk taking.

wim··on Local-First and Ejectable
Yep love CRDTs but I think we are in agreement that it's a matter of trade-offs whether or not to use a backend (beyond a shared fs service). The idea with ejectable is that if you've decided the trade-off of a backend is worth it to enable certain features/UX, then it's a good way to ensure longevity of the entire app for users.
wim··on Local-First and Ejectable
Hah yes it took a while, thanks for following! When we started the blog we initially thought of building something very small, but along the way realized that the kind of thing we would really love using ourselves would be a much bigger project. It basically involved building a completely new editor from scratch, sync engine, adding multiplayer and end-to-end-encryption, and so on. It would definitely have been faster to take shortcuts and use many existing libs and frameworks around editors, UI and syncing, but then it wouldn't have been something meaningfully different I think, as you point out there's plenty of options in the space so why take the same approach.

We're very much still working on it though and it's finally at the point where it's just some polish, so pretty sure next Q.

wim··on Local-First and Ejectable
Sure but not all backend operations can always be mapped to flat files on Dropbox, like when you have certain real-time collaboration features, syncing on graph/tree-like data structures, or perhaps permissions in case of a company tool. That's why longevity of the "data" aspect is usually easy to solve when a copy of the data is already local, but then you still risk losing a part of what it is that makes the app when there is no way to run the app's syncing backend yourself.
wim··on Local-First and Ejectable
Many apps have some sort of backend or server component to it though, for syncing or multiplayer features. Usually that part disappears when you don't have the option to eject and self-host.
wim··on Local-First and Ejectable
One of the important points of an ejectable app is that you can easily move back and forth between cloud and self-hosted.

You can always start with the cloud version and then transfer to self-hosted if you change your mind and continue right where you left off. Not just that, you can also move from self-hosted back to cloud. That makes it easier to get start with a service because you're free to change your mind without lock-in or risk of painful migrations.

wim··on Docs – Open source alternative to Notion or Outline
Yep, should work!
Page 1 of 4Next →