The best Hacker News stories from Show from the past week
Latest posts:
Show HN: I rewrote my Mac Electron app in Rust
A year ago, my co-founder launched Desktop Docs here on HN. It's a Mac app we built with Electron that uses CLIP embeddings to search photos and videos locally with natural language. We got positive feedback from HN and our first paying customers, but the app was almost 1GB and clunky to use.<p>TLDR; rebuilding in Rust was the right move.<p>So we rewrote the app with Rust and Tauri and here are the results:<p>- App size is 83% smaller: 1GB → 172MB
- DMG Installer is 70% smaller: 232MB → 69.5MB
- Indexing files is faster: A 38-minute video now indexes in ~3 minutes instead of 10-14 minutes
- Overall more stability (old app used to randomly crash)<p>The original version worked, but it didn't perform well when you tried indexing thousands of images or large videos. We lost a lot of time struggling to optimize Electron’s main-renderer process communication and ended up with a complex worker system to process large batches of media files.<p>For months we wrestled with indecision about continuing to optimize the Electron app vs. starting a full rebuild in Swift or Rust. The main thing holding us back was that we hadn’t coded in Swift in almost 10 years and we didn’t know Rust very well.<p>What finally broke us was when users complained the app crashed their video calls just running in background. I guess that’s what happens when you ship an app with Chromium that takes up 200mb before any application code.<p>Today the app still uses CLIP for embeddings and Redis for vector storage and search, except Rust now handles the image and video processing pipeline and all the file I/O to let users browse their entire machine, not just indexed files.<p>For the UI, we decided to rebuild it from scratch instead of porting over the old UI. This turned out well because it resulted in a cleaner, simpler UI after living with the complexity of the old version.<p>The trickiest part of the migration was learning Rust. LLMs definitely help, but the Rust/Tauri community just isn’t as mature compared to Electron. Bundling Redis into the app was a permissioning nightmare, but I think our solution with Rust handles this better than what we had with Electron.<p>All in, the rebuild took about two months and still needs some more work to be at total parity with its Electron version, but the core functionality of indexing and searching files is way more performant than before and that made it worth the time. Sometimes you gotta throw away working code to build the right thing.<p>AMA about Rust/Tauri migration, Redis bundling nightmares, how CLIP embeddings work for local semantic search, or why Electron isn't always the answer.
Show HN: I rewrote my Mac Electron app in Rust
A year ago, my co-founder launched Desktop Docs here on HN. It's a Mac app we built with Electron that uses CLIP embeddings to search photos and videos locally with natural language. We got positive feedback from HN and our first paying customers, but the app was almost 1GB and clunky to use.<p>TLDR; rebuilding in Rust was the right move.<p>So we rewrote the app with Rust and Tauri and here are the results:<p>- App size is 83% smaller: 1GB → 172MB
- DMG Installer is 70% smaller: 232MB → 69.5MB
- Indexing files is faster: A 38-minute video now indexes in ~3 minutes instead of 10-14 minutes
- Overall more stability (old app used to randomly crash)<p>The original version worked, but it didn't perform well when you tried indexing thousands of images or large videos. We lost a lot of time struggling to optimize Electron’s main-renderer process communication and ended up with a complex worker system to process large batches of media files.<p>For months we wrestled with indecision about continuing to optimize the Electron app vs. starting a full rebuild in Swift or Rust. The main thing holding us back was that we hadn’t coded in Swift in almost 10 years and we didn’t know Rust very well.<p>What finally broke us was when users complained the app crashed their video calls just running in background. I guess that’s what happens when you ship an app with Chromium that takes up 200mb before any application code.<p>Today the app still uses CLIP for embeddings and Redis for vector storage and search, except Rust now handles the image and video processing pipeline and all the file I/O to let users browse their entire machine, not just indexed files.<p>For the UI, we decided to rebuild it from scratch instead of porting over the old UI. This turned out well because it resulted in a cleaner, simpler UI after living with the complexity of the old version.<p>The trickiest part of the migration was learning Rust. LLMs definitely help, but the Rust/Tauri community just isn’t as mature compared to Electron. Bundling Redis into the app was a permissioning nightmare, but I think our solution with Rust handles this better than what we had with Electron.<p>All in, the rebuild took about two months and still needs some more work to be at total parity with its Electron version, but the core functionality of indexing and searching files is way more performant than before and that made it worth the time. Sometimes you gotta throw away working code to build the right thing.<p>AMA about Rust/Tauri migration, Redis bundling nightmares, how CLIP embeddings work for local semantic search, or why Electron isn't always the answer.
Show HN: Lazy Tetris
I made a tetris variant<p>Aims to remove all stress, and focus the game on what I like the best - stacking.<p>No timer, no score, no gravity. Move to the next piece when you are ready, and clear lines when you are ready.<p>Separate mobile + desktop controls
Show HN: Lazy Tetris
I made a tetris variant<p>Aims to remove all stress, and focus the game on what I like the best - stacking.<p>No timer, no score, no gravity. Move to the next piece when you are ready, and clear lines when you are ready.<p>Separate mobile + desktop controls
Show HN: My LLM CLI tool can run tools now, from Python code or plugins
Show HN: My LLM CLI tool can run tools now, from Python code or plugins
Show HN: PgDog – Shard Postgres without extensions
Hey HN! Lev here, author of PgDog (<a href="https://github.com/pgdogdev/pgdog">https://github.com/pgdogdev/pgdog</a>). I’m scaling our favorite database, PostgreSQL. PgDog is a new open source proxy, written in Rust, with first-class support for sharding — without changes to your app or needing database extensions.<p>Here’s a walkthrough of how it works: <a href="https://www.youtube.com/watch?v=y6sebczWZ-c" rel="nofollow">https://www.youtube.com/watch?v=y6sebczWZ-c</a><p>Running Postgres at scale is hard. Eventually, one primary isn’t enough at which point you need to split it up. Since there is currently no good tooling out there to do this, teams end up breaking their apps apart instead.<p>If you’re familiar with PgCat, my previous project, PgDog is its spiritual successor but with a fresh codebase and new goals. If not, PgCat is a pooler for Postgres also written in Rust.<p>So, what’s changed and why a new project? Cross-shard queries are supported out of the box. The new architecture is more flexible, completely asynchronous and supports manipulating the Postgres protocol at any stage of query execution. (Oh, and you guessed it — I adopted a dog. Still a cat person though!)<p>Not everything is working yet, but simple aggregates like max(), min(), count(*) and sum() are in. More complex functions like percentiles and average will require a bit more work. Sorting (i.e. ORDER BY) works, as long as the values are part of the result set, e.g.:<p><pre><code> SELECT id, email FROM users
WHERE admin = true
ORDER BY 1 DESC;
</code></pre>
PgDog buffers and sorts the rows in memory, before sending them to the client. Most of the time, the working set is small, so this is fine. For larger results, we need to build swap to disk, just like Postgres does, but for OLTP workloads, which PgDog is targeting, we want to keep things fast. Sorting currently works for bigint, integer, and text/varchar. It’s pretty straightforward to add all the other data types, I just need to find the time and make sure to handle binary encoding correctly.<p>All standard Postgres features work as normal for unsharded and direct-to-shard queries. As long as you include the sharding key (a column like customer_id, for example) in your query, you won’t notice a difference.<p>How does this compare to Citus? In case you’re not familiar, Citus is an open source extension for sharding Postgres. It runs inside a single Postgres node (a coordinator) and distributes queries between worker databases.<p>PgDog’s architecture is fundamentally different. It runs outside the DB: it’s a proxy, so you can deploy it anywhere, including managed Postgres like RDS, Cloud SQL and others where Citus isn’t available. It’s multi-threaded and asynchronous, so it can handle thousands, if not millions, of concurrent connections. Its focus is OLTP, not OLAP. Meanwhile, Citus is more mature and has good support for cross-shard queries and aggregates. It will take PgDog a while to catch up.<p>My Rust has improved since my last attempt at this and I learned how to use the bytes crate correctly. PgDog does almost zero memory allocations per request. That results in a 3-5% performance increase over PgCat and a much more consistent p95. If you’re obsessed with performance like me, you know that small percentage is nothing to sneeze at. Like before, multi-threaded Tokio-powered PgDog leaves the single-threaded PgBouncer in the dust (<a href="https://pgdog.dev/blog/pgbouncer-vs-pgdog">https://pgdog.dev/blog/pgbouncer-vs-pgdog</a>).<p>Since we’re using pg_query (which itself bundles the Postgres parser), PgDog can understand all Postgres queries. This is important because we can not only correctly extract the WHERE clause and INSERT parameters for automatic routing, but also rewrite queries. This will be pretty useful when we’ll add support for more complex aggregates, like avg(), and cross-shard joins!<p>Read/write traffic split is supported out of the box, so you can put PgDog in front of the whole cluster and ditch the code annotations. It’s also a load balancer, so you can deploy it in front of multiple replicas to get 4 9’s of uptime.<p>One of the coolest features so far, in my opinion, is distributed COPY. This works by hacking the Postgres network protocol and sending individual rows to different shards (<a href="https://pgdog.dev/blog/hacking-postgres-wire-protocol">https://pgdog.dev/blog/hacking-postgres-wire-protocol</a>). You can just use it without thinking about cluster topology, e.g.:<p><pre><code> COPY temperature_records (sensor_uuid, created_at, value)
FROM STDIN CSV;
</code></pre>
The sharding function is straight out of Postgres partitions and supports uuid v4 and bigint. Technically, it works with any data type, but I just haven’t added all the wrappers yet. Let me know if you need one.<p>What else? Since we have the Postgres parser handy, we can inspect, block and rewrite queries. One feature I was playing with is ensuring that the app is passing in the customer_id in all queries, to avoid data leaks between tenants. Brain dump of that in my blog here: <a href="https://pgdog.dev/blog/multi-tenant-pg-can-be-easy">https://pgdog.dev/blog/multi-tenant-pg-can-be-easy</a>.<p>What’s on the roadmap: (re)sharding Postgres using logical replication, so we can scale DBs without taking downtime. There is a neat trick on how to quickly do this on copy-on-write filesystems (like EBS used by RDS, Google Cloud volumes, ZFS, etc.). I’ll publish a blog post on this soon. More at-scale features like blocking bad queries and just general “I wish my Postgres proxy could do this” stuff. Speaking of which, if you can think of any more features you’d want, get in touch. Your wishlist can become my roadmap.<p>PgDog is being built in the open. If you have thoughts or suggestions about this topic, I would love to hear them. Happy to listen to your battle stories with Postgres as well.<p>Happy hacking!<p>Lev
Show HN: PgDog – Shard Postgres without extensions
Hey HN! Lev here, author of PgDog (<a href="https://github.com/pgdogdev/pgdog">https://github.com/pgdogdev/pgdog</a>). I’m scaling our favorite database, PostgreSQL. PgDog is a new open source proxy, written in Rust, with first-class support for sharding — without changes to your app or needing database extensions.<p>Here’s a walkthrough of how it works: <a href="https://www.youtube.com/watch?v=y6sebczWZ-c" rel="nofollow">https://www.youtube.com/watch?v=y6sebczWZ-c</a><p>Running Postgres at scale is hard. Eventually, one primary isn’t enough at which point you need to split it up. Since there is currently no good tooling out there to do this, teams end up breaking their apps apart instead.<p>If you’re familiar with PgCat, my previous project, PgDog is its spiritual successor but with a fresh codebase and new goals. If not, PgCat is a pooler for Postgres also written in Rust.<p>So, what’s changed and why a new project? Cross-shard queries are supported out of the box. The new architecture is more flexible, completely asynchronous and supports manipulating the Postgres protocol at any stage of query execution. (Oh, and you guessed it — I adopted a dog. Still a cat person though!)<p>Not everything is working yet, but simple aggregates like max(), min(), count(*) and sum() are in. More complex functions like percentiles and average will require a bit more work. Sorting (i.e. ORDER BY) works, as long as the values are part of the result set, e.g.:<p><pre><code> SELECT id, email FROM users
WHERE admin = true
ORDER BY 1 DESC;
</code></pre>
PgDog buffers and sorts the rows in memory, before sending them to the client. Most of the time, the working set is small, so this is fine. For larger results, we need to build swap to disk, just like Postgres does, but for OLTP workloads, which PgDog is targeting, we want to keep things fast. Sorting currently works for bigint, integer, and text/varchar. It’s pretty straightforward to add all the other data types, I just need to find the time and make sure to handle binary encoding correctly.<p>All standard Postgres features work as normal for unsharded and direct-to-shard queries. As long as you include the sharding key (a column like customer_id, for example) in your query, you won’t notice a difference.<p>How does this compare to Citus? In case you’re not familiar, Citus is an open source extension for sharding Postgres. It runs inside a single Postgres node (a coordinator) and distributes queries between worker databases.<p>PgDog’s architecture is fundamentally different. It runs outside the DB: it’s a proxy, so you can deploy it anywhere, including managed Postgres like RDS, Cloud SQL and others where Citus isn’t available. It’s multi-threaded and asynchronous, so it can handle thousands, if not millions, of concurrent connections. Its focus is OLTP, not OLAP. Meanwhile, Citus is more mature and has good support for cross-shard queries and aggregates. It will take PgDog a while to catch up.<p>My Rust has improved since my last attempt at this and I learned how to use the bytes crate correctly. PgDog does almost zero memory allocations per request. That results in a 3-5% performance increase over PgCat and a much more consistent p95. If you’re obsessed with performance like me, you know that small percentage is nothing to sneeze at. Like before, multi-threaded Tokio-powered PgDog leaves the single-threaded PgBouncer in the dust (<a href="https://pgdog.dev/blog/pgbouncer-vs-pgdog">https://pgdog.dev/blog/pgbouncer-vs-pgdog</a>).<p>Since we’re using pg_query (which itself bundles the Postgres parser), PgDog can understand all Postgres queries. This is important because we can not only correctly extract the WHERE clause and INSERT parameters for automatic routing, but also rewrite queries. This will be pretty useful when we’ll add support for more complex aggregates, like avg(), and cross-shard joins!<p>Read/write traffic split is supported out of the box, so you can put PgDog in front of the whole cluster and ditch the code annotations. It’s also a load balancer, so you can deploy it in front of multiple replicas to get 4 9’s of uptime.<p>One of the coolest features so far, in my opinion, is distributed COPY. This works by hacking the Postgres network protocol and sending individual rows to different shards (<a href="https://pgdog.dev/blog/hacking-postgres-wire-protocol">https://pgdog.dev/blog/hacking-postgres-wire-protocol</a>). You can just use it without thinking about cluster topology, e.g.:<p><pre><code> COPY temperature_records (sensor_uuid, created_at, value)
FROM STDIN CSV;
</code></pre>
The sharding function is straight out of Postgres partitions and supports uuid v4 and bigint. Technically, it works with any data type, but I just haven’t added all the wrappers yet. Let me know if you need one.<p>What else? Since we have the Postgres parser handy, we can inspect, block and rewrite queries. One feature I was playing with is ensuring that the app is passing in the customer_id in all queries, to avoid data leaks between tenants. Brain dump of that in my blog here: <a href="https://pgdog.dev/blog/multi-tenant-pg-can-be-easy">https://pgdog.dev/blog/multi-tenant-pg-can-be-easy</a>.<p>What’s on the roadmap: (re)sharding Postgres using logical replication, so we can scale DBs without taking downtime. There is a neat trick on how to quickly do this on copy-on-write filesystems (like EBS used by RDS, Google Cloud volumes, ZFS, etc.). I’ll publish a blog post on this soon. More at-scale features like blocking bad queries and just general “I wish my Postgres proxy could do this” stuff. Speaking of which, if you can think of any more features you’d want, get in touch. Your wishlist can become my roadmap.<p>PgDog is being built in the open. If you have thoughts or suggestions about this topic, I would love to hear them. Happy to listen to your battle stories with Postgres as well.<p>Happy hacking!<p>Lev
Show HN: Rotary Phone Dial Linux Kernel Driver
A Linux kernel driver that turns a rotary phone dial into an evdev input device. You might be interested in this driver if you<p>- prefer the slow pace of dialing over typing numbers with your numpad,<p>- want to bring your old rotary phone into the digital era,<p>- are an educator looking for a simple example driver with a VM-based end-to-end development & test environment (no real hardware needed)<p>- have another creative use case in mind!<p>This driver was my introduction to embedded Linux years ago—and ultimately led to my career. However, it remained unfinished and unpublished until now. Initially, I intended to reimplement the driver in Rust to explore the state of the Rust for Linux project. Unfortunately, I soon realized that the necessary bindings simply are not available yet, so that part will have to wait.
Show HN: Rotary Phone Dial Linux Kernel Driver
A Linux kernel driver that turns a rotary phone dial into an evdev input device. You might be interested in this driver if you<p>- prefer the slow pace of dialing over typing numbers with your numpad,<p>- want to bring your old rotary phone into the digital era,<p>- are an educator looking for a simple example driver with a VM-based end-to-end development & test environment (no real hardware needed)<p>- have another creative use case in mind!<p>This driver was my introduction to embedded Linux years ago—and ultimately led to my career. However, it remained unfinished and unpublished until now. Initially, I intended to reimplement the driver in Rust to explore the state of the Rust for Linux project. Unfortunately, I soon realized that the necessary bindings simply are not available yet, so that part will have to wait.
Show HN: Rotary Phone Dial Linux Kernel Driver
A Linux kernel driver that turns a rotary phone dial into an evdev input device. You might be interested in this driver if you<p>- prefer the slow pace of dialing over typing numbers with your numpad,<p>- want to bring your old rotary phone into the digital era,<p>- are an educator looking for a simple example driver with a VM-based end-to-end development & test environment (no real hardware needed)<p>- have another creative use case in mind!<p>This driver was my introduction to embedded Linux years ago—and ultimately led to my career. However, it remained unfinished and unpublished until now. Initially, I intended to reimplement the driver in Rust to explore the state of the Rust for Linux project. Unfortunately, I soon realized that the necessary bindings simply are not available yet, so that part will have to wait.
Display any CSV file as a searchable, filterable, pretty HTML table
I combined this with a simple API to update a CSV file using Deno/deno-csv library, allowing an Ansible job to easily update a CSV file via the API with Ansible URI module, and then have that same CSV file viewable/downloadable in a simple and easy/dashboardy way (with CSV-to-html-table). Copilot created the Deno/deno-csv CSV API code and then with a little back and forth I added static website functionality (to serve the CSV table), and I had a /view and a /update route. I'm just a sysadmin but I love piecing together stuff like this. Thanks Derek!
Show HN: Defuddle, an HTML-to-Markdown alternative to Readability
Defuddle is an open-source JS library I built to parse and extract the main content and metadata from web pages. It can also return the content as Markdown.<p>I built Defuddle while working on Obsidian Web Clipper[1] (also MIT-licensed) because Mozilla's Readability[2] appears to be mostly abandoned, and didn't work well for many sites.<p>It's still very much a work in progress, but I thought I'd share it today, in light of the announcement that Mozilla is shutting down Pocket. This library could be helpful to anyone building a read-it-later app.<p>Defuddle is also available as a CLI:<p><a href="https://github.com/kepano/defuddle-cli">https://github.com/kepano/defuddle-cli</a><p>[1] <a href="https://github.com/obsidianmd/obsidian-clipper">https://github.com/obsidianmd/obsidian-clipper</a><p>[2] <a href="https://github.com/mozilla/readability">https://github.com/mozilla/readability</a>
Show HN: A Tiling Window Manager for Windows, Written in Janet
Hi HN!<p>I read[1] about Janet[2] some time ago, then immediately got impressed by the enthusiasm of its community, and by the language itself, so I started playing with it.<p>At the time I was searching for a tiling window manager for Windows, and unavoidably the idea of scratching my own itch with Janet got hold of me, so Jwno was born.<p>Simply put, Jwno is a keyboard-driven tiling window manager for Windows, scriptable with Janet. But since it has a complete Lisp runtime, and a thin wrapper library for Win32 APIs[3], you can certainly do much more with it.<p>I hope you'll enjoy playing with it as much as I enjoyed building it.<p>And yes, I use StumpWM on the Linux side, by the way.<p>[1]: <a href="https://ianthehenry.com/posts/why-janet/" rel="nofollow">https://ianthehenry.com/posts/why-janet/</a><p>[2]: <a href="https://janet-lang.org/" rel="nofollow">https://janet-lang.org/</a><p>[3]: <a href="https://github.com/agent-kilo/jw32">https://github.com/agent-kilo/jw32</a>
Show HN: 90s.dev – Game maker that runs on the web
Show HN: Job board aggregator for best paying remote SWE jobs in the U.S.
I’ve been a remote SWE since the pandemic and truly appreciate its flexibilities and time saved from not commuting. Lately, friends and close ones have been asking me for advice on finding remote roles. I shared my remote company spreadsheet with them, but realized it was a rather manual process to scroll and refresh each company’s career page for new postings.<p>So I put together a centralized job board aggregator that lists the best paying SWE jobs in one place, starting with the U.S. and 14 companies. The way it works is via a cron job that runs daily in the afternoon to pull the latest job postings from each company and updates the website with the new listings.<p>Some other key features are<p>1. Quickly see which companies are actively hiring, e.g. Coinbase currently has the most openings<p>2. Filter by years of experience or companies to find suitable matches<p>3. Easily see estimated salary and posted date<p>If you're also on the hunt for the next remote SWE role, I hope this site helps streamline your job search and would appreciate any feedback and suggestions. Thanks!<p>Home page: <a href="https://www.remoteswe.fyi" rel="nofollow">https://www.remoteswe.fyi</a><p>FAQ page with additional context: <a href="https://www.remoteswe.fyi/faq" rel="nofollow">https://www.remoteswe.fyi/faq</a>
Side projects I've built since 2009
Side projects I've built since 2009
Show HN: Chat with 19 years of HN
Hey HN<p>We loaded a BigQuery dataset of all of Hacker News, every comment, story and user, into camelAI.<p>You can ask questions like:<p>• “When does dang tend to comment during the day?”<p>• “Which domains have gained the most submissions since 2015, year-over-year?”<p>• “How has average comment length changed each January since 2007?”<p>• “Top five users who link to arXiv papers the most.”<p>It's behind a log-in to prevent abuse but free to use for 10 messages. No payment info required. We use OpenAI o3 or Claude sonnet 3.7 for the agent which can be really expensive.<p>Would love feedback especially around graph/chart quality and o3 vs sonnet.
Show HN: Hardtime.nvim – break bad habits and master Vim motions