1 00:00:00,000 --> 00:00:01,100 There's database. 2 00:00:01,451 --> 00:00:03,721 sync engines and then there's document sync engines. 3 00:00:04,161 --> 00:00:07,131 So for database sync engine, I think of things like Linear, like things 4 00:00:07,131 --> 00:00:11,641 where you have some relational model data, you probably don't 5 00:00:11,641 --> 00:00:12,881 want the client to have all of it. 6 00:00:12,881 --> 00:00:16,924 You kind of have, the client storing some subset of a database 7 00:00:16,924 --> 00:00:18,679 for each, for each account. 8 00:00:18,909 --> 00:00:22,639 Maybe you're sharing this data across multiple people in that account. 9 00:00:22,946 --> 00:00:27,209 On the document sync side you're sending all of the data down to the client. 10 00:00:27,281 --> 00:00:31,428 The unit of data that gets synced is in memory size on the browser. 11 00:00:31,428 --> 00:00:33,238 You're not dealing with like a terabyte of data here. 12 00:00:33,281 --> 00:00:34,441 you're not taking a subset of it. 13 00:00:34,441 --> 00:00:35,911 You're synchronizing the entire document. 14 00:00:36,451 --> 00:00:41,028 This would be kind of things like Figma or Google Docs, where there's a full local 15 00:00:41,028 --> 00:00:44,838 copy of some self standing piece of data. 16 00:00:45,251 --> 00:00:47,351 Welcome to the localfirst.fm podcast. 17 00:00:47,711 --> 00:00:51,701 I'm your host, Johannes Schickling and I'm a web developer, a startup founder, and 18 00:00:51,701 --> 00:00:53,651 love the craft of software engineering. 19 00:00:53,921 --> 00:00:57,836 For the past few years, I've been on a journey to build a modern, high quality 20 00:00:57,836 --> 00:01:01,811 music app using web technologies, and in doing so, I've been falling down the 21 00:01:01,811 --> 00:01:03,611 rabbit hole of local-first software. 22 00:01:04,061 --> 00:01:06,941 This podcast is your invitation to join me on that journey. 23 00:01:07,736 --> 00:01:11,636 In this episode, I'm speaking to Paul Butler, founder of Jamsocket, 24 00:01:11,756 --> 00:01:13,646 and creator of the Y-Sweet Project. 25 00:01:14,096 --> 00:01:17,576 In this conversation, we talk about building versus buying a sync engine 26 00:01:17,906 --> 00:01:22,686 and explore the various projects behind Jamsocket, including Plane, Y-Sweet, 27 00:01:22,706 --> 00:01:27,996 and Forever VM Before getting started, also a big thank you to ElectricSQL 28 00:01:28,016 --> 00:01:30,266 and Jazz for supporting this podcast. 29 00:01:30,446 --> 00:01:32,246 And now my interview with Paul. 30 00:01:33,451 --> 00:01:35,661 Hey, Paul, so nice to have you on the podcast. 31 00:01:35,671 --> 00:01:36,291 How are you doing? 32 00:01:37,031 --> 00:01:37,401 I'm good. 33 00:01:37,401 --> 00:01:38,041 Thank you, Johannes. 34 00:01:38,041 --> 00:01:40,271 I'm excited to be here and been listening since the beginning. 35 00:01:41,034 --> 00:01:41,974 Thank you so much. 36 00:01:42,004 --> 00:01:45,114 The two of us had the pleasure to meet in person at last year's 37 00:01:45,114 --> 00:01:48,744 local-first conf, and I'm hoping to see you there again this year. 38 00:01:49,174 --> 00:01:50,834 So for those in the audience. 39 00:01:51,079 --> 00:01:53,959 Who don't know who you are, would you mind introducing yourself? 40 00:01:54,719 --> 00:01:55,009 Sure. 41 00:01:55,009 --> 00:01:56,039 I'm Paul Butler. 42 00:01:56,039 --> 00:01:58,469 I'm a co founder of a company called Jamsocket. 43 00:01:58,622 --> 00:02:03,512 the kind of one line pitch is it's like a Lambda, but for WebSockets. 44 00:02:03,865 --> 00:02:04,265 Yeah. 45 00:02:04,305 --> 00:02:06,855 I've been looking a little bit into Jamsocket and it's 46 00:02:06,895 --> 00:02:08,805 like, looks really fascinating. 47 00:02:08,815 --> 00:02:13,095 And I also want to hear more about The origin story where it's coming from, 48 00:02:13,375 --> 00:02:17,825 since by now we got more and more sort of like infrastructural options. 49 00:02:17,825 --> 00:02:21,125 Obviously there's like CloudFlare with their primitives, 50 00:02:21,125 --> 00:02:22,545 CloudFlare workers, et cetera. 51 00:02:22,895 --> 00:02:27,585 And I think with Jamsocket, you provide a really powerful alternative. 52 00:02:27,885 --> 00:02:30,085 For high scale applications. 53 00:02:30,385 --> 00:02:35,095 So yeah, before we go into more into depth, what Jamsocket is and what 54 00:02:35,095 --> 00:02:38,909 it offers, would you mind sharing a bit more of the origin story, 55 00:02:38,939 --> 00:02:40,879 how you ended up working on it? 56 00:02:41,355 --> 00:02:41,665 Sure. 57 00:02:41,665 --> 00:02:41,895 Yeah. 58 00:02:41,895 --> 00:02:45,106 so I started, with my co founder started the company about three years ago. 59 00:02:45,352 --> 00:02:49,892 prior to that, I was working in finance and I was doing a lot of building a lot of 60 00:02:49,892 --> 00:02:52,512 internal tools for myself, my team, that. 61 00:02:52,882 --> 00:02:56,972 We're dealing with midsize amounts of data, so talking about like single digit, 62 00:02:56,972 --> 00:03:02,182 double digit, gigabytes of data, not anything that was out of realm of putting 63 00:03:02,182 --> 00:03:06,432 in RAM for a desktop application, but I realized that as soon as people wanted 64 00:03:06,432 --> 00:03:09,362 these things to be delivered through the browser, there was really nowhere 65 00:03:09,362 --> 00:03:13,149 to put that data, that I couldn't really load that over the Internet into the 66 00:03:13,159 --> 00:03:17,467 browser, Chrome would just give up, didn't really make sense to load that 67 00:03:17,487 --> 00:03:21,547 into kind of a flask server or something like that, because the web stack is 68 00:03:21,547 --> 00:03:26,524 kind of built for these servers to not consume a lot of memory for each user 69 00:03:26,524 --> 00:03:28,281 of the application, things like that. 70 00:03:28,281 --> 00:03:33,301 So I really wanted this sort of neutral location and a way for the, I almost 71 00:03:33,301 --> 00:03:34,951 think of it as a way for a browser. 72 00:03:35,196 --> 00:03:39,256 Based application to spin up a server side sub process that 73 00:03:39,266 --> 00:03:40,966 just belongs to that browser tab. 74 00:03:40,986 --> 00:03:45,166 And that when you close that browser tab, that server side process also goes away. 75 00:03:45,676 --> 00:03:48,406 So that was essentially the origin story of Jamsocket. 76 00:03:48,786 --> 00:03:52,136 That makes a lot of sense, but could you motivate a little bit more? 77 00:03:52,136 --> 00:03:54,666 What kind of application I should imagine there? 78 00:03:54,666 --> 00:03:57,946 I've never worked in finance and I think the average web 79 00:03:57,946 --> 00:03:59,896 developer has sort of like. 80 00:04:00,151 --> 00:04:05,687 A list of like 50 Airbnb, items that they want to render. 81 00:04:05,687 --> 00:04:09,607 And then there's like pagination and all of that easily fits like in a 82 00:04:09,877 --> 00:04:15,879 JSON array that you can fetch into like, a single, CRUD, REST API call. 83 00:04:16,092 --> 00:04:20,992 But when you say like single digits, double digit, gigabytes of data, what 84 00:04:20,992 --> 00:04:23,012 sort of data are we dealing with here? 85 00:04:23,042 --> 00:04:27,142 And if you want it to transfer it over the wire into the browser, 86 00:04:27,342 --> 00:04:28,872 what would that even look like? 87 00:04:28,892 --> 00:04:33,622 Would that be sort of like one big JSON blob or can't, yeah, maybe 88 00:04:33,622 --> 00:04:35,072 you can motivate that a bit more. 89 00:04:35,557 --> 00:04:40,064 Yeah, so, one of the motivating examples at the time was, we would run like a 90 00:04:40,064 --> 00:04:41,924 simulation, a back test simulation. 91 00:04:41,924 --> 00:04:46,944 So we have some model that we hypothesize is predictive of of stock returns, 92 00:04:47,347 --> 00:04:52,577 run it back in time and generate a bunch of data could be say on every 93 00:04:52,577 --> 00:04:55,857 five minute increment or even more fine grained than that, over petabytes 94 00:04:55,857 --> 00:04:58,094 and petabytes of, past market data. 95 00:04:58,550 --> 00:05:03,270 and then we get back some gigantic time series data, number of time 96 00:05:03,270 --> 00:05:07,117 series, maybe you have profit and loss over time and record of all 97 00:05:07,117 --> 00:05:08,847 the trades and everything like that. 98 00:05:08,874 --> 00:05:14,174 so we have like massive, not massive, large, like, Gigabyte, 99 00:05:14,370 --> 00:05:18,150 multi gigabyte of time series data, likely in something like Parquet. 100 00:05:18,304 --> 00:05:20,724 that tend to be the best format for that type of thing. 101 00:05:21,140 --> 00:05:24,530 and so over the wire, ideally it would be Parquet or Arrow. 102 00:05:25,130 --> 00:05:25,580 Got it. 103 00:05:25,670 --> 00:05:28,730 And over that sort of data you want to do like. 104 00:05:28,960 --> 00:05:34,484 Based on the user's input through the UI, driving some sort of queries, some sort 105 00:05:34,484 --> 00:05:40,334 of like accumulations to make sense of like what the data is trying to tell us. 106 00:05:40,744 --> 00:05:41,194 Yeah. 107 00:05:41,194 --> 00:05:44,784 It was things like, maybe I want to be able to drill down in the data, in the 108 00:05:44,784 --> 00:05:50,620 client, be able to kind of go from this high level overview of data to kind of. 109 00:05:51,065 --> 00:05:54,862 Looking at specific trades, specific stocks, things like that. 110 00:05:55,245 --> 00:05:55,625 Got it. 111 00:05:55,965 --> 00:06:01,492 And sort of your insight and way to deal with that, fundamental problem where 112 00:06:01,492 --> 00:06:07,262 like ideally you could just like move that big data blob over in front of like 113 00:06:07,262 --> 00:06:12,235 your, browser that you're looking at and then like happily query and compute 114 00:06:12,235 --> 00:06:17,365 away, but that wasn't feasible because like Chrome or another browser has. 115 00:06:17,600 --> 00:06:22,330 Certain limits and the way how you want it to like, cope with that 116 00:06:22,380 --> 00:06:25,980 is to say like, okay, we're going to have like a little companion. 117 00:06:25,990 --> 00:06:30,260 Each browser session has a little companion on some beefy server, which 118 00:06:30,270 --> 00:06:32,730 holds all of that data in memory. 119 00:06:33,230 --> 00:06:34,750 And then there's some sort of like. 120 00:06:34,950 --> 00:06:41,497 Real time wire protocol that helps you do that, like still so fast that 121 00:06:41,497 --> 00:06:43,744 it's, sort of proxying to being local. 122 00:06:44,504 --> 00:06:45,534 Yeah, exactly that. 123 00:06:45,534 --> 00:06:48,284 I kind of think of it as like a somewhere along the spectrum where 124 00:06:48,284 --> 00:06:49,644 you have like there's thin client. 125 00:06:50,274 --> 00:06:53,174 Sort of setups where the server does everything and the client's really 126 00:06:53,174 --> 00:06:58,684 just a dumb display all the way to a full fledged browser based app that 127 00:06:59,004 --> 00:07:01,914 where everything's happening in the browser that can happen in the browser. 128 00:07:02,244 --> 00:07:05,174 I think there's some middle ground where you get. 129 00:07:05,484 --> 00:07:10,624 Next frame latency on almost everything, but maybe in the background 130 00:07:11,334 --> 00:07:14,024 it needs to query some server data and load that in and maybe it 131 00:07:14,024 --> 00:07:15,814 can even approximate client side. 132 00:07:16,110 --> 00:07:18,970 what that next frame will look like, but it's able to sort of do 133 00:07:18,970 --> 00:07:20,080 that in the background as well. 134 00:07:20,324 --> 00:07:20,704 Got it. 135 00:07:20,984 --> 00:07:26,644 So as you face those problems that has led you to get so interested in the 136 00:07:26,644 --> 00:07:31,264 problem that you started to dedicate your next chapter in life to that. 137 00:07:31,564 --> 00:07:35,404 And that led to you building a technology called Plane. 138 00:07:35,744 --> 00:07:38,544 And that was then also the foundation for Jamsocket. 139 00:07:38,554 --> 00:07:43,444 So can you explain a bit more what Plane does and then how it 140 00:07:43,484 --> 00:07:45,364 connects to what Jamsocket is? 141 00:07:45,724 --> 00:07:48,157 Yeah, so, and just to kind of continue on the story. 142 00:07:48,157 --> 00:07:51,327 So my co founder, Taylor was at data dog and had kind of faced 143 00:07:51,327 --> 00:07:52,577 some, some similar problems. 144 00:07:52,587 --> 00:07:55,057 So we got together in 2022. 145 00:07:55,490 --> 00:07:58,680 and the first thing we started working on was, yeah, what became 146 00:07:58,680 --> 00:08:01,057 Plane, which is, it's open source. 147 00:08:01,164 --> 00:08:06,774 and it's a, I think of it as kind of the way that we spin up those processes. 148 00:08:06,774 --> 00:08:10,735 It's kind of the orchestration plane essentially for that type of application. 149 00:08:11,232 --> 00:08:15,819 so what it's responsible for is you kind of give it a pool of computers. 150 00:08:16,275 --> 00:08:20,445 you tell it you want to start a specific process and it will find where on those 151 00:08:20,485 --> 00:08:22,065 on that pool of computers to start that. 152 00:08:22,715 --> 00:08:28,025 But it will also give that process a secure web accessible URL. 153 00:08:28,335 --> 00:08:32,475 so it can give it a host name and a kind of a password, essentially, 154 00:08:32,755 --> 00:08:35,679 then anything on the web, anything on the public Internet. 155 00:08:35,930 --> 00:08:39,560 That can access the web, can use that URL to send and receive 156 00:08:39,590 --> 00:08:41,660 messages from that process. 157 00:08:42,330 --> 00:08:45,700 And as long as there's at least one open connection to that 158 00:08:45,700 --> 00:08:47,220 process, Plane will keep it alive. 159 00:08:47,240 --> 00:08:50,390 And then as soon as there's no more processes, Plane 160 00:08:50,390 --> 00:08:51,560 will start a countdown timer. 161 00:08:51,640 --> 00:08:54,170 And if nothing reconnects, it'll shut that process off. 162 00:08:54,785 --> 00:08:55,145 Got it. 163 00:08:55,615 --> 00:09:01,065 So in terms of use cases, you've clearly motivated that original use case that you 164 00:09:01,075 --> 00:09:04,072 had while working, at a financial company. 165 00:09:04,459 --> 00:09:09,279 are those also the kind of use cases that, you know, mostly face when talking to 166 00:09:09,279 --> 00:09:14,549 people that are interested in Jamsocket or is there a wider set of applications 167 00:09:14,599 --> 00:09:16,789 that Jamsocket is trying to serve. 168 00:09:17,185 --> 00:09:20,585 yeah, largely not that actually hasn't, we haven't seen that many 169 00:09:20,585 --> 00:09:25,600 use cases of kind of wanting to just modify massive data sets or deal with 170 00:09:25,600 --> 00:09:26,790 massive data sets in the browser. 171 00:09:27,460 --> 00:09:31,170 But one of the things we quickly realized was that the infrastructure we were 172 00:09:31,190 --> 00:09:35,910 building had a lot of parallels to how Figma did things, how Google Docs 173 00:09:35,910 --> 00:09:38,880 did things, how a lot of these kind of collaborative applications did things. 174 00:09:39,300 --> 00:09:45,020 And so we decided to kind of lean into the sync engine hosting side of things. 175 00:09:45,392 --> 00:09:45,832 Got it. 176 00:09:45,892 --> 00:09:49,499 And when I'm looking at your, website, among a few other 177 00:09:49,499 --> 00:09:54,122 companies, it looks like Rayon is built also on, on top of Jamsocket. 178 00:09:54,122 --> 00:09:57,512 So I've happened to have seen their launch, I think, a while back. 179 00:09:57,879 --> 00:10:03,149 if I recall correctly, it was sort of like a really interesting Figma esque, 180 00:10:03,425 --> 00:10:05,755 application, I think for architects. 181 00:10:06,245 --> 00:10:10,779 And, yeah, maybe you can share a little bit more about their specific scenario, 182 00:10:10,789 --> 00:10:15,179 how they're employing Jamsocket to build their collaborative experience. 183 00:10:15,509 --> 00:10:17,899 Yeah, Rayon's one of my favorite use cases. 184 00:10:17,932 --> 00:10:19,042 cause we've really grown with them. 185 00:10:19,160 --> 00:10:22,210 They've been using us since we started the company, essentially. 186 00:10:22,314 --> 00:10:26,124 they were one of the first users on the platform and we've seen them kind of grow 187 00:10:26,124 --> 00:10:27,414 as they launched and, and everything. 188 00:10:27,890 --> 00:10:32,660 essentially the way that they're using us is that we are the data backend for 189 00:10:32,780 --> 00:10:34,070 these documents while they're open. 190 00:10:34,250 --> 00:10:39,027 So I open a document, you open a document, they'll start a server 191 00:10:39,237 --> 00:10:41,007 on Jamsocket for that document. 192 00:10:41,397 --> 00:10:42,267 And as I make edits. 193 00:10:43,117 --> 00:10:44,547 They get pushed up to that server. 194 00:10:45,077 --> 00:10:46,417 They get sent back down to you. 195 00:10:46,427 --> 00:10:50,927 And, that back end is also what's storing the data on S3. 196 00:10:51,457 --> 00:10:56,980 So even if it's single player mode, that Jamsocket server still sits between their 197 00:10:56,980 --> 00:11:01,455 end user and the source of truth on the data source, the durable data source. 198 00:11:02,012 --> 00:11:02,452 Okay. 199 00:11:02,612 --> 00:11:06,622 So you mentioning S3 and a durable data source. 200 00:11:06,855 --> 00:11:11,475 maybe we can take a step back and motivate if someone wants to 201 00:11:11,475 --> 00:11:16,105 build their own, little version of something like Jamsocket or Plane. 202 00:11:16,402 --> 00:11:17,872 how would that look like? 203 00:11:17,872 --> 00:11:22,182 So there seems to be something pretty beefy in the middle that 204 00:11:22,222 --> 00:11:25,032 holds the necessary data in memory. 205 00:11:25,632 --> 00:11:30,072 And as the name, as in memory suggests, that's pretty volatile. 206 00:11:30,372 --> 00:11:34,062 So if someone stumbles over a power cord, that data might be gone. 207 00:11:34,682 --> 00:11:39,545 And, that's also why it needs to stay some more, more durable, something like S3. 208 00:11:39,915 --> 00:11:43,552 So can you walk us through like the rough architecture? 209 00:11:43,922 --> 00:11:48,662 And what were sort of like the insides and deliberate trade offs that went into it? 210 00:11:49,082 --> 00:11:53,835 Yeah, I mean, a common pattern that I see people use with Jamsocket is that the 211 00:11:53,835 --> 00:11:58,455 source of truth for application data will kind of shift as the application is used. 212 00:11:58,465 --> 00:12:04,465 So at rest, the source of truth of the application data is In durable storage 213 00:12:04,465 --> 00:12:09,215 somewhere, usually S3, something like that, where you might want to, might 214 00:12:09,215 --> 00:12:13,675 not want to write to that like 60 times a second, but you want it to 215 00:12:13,675 --> 00:12:16,345 persist when that document is open. 216 00:12:16,745 --> 00:12:20,995 Then that source of truth effectively of that document is in memory on Jamsocket. 217 00:12:21,575 --> 00:12:23,965 And the nice thing about that is it's, you know, it's memory. 218 00:12:23,975 --> 00:12:25,625 You can write to it very frequently. 219 00:12:25,635 --> 00:12:28,845 You can write to it 100 times a second if you want to more than that. 220 00:12:29,129 --> 00:12:32,859 and that can then be synced down to all of the connected clients and then. 221 00:12:33,179 --> 00:12:37,259 In some sort of loop or, you could have some sort of write ahead log, but 222 00:12:37,359 --> 00:12:40,949 as changes are made to that document, you are then durably persisting them. 223 00:12:41,332 --> 00:12:43,902 some people really care about that being really low latency. 224 00:12:44,019 --> 00:12:47,742 I think in general, unless it's really a bad thing for users to lose 225 00:12:47,742 --> 00:12:52,792 like 5 seconds of data that just batching everything up into writing 226 00:12:53,222 --> 00:12:54,882 just the edits every five seconds. 227 00:12:54,932 --> 00:12:56,512 Something like that is pretty reasonable. 228 00:12:56,819 --> 00:13:00,949 or you can, you know, what a lot of people do is they just say 60 seconds is fine. 229 00:13:00,979 --> 00:13:04,769 I'm just going to write the entire document over what existed there before 230 00:13:04,819 --> 00:13:10,699 every 60 seconds because the outage, you know, a server just failing out of the 231 00:13:10,699 --> 00:13:12,089 blue is actually pretty rare these days. 232 00:13:12,410 --> 00:13:12,820 Got it. 233 00:13:13,100 --> 00:13:19,457 So if we compared to, a technology like Cloudflare durable objects, with 234 00:13:19,477 --> 00:13:25,234 Cloudflare workers, that's a particularly distinct programming model where it 235 00:13:25,234 --> 00:13:28,814 kind of gives you kind of Best of both worlds in that regard that you 236 00:13:28,854 --> 00:13:34,044 only pay for the CPU cycles where you actually want the CPU to do things. 237 00:13:34,414 --> 00:13:39,704 And otherwise it can hibernate while still keeping a web socket connection alive, for 238 00:13:39,704 --> 00:13:46,504 example, or keep like some memory alive or rehydrated from some persistent storage. 239 00:13:46,887 --> 00:13:50,797 is that sort of like a useful parallel way to think about 240 00:13:50,807 --> 00:13:52,767 the programming model and also. 241 00:13:53,095 --> 00:13:59,935 can I implement any sort of free web socket messages or request handlers, or is 242 00:13:59,955 --> 00:14:07,685 there a more pre specified API, something like Redis, how I interact with data from 243 00:14:07,685 --> 00:14:09,585 a client to the server and vice versa? 244 00:14:09,902 --> 00:14:10,762 Yeah, good question. 245 00:14:10,814 --> 00:14:14,734 I agree that like, I think durable objects is probably the closest kind of 246 00:14:14,834 --> 00:14:17,124 parallel product out there right now. 247 00:14:17,734 --> 00:14:22,814 when we started this up, durable objects, wasn't really a big thing and had may have 248 00:14:22,814 --> 00:14:24,164 existed, but had a lot of limitations. 249 00:14:24,260 --> 00:14:27,124 like, I think we, we came at things from a very different angle, but kind of 250 00:14:27,124 --> 00:14:29,974 landed in a similar architectural space. 251 00:14:30,237 --> 00:14:35,042 in terms of the servers though, we just, Really host anything that's HTTP. 252 00:14:35,052 --> 00:14:38,205 So, when I talk about it as being for WebSocket servers, I think that 253 00:14:38,425 --> 00:14:42,375 we kind of came at it at an angle of we want this to be the right 254 00:14:42,385 --> 00:14:44,045 model for hosting WebSocket servers. 255 00:14:44,075 --> 00:14:48,232 But, and we do, you know, we sit on the connection. 256 00:14:48,232 --> 00:14:48,832 So we. 257 00:14:49,442 --> 00:14:52,552 Work well with WebSockets where there's a long lived connection, 258 00:14:52,562 --> 00:14:56,022 because then we know not to terminate the server with HTTP requests. 259 00:14:56,022 --> 00:14:57,932 We have to rely a little bit more on heuristics. 260 00:14:58,255 --> 00:15:00,315 we've got that WebSocket connection open. 261 00:15:00,775 --> 00:15:05,082 really, just anything could be Socket.IO could be, your own WebSocket protocol. 262 00:15:05,354 --> 00:15:07,745 we essentially just take a container from our customers that 263 00:15:07,805 --> 00:15:10,015 will serve HTTP on port 8080. 264 00:15:10,415 --> 00:15:13,837 And we expose that to the, the outside web through a proxy that we wrote. 265 00:15:14,420 --> 00:15:14,780 Got it. 266 00:15:14,790 --> 00:15:20,957 So in the specific case of Rayon, did they build their own from scratch sync engine? 267 00:15:20,967 --> 00:15:26,667 Did they leverage any specific off the shelf technology, something like Yjs? 268 00:15:26,894 --> 00:15:31,084 given that Jamsocket advertises as the platform where you build your 269 00:15:31,084 --> 00:15:35,760 own sync engine on top of, maybe you can walk us through by this example. 270 00:15:36,060 --> 00:15:37,330 how I should think about that. 271 00:15:37,970 --> 00:15:38,550 Yeah. 272 00:15:38,600 --> 00:15:41,680 they're one of a number of customers who have kind of built their own 273 00:15:41,680 --> 00:15:43,770 sync engine on top of Jamsocket. 274 00:15:44,007 --> 00:15:46,717 there's not like an SDK that you need to adopt or anything like 275 00:15:46,717 --> 00:15:48,557 that on, on the server side. 276 00:15:48,557 --> 00:15:50,797 It's, you're just writing a web server. 277 00:15:51,044 --> 00:15:54,024 but one of the things that's specific about this model is that. 278 00:15:54,594 --> 00:16:00,274 You are guaranteed by the infrastructure that only one, at most one server is 279 00:16:00,274 --> 00:16:05,904 running per document or however, you want to fragment your kind of space of things, 280 00:16:06,314 --> 00:16:08,016 but, in their case, it's per document. 281 00:16:08,016 --> 00:16:13,006 And so, yeah, you get that guarantee from the system, and then it becomes much 282 00:16:13,006 --> 00:16:14,726 easier to implement your own sync engine. 283 00:16:14,726 --> 00:16:19,366 But we, at least at the Jamsocket level, are not opinionated about how 284 00:16:19,366 --> 00:16:21,046 you actually go about implementing that. 285 00:16:21,362 --> 00:16:22,119 but then you mentioned Y-Sweet. 286 00:16:22,139 --> 00:16:23,354 Yeah, we. 287 00:16:23,864 --> 00:16:27,841 So Rayon does not use Y Suite, but, some of our customers use Y Suite, which is a 288 00:16:27,891 --> 00:16:29,951 Yjs backend that we wrote that we provide. 289 00:16:29,951 --> 00:16:32,331 That's a much more opinionated path if they want to take that. 290 00:16:32,744 --> 00:16:33,124 Got it. 291 00:16:33,144 --> 00:16:33,464 Yeah. 292 00:16:33,474 --> 00:16:36,834 I want to learn a lot more about Y Suite in a moment as well. 293 00:16:37,164 --> 00:16:42,804 But given that you've already mentioned those 2 paths of Y Suite, which is a 294 00:16:42,834 --> 00:16:47,838 off the shelf technology that you're building that basis, on top of Yjs, 295 00:16:47,858 --> 00:16:53,254 which is a very well known, CRDT implementation, probably the most, common 296 00:16:53,284 --> 00:16:55,691 and, longest technology that's out there. 297 00:16:55,961 --> 00:16:59,391 so that being an example for an off the shelf technology. 298 00:16:59,641 --> 00:17:02,711 Rayon, which has built their own sync engine. 299 00:17:03,034 --> 00:17:07,241 you've probably seen many, many, decisions being made where people 300 00:17:07,261 --> 00:17:11,681 choose to use an off the shelf technology or choose to build their own. 301 00:17:11,948 --> 00:17:14,908 which sort of advice would you give to people who are thinking 302 00:17:14,918 --> 00:17:19,148 whether they should buy, or, as an alternative to buying is like 303 00:17:19,148 --> 00:17:21,148 adopting an off the shelf technology. 304 00:17:22,378 --> 00:17:24,418 Yeah, I think that where. 305 00:17:25,038 --> 00:17:29,918 It kind of comes down to for the kind of build versus off the shelf is whether 306 00:17:29,918 --> 00:17:34,048 you want to have business logic live in the sync engine on the server side. 307 00:17:34,364 --> 00:17:38,664 so where I think you generally don't need that is if you want to just 308 00:17:38,684 --> 00:17:43,824 think text documents, things like that, where CRDTs are probably the 309 00:17:43,824 --> 00:17:48,244 best way to do it right now, at least the most off the shelf way to do it. 310 00:17:48,639 --> 00:17:51,199 You can do your own way, but it's sort of a research problem. 311 00:17:51,686 --> 00:17:54,606 where, on the other hand, I think if you have a very simple data 312 00:17:54,606 --> 00:17:57,516 model, but you want to do atomic transactions, you want to have, kind 313 00:17:57,516 --> 00:17:59,586 of an event sourcing type approach. 314 00:17:59,926 --> 00:18:04,176 you want to be able to do things like trees with reparenting and 315 00:18:04,206 --> 00:18:08,468 and some of that Ends up being that you're working against the CRDT. 316 00:18:08,698 --> 00:18:12,208 and in those cases, I think it makes more sense to implement 317 00:18:12,208 --> 00:18:13,108 your own business logic. 318 00:18:13,398 --> 00:18:16,938 The other thing that we see is if maybe you want some change to trigger 319 00:18:16,938 --> 00:18:19,438 some action server side, you want actions to have some side effect. 320 00:18:19,438 --> 00:18:21,984 You want to, maybe some piece of data changes and you want 321 00:18:21,984 --> 00:18:23,204 to insert that into a queue. 322 00:18:23,534 --> 00:18:26,214 So it becomes really nice to have some server side code that 323 00:18:26,214 --> 00:18:28,214 Reacts to changes to the document. 324 00:18:28,658 --> 00:18:30,148 that's another place that we find. 325 00:18:30,588 --> 00:18:33,658 Building your own tends to be really nice because you can just 326 00:18:34,408 --> 00:18:38,068 have that be one server that's responsible both for the sync and, 327 00:18:38,068 --> 00:18:40,178 and for triggering some side effect. 328 00:18:40,901 --> 00:18:45,291 Right so maybe to linger a little bit on that specific point, I think 329 00:18:45,301 --> 00:18:50,224 with, local-first software you have, in this scenario where you build your 330 00:18:50,224 --> 00:18:54,004 own sync engine, you have kind of two, approaches, how to deal with that. 331 00:18:54,004 --> 00:18:57,984 And also for the off the shelf approach, if you use something like Yjs. 332 00:18:58,666 --> 00:19:02,216 so if you build your own, you can basically just wherever you handle the 333 00:19:02,216 --> 00:19:06,663 messages, you can, possibly inspect the messages and see, okay, this 334 00:19:06,663 --> 00:19:09,673 seems to be like a user signup event. 335 00:19:09,943 --> 00:19:14,803 And so here let's send out that confirmation email or something like that. 336 00:19:15,309 --> 00:19:19,669 but another approach could also be that you basically have a server 337 00:19:19,669 --> 00:19:25,909 side client instance that listens to the same sync messages and you. 338 00:19:25,984 --> 00:19:30,888 Based on the state that you have, on that server side client, you 339 00:19:30,888 --> 00:19:33,568 could then basically React to that. 340 00:19:33,924 --> 00:19:37,344 have you thoughts on one approach versus the other? 341 00:19:37,394 --> 00:19:44,314 Maybe, one is like a lot more, expensive to run or, more, complex to model. 342 00:19:44,521 --> 00:19:47,228 What thoughts do you have on the different approaches here? 343 00:19:47,681 --> 00:19:50,771 I think that where I've tended to see this breakdown because we've, we've seen 344 00:19:50,771 --> 00:19:56,008 it both ways and we've seen, we've seen customers do it both ways is that if it's. 345 00:19:56,413 --> 00:19:58,683 Purely just sort of Reacting to a side effect. 346 00:19:58,693 --> 00:20:02,623 And it's something that you want to that your model of it is that it's 347 00:20:02,623 --> 00:20:05,173 like a server triggered type of thing. 348 00:20:05,183 --> 00:20:07,873 Like, if it's that, you know, that send email example, send 349 00:20:07,873 --> 00:20:08,913 some sort of notification. 350 00:20:09,259 --> 00:20:13,619 I think that that makes more sense to just do in the server, just in 351 00:20:13,619 --> 00:20:15,089 terms of architectural complexity. 352 00:20:15,333 --> 00:20:16,623 you could certainly listen for the events. 353 00:20:16,623 --> 00:20:20,923 And if there's architectural reasons that that makes sense for you, I don't see 354 00:20:20,923 --> 00:20:26,868 any problems with it, but where I think that the server being a client can make a 355 00:20:26,868 --> 00:20:32,354 lot of sense is like AI integration type things, where you want the server in this 356 00:20:32,354 --> 00:20:36,024 case that, you know, it's code running on the server, but it, your application 357 00:20:36,034 --> 00:20:37,944 should just treat it like another client. 358 00:20:38,384 --> 00:20:40,844 This is something like maybe an agent's going out and modifying 359 00:20:40,844 --> 00:20:42,224 a document based on some prompt. 360 00:20:42,657 --> 00:20:45,967 Then I think it does make sense if you want to run it through the same 361 00:20:46,957 --> 00:20:51,067 kind of code paths that a user edit would go through, then it makes 362 00:20:51,067 --> 00:20:55,157 sense to, to kind of treat that as a distinct client of the data. 363 00:20:55,484 --> 00:20:55,854 Got it. 364 00:20:55,874 --> 00:21:03,317 So to dig a little bit more and towards that, server as a client, when I'm 365 00:21:03,367 --> 00:21:08,487 thinking more about like a browser client, or like using my, phone, 366 00:21:08,897 --> 00:21:14,054 or there's like a concrete point in time where I'm starting a session. 367 00:21:14,084 --> 00:21:15,154 I'm opening a tab. 368 00:21:15,154 --> 00:21:16,154 I'm opening an app. 369 00:21:16,464 --> 00:21:18,224 I'm doing things afterwards. 370 00:21:18,224 --> 00:21:19,304 Like I'm closing it. 371 00:21:19,314 --> 00:21:22,224 So there's like a concrete start stop. 372 00:21:22,484 --> 00:21:26,477 Maybe there's like some background stuff, but, let's pretend there's just 373 00:21:26,477 --> 00:21:29,207 like a clear start, stop 30 seconds. 374 00:21:29,557 --> 00:21:30,267 And that's it. 375 00:21:30,647 --> 00:21:34,517 how should I think about that in a server context? 376 00:21:34,785 --> 00:21:38,324 let's say I'm trying to offer that to a thousand customers. 377 00:21:38,634 --> 00:21:42,944 Would I have a thousand separate, like, but let's go crazy. 378 00:21:42,944 --> 00:21:46,934 Let's say we have a thousand VMs, one per customer. 379 00:21:47,324 --> 00:21:49,334 that strikes me as very expensive. 380 00:21:49,334 --> 00:21:54,244 So what is like a useful programming model, like a useful deployment model. 381 00:21:54,539 --> 00:21:57,632 To, deploy those sort of server side clients. 382 00:21:57,980 --> 00:22:01,880 so the way that Jamsocket does this is that we run a process 383 00:22:01,880 --> 00:22:04,117 for every service, essentially. 384 00:22:04,117 --> 00:22:07,357 So when, when you and I are connected to a document, we're running a 385 00:22:07,357 --> 00:22:11,294 process, not a full fledged VM, but it's, using some Cisco interception 386 00:22:11,294 --> 00:22:12,344 through something called G visor. 387 00:22:12,344 --> 00:22:14,554 So it's a little bit more secure than sort of just. 388 00:22:14,554 --> 00:22:14,619 Yeah. 389 00:22:15,219 --> 00:22:16,239 Containerized workloads. 390 00:22:16,699 --> 00:22:20,829 so the nice thing about that is that processes are pretty good at giving 391 00:22:20,829 --> 00:22:24,092 resources back to the system when they're, when they're not actively in use. 392 00:22:24,102 --> 00:22:28,663 So we've seen is that when you want the server to kind of first Okay. 393 00:22:29,383 --> 00:22:32,833 Class of interactions where it's sort of definitely want it to 394 00:22:32,843 --> 00:22:34,133 be processed by the service. 395 00:22:34,386 --> 00:22:36,516 in those cases, it makes sense to run directly in the 396 00:22:36,516 --> 00:22:38,486 sync engine when it comes to. 397 00:22:38,733 --> 00:22:42,229 multiple clients, we tend to see those run off of Jamsocket. 398 00:22:42,239 --> 00:22:47,629 So these are running on an end user server talking to Jamsocket and the 399 00:22:47,629 --> 00:22:54,259 pattern that I've seen their work is that client will maybe trigger something 400 00:22:54,259 --> 00:22:58,089 directly through like a web endpoint on that remote server that's not running 401 00:22:58,089 --> 00:23:02,899 on Jamsocket, that server will then talk to Jamsocket to say, fetch some data or, 402 00:23:03,213 --> 00:23:05,283 connect and sort of trigger something. 403 00:23:05,519 --> 00:23:08,536 so it might synchronize data, but it's not, a long live client. 404 00:23:08,556 --> 00:23:12,406 It's kind of a client that spun up based on a specific action. 405 00:23:12,726 --> 00:23:14,086 That's usually triggered by the client. 406 00:23:14,516 --> 00:23:14,836 Got it. 407 00:23:14,856 --> 00:23:15,826 That makes a lot of sense. 408 00:23:15,836 --> 00:23:19,916 So instead of like being super long running, and that's times 409 00:23:19,936 --> 00:23:25,066 and for each possible instance, you make it more event based. 410 00:23:25,076 --> 00:23:29,076 So, let's say there is a new sync message that you want to React 411 00:23:29,086 --> 00:23:31,656 to, or there's like some other. 412 00:23:31,916 --> 00:23:37,106 maybe like a webhook that's coming in from Stripe and then, so you, you do your 413 00:23:37,106 --> 00:23:43,643 thing as a response to the event and, then you go, yield again, back to the runtime. 414 00:23:44,026 --> 00:23:47,896 and I think a model that also comes to mind that could fit 415 00:23:47,906 --> 00:23:49,166 really well together here. 416 00:23:49,476 --> 00:23:54,043 Is, our durable long running workflows, something like Temporal. 417 00:23:54,053 --> 00:23:57,813 And there's also other options as well, I think could work really well 418 00:23:57,813 --> 00:24:00,133 together here that you have a workflow. 419 00:24:00,873 --> 00:24:05,323 That's essentially a participant in a sync system where it's 420 00:24:05,323 --> 00:24:07,293 just a long running workflow. 421 00:24:07,333 --> 00:24:12,073 It's just like another client happens to live on a server and not in a browser. 422 00:24:12,386 --> 00:24:17,636 yeah, I'm, I'm really excited to see more folks explore this since I think it will. 423 00:24:17,910 --> 00:24:21,705 open the door for a whole bunch of different application topologies, really. 424 00:24:22,048 --> 00:24:26,135 One of the things, things that we found with Y Suite is that, we had people ask 425 00:24:26,135 --> 00:24:28,565 for, like, I want a Python client to this. 426 00:24:28,585 --> 00:24:30,165 And it was for exactly that reason. 427 00:24:30,165 --> 00:24:34,365 Like they want to run some server side code that interacts with a document. 428 00:24:34,825 --> 00:24:36,535 same with the node on the node side. 429 00:24:37,070 --> 00:24:40,240 We support kind of the built in WebSocket client in the browser, but 430 00:24:40,240 --> 00:24:44,270 we also support a shimmed in WebSocket client so that you can run it in Node. 431 00:24:45,043 --> 00:24:45,713 Very cool. 432 00:24:45,753 --> 00:24:49,993 Yeah, I'm really looking forward to like, whether it's Python or well, 433 00:24:50,160 --> 00:24:55,678 I'm a native person in JavaScript and JavaScript has this amazing, Aspect to 434 00:24:55,678 --> 00:25:00,478 it that supposedly runs everywhere and we're getting more and more there with 435 00:25:00,478 --> 00:25:03,805 like ESM now, being really, the default. 436 00:25:03,885 --> 00:25:09,178 And, I'm really excited about bringing the same business logic, the same code 437 00:25:09,408 --> 00:25:11,598 to all sorts of different platforms. 438 00:25:11,948 --> 00:25:14,013 And I think sync engines are. 439 00:25:14,247 --> 00:25:19,177 or like a huge lever that gets us closer towards that since like, otherwise 440 00:25:19,177 --> 00:25:24,223 we can have, the code there, but if we don't have the data there, that 441 00:25:24,263 --> 00:25:26,773 is only good for so many use cases. 442 00:25:27,383 --> 00:25:28,223 So maybe. 443 00:25:28,383 --> 00:25:32,163 transitioning towards Y-Sweet, what you've already mentioned. 444 00:25:32,567 --> 00:25:37,357 before we get into what Y-Sweet is, can you share more about 445 00:25:37,367 --> 00:25:42,137 the origin story of Y-Sweet and which problems you try to solve? 446 00:25:42,540 --> 00:25:42,910 Yeah. 447 00:25:42,973 --> 00:25:46,910 so we'd already been working on Jamsocket for a while by the time we started Y-Sweet 448 00:25:46,930 --> 00:25:50,417 and we sort of started to see for one thing, You know, we thought from the 449 00:25:50,417 --> 00:25:53,467 get go that, well, people are going to want to write their own sync engines. 450 00:25:53,843 --> 00:25:57,043 one of the things we saw was that a lot of people were sort of using Yjs 451 00:25:57,043 --> 00:26:03,143 and other CRDTs and running those on Jamsocket and finding advantages, even 452 00:26:03,143 --> 00:26:08,263 though they don't need the authoritative kind of model of Jamsocket that they were 453 00:26:08,263 --> 00:26:10,273 still finding advantages to having that. 454 00:26:10,680 --> 00:26:14,550 so we started thinking like, what would a Yjs server kind of built 455 00:26:14,560 --> 00:26:16,000 to run on Jamsocket look like? 456 00:26:16,000 --> 00:26:17,050 And one of the things that. 457 00:26:17,855 --> 00:26:20,385 It's nice if we're, you know, running a lot of a process is that 458 00:26:20,385 --> 00:26:22,055 it's really memory lightweight. 459 00:26:22,055 --> 00:26:26,225 So we wrote Y-Sweet in Rust and it's pretty memory efficient. 460 00:26:26,578 --> 00:26:30,448 another thing that we became really opinionated about is that you shouldn't 461 00:26:30,458 --> 00:26:32,588 really start document data in a database. 462 00:26:32,648 --> 00:26:33,778 I think it's just a bad fit. 463 00:26:33,828 --> 00:26:37,638 I think with something like a, you know, if you're building something 464 00:26:37,638 --> 00:26:40,388 like Figma, like Figma uses S3. 465 00:26:40,678 --> 00:26:44,908 As where they store the document, they store the document metadata in Postgres 466 00:26:44,938 --> 00:26:49,938 and started to see a lot of use cases of like patterns like that, because if 467 00:26:49,938 --> 00:26:54,160 you're writing the document each document that's open many times a minute, If 468 00:26:54,160 --> 00:26:57,140 you're using a Postgres database, that Postgres database is in the bottleneck. 469 00:26:57,210 --> 00:26:59,160 Every, every edit is coming through that. 470 00:26:59,480 --> 00:27:03,310 Whereas S3 is a more distributed kind of file system where if you 471 00:27:03,320 --> 00:27:07,820 have a server that is the authority of what's in a document at that 472 00:27:07,820 --> 00:27:11,890 given point in time, it can just write to S3 and you can horizontally 473 00:27:11,890 --> 00:27:13,130 scale that out as much as you want. 474 00:27:13,150 --> 00:27:16,580 So we kind of became opinionated about, okay, that should be rust. 475 00:27:16,580 --> 00:27:17,320 It should be lightweight. 476 00:27:17,360 --> 00:27:18,520 It should write to S3. 477 00:27:18,880 --> 00:27:20,410 and it should be, Okay. 478 00:27:20,783 --> 00:27:25,057 As simple as possible to just use, like, I really like software like Caddy, where 479 00:27:25,067 --> 00:27:28,297 it is, which is web server written in Go, if people aren't familiar with it, where 480 00:27:28,297 --> 00:27:31,417 you like that has really sane defaults. 481 00:27:31,477 --> 00:27:34,967 It's somewhat opinionated about just doing things right. 482 00:27:34,967 --> 00:27:35,997 You don't have to 483 00:27:35,997 --> 00:27:36,627 fantastic. 484 00:27:36,627 --> 00:27:41,933 It even gives you like, SL certificates that work locally works with tail scales. 485 00:27:41,933 --> 00:27:42,563 Fantastic. 486 00:27:42,563 --> 00:27:43,423 Definitely check it out. 487 00:27:43,423 --> 00:27:44,603 If you're not using it yet. 488 00:27:45,143 --> 00:27:50,453 Yeah, so Caddy just like simplifies so much and just like does things right. 489 00:27:50,463 --> 00:27:52,793 And so we wanted to build a piece of software that was felt like 490 00:27:52,793 --> 00:27:56,143 that to use, that it was, we wanted something that you could use in a 491 00:27:56,143 --> 00:28:01,093 CICD process and it would be the same API as if you were using it at scale, 492 00:28:01,413 --> 00:28:03,013 horizontally scaled out on the cluster. 493 00:28:03,053 --> 00:28:06,073 so it was like, because the other thing, I mean, the things that we were thinking 494 00:28:06,073 --> 00:28:11,758 about at the time were like, what would an open source document sync engine 495 00:28:11,758 --> 00:28:16,762 look like, if we were to write it from scratch and we kind of kept landing on, 496 00:28:17,632 --> 00:28:22,002 it would look something like, you know, pretty close to Yjs, even if we didn't 497 00:28:22,012 --> 00:28:25,292 have the distributed constraints of Yjs. 498 00:28:25,698 --> 00:28:28,408 So we're like, well, Yjs exists. 499 00:28:28,408 --> 00:28:29,938 It has great community. 500 00:28:30,493 --> 00:28:31,983 Great people involved with it. 501 00:28:32,423 --> 00:28:34,223 this looks like what we would want to build. 502 00:28:34,223 --> 00:28:36,783 So let's just build a sync engine around this. 503 00:28:37,293 --> 00:28:37,683 Got it. 504 00:28:37,973 --> 00:28:43,270 In terms of the, behavior or like what makes it a little bit more like Caddy 505 00:28:43,290 --> 00:28:48,357 in terms of opinionated, but like, very well motivated opinions baked 506 00:28:48,357 --> 00:28:50,987 into it, if you compare it to the Yjs. 507 00:28:51,267 --> 00:28:56,820 Default server, any sort of thing that stands out there where you lean a little 508 00:28:56,820 --> 00:28:59,100 bit more heavy into some opinions? 509 00:28:59,490 --> 00:29:03,400 Yeah, I mean, I think the default Yjs server is built to be very modular 510 00:29:03,400 --> 00:29:08,412 and suit a bunch of use cases The Yjs community in general embraces this 511 00:29:08,412 --> 00:29:10,802 idea of providers where a provider. 512 00:29:10,882 --> 00:29:15,732 So Yjs itself is just a data structure and then providers are what will synchronize 513 00:29:15,732 --> 00:29:18,782 it to another client or synchronize it to a database or things like that. 514 00:29:19,075 --> 00:29:22,605 the kind of official way to do things in the. 515 00:29:22,955 --> 00:29:25,975 Yjs world is to kind of compose a bunch of providers together. 516 00:29:26,242 --> 00:29:29,782 so you might have an index db provider on the client, synchronizing the index db. 517 00:29:30,182 --> 00:29:34,142 You might have a web socket provider, synchronizing to other clients. 518 00:29:34,602 --> 00:29:36,842 And then you might have a database provider on the server. 519 00:29:37,232 --> 00:29:41,642 We wanted to just have a single stack that was kind of our opinionated stack. 520 00:29:41,642 --> 00:29:44,892 So we have an index db implementation on the client. 521 00:29:45,332 --> 00:29:49,122 We have our s3 storage, which we've Decided is, you know, the only storage 522 00:29:49,692 --> 00:29:52,562 that will support will support S3 compatible storage, but it's, it's 523 00:29:52,562 --> 00:29:57,982 ultimately our opinion was object storage is the right way to do storage for this. 524 00:29:58,302 --> 00:30:00,392 and then we have our, our wire protocol as well. 525 00:30:00,402 --> 00:30:00,862 WebSocket. 526 00:30:01,489 --> 00:30:01,939 Got it. 527 00:30:02,029 --> 00:30:02,749 That makes sense. 528 00:30:02,929 --> 00:30:03,149 Yeah. 529 00:30:03,149 --> 00:30:05,744 And I haven't managed yet to. 530 00:30:05,744 --> 00:30:10,407 Have, Kevin Jans here on the podcast, but he happens to also live in Berlin, 531 00:30:10,437 --> 00:30:14,710 and I've just seen him, for the, last local-first meetup that we've done here. 532 00:30:14,980 --> 00:30:20,294 So I think it's, well, about time that we hear from Kevin, about YJS, there's 533 00:30:20,294 --> 00:30:26,439 been, it's been such a rich ecosystem of different things around it, so I 534 00:30:26,469 --> 00:30:28,204 think we gotta make that happen as well. 535 00:30:28,654 --> 00:30:29,454 Yeah, you should. 536 00:30:29,454 --> 00:30:33,834 So I'm actually, I've been procrastinating editing a podcast that I did with Kevin. 537 00:30:33,914 --> 00:30:34,904 so we'll have that soon. 538 00:30:35,684 --> 00:30:36,224 There you go. 539 00:30:36,277 --> 00:30:37,777 we should put it in the show notes. 540 00:30:38,227 --> 00:30:45,000 So, YJS you've built, just, as you've seen that this is a, flavor of Sync 541 00:30:45,000 --> 00:30:48,440 server that can be hosted on, Jamsocket. 542 00:30:48,820 --> 00:30:55,480 So, is my understanding correct that, if I want to use YJS with Y Suite, I can just 543 00:30:55,480 --> 00:30:58,140 deploy that off the shelf on Jamsocket 544 00:30:59,390 --> 00:31:00,990 yeah, so you could deploy that. 545 00:31:01,280 --> 00:31:04,240 We have like a off the shelf offering that deploys it on Jamsocket. 546 00:31:04,620 --> 00:31:07,060 you can run it on your own servers as well. 547 00:31:07,137 --> 00:31:10,540 and it's one of the things we decided was like, regardless of how it's 548 00:31:10,540 --> 00:31:12,310 hosted, it should be the same API. 549 00:31:12,310 --> 00:31:15,870 So we have kind of the, what I call it, the document management API where 550 00:31:15,870 --> 00:31:19,640 you're, you know, create a document, give somebody an access token to that document. 551 00:31:19,777 --> 00:31:22,567 that is sort of just universal, no matter how it's deployed. 552 00:31:22,977 --> 00:31:28,077 Got it, so I think Yjs is one of the most mature options right now for 553 00:31:28,077 --> 00:31:32,047 people who want to build local-first apps, for people who are just, who've 554 00:31:32,047 --> 00:31:36,924 heard it a bunch of times, but maybe haven't yet come around to, fully. 555 00:31:37,264 --> 00:31:38,784 Implement their app using it. 556 00:31:39,134 --> 00:31:42,634 what are questions that people should ask themselves? 557 00:31:42,634 --> 00:31:47,134 Whether Yjs is a useful foundation for the app and in which scenarios 558 00:31:47,154 --> 00:31:50,804 would you say, actually, you probably want to build your own sync engine. 559 00:31:51,204 --> 00:31:54,434 yeah, so I, I think the, one of the first dimensions to think about here is 560 00:31:54,434 --> 00:31:56,474 I see this sort of, there's two worlds. 561 00:31:56,474 --> 00:31:58,224 There's like database. 562 00:31:58,575 --> 00:32:00,845 sync engines and then there's document sync engines. 563 00:32:01,285 --> 00:32:04,255 So for database sync engine, I think of things like Linear, like things 564 00:32:04,255 --> 00:32:08,765 where you have some relational model data, you probably don't 565 00:32:08,765 --> 00:32:10,005 want the client to have all of it. 566 00:32:10,005 --> 00:32:14,049 You kind of have, the client storing some subset of a Database 567 00:32:14,049 --> 00:32:15,804 for each, for each account. 568 00:32:16,034 --> 00:32:19,764 Maybe you're sharing this data across multiple people in that account. 569 00:32:20,034 --> 00:32:25,484 database sync world where there's, Elastic SQL and, zero and, power sync 570 00:32:25,484 --> 00:32:27,844 and kind of a number of players there. 571 00:32:28,298 --> 00:32:31,137 instant DB and triplet and a number of others. 572 00:32:31,784 --> 00:32:36,837 on the document sync side, that's where you kind of have, you're sending 573 00:32:36,847 --> 00:32:38,157 all of the data down to the client. 574 00:32:38,157 --> 00:32:41,054 So you're dealing with kind of the unit of data that gets synced 575 00:32:41,064 --> 00:32:43,590 is in memory size on the browser. 576 00:32:43,590 --> 00:32:45,400 You're not dealing with like a terabyte of data here. 577 00:32:45,444 --> 00:32:46,604 you're not taking a subset of it. 578 00:32:46,604 --> 00:32:48,074 You're synchronizing the entire document. 579 00:32:48,614 --> 00:32:51,990 This would be kind of things like Figma or Google Docs, where 580 00:32:52,160 --> 00:32:54,170 there's a full local copy of. 581 00:32:54,530 --> 00:32:57,000 Some self standing piece of data. 582 00:32:57,480 --> 00:33:00,440 and generically in, Yjs, that's essentially like a 583 00:33:00,440 --> 00:33:03,160 JSON style or JSON shape data. 584 00:33:03,540 --> 00:33:07,084 So things like nested maps, things like nested lists, and 585 00:33:07,084 --> 00:33:10,200 text, and then JSON primitives. 586 00:33:10,584 --> 00:33:15,434 Is it fair to say that, so you've mentioning Figma, Google Docs, if I think 587 00:33:15,434 --> 00:33:20,717 about Figma and Google Docs, there is like a distinct boundary of a document. 588 00:33:20,987 --> 00:33:23,417 So I have a Google Docs document open. 589 00:33:23,457 --> 00:33:25,157 I have a Figma document open. 590 00:33:25,575 --> 00:33:32,775 is it wherever a product experience has sort of like for a given part of 591 00:33:32,775 --> 00:33:38,065 the experience is all centered around a document or tl draw comes to mind? 592 00:33:38,429 --> 00:33:44,404 is that a great fit for embracing the document model and anything that 593 00:33:44,444 --> 00:33:49,294 is more, rich in terms of, like a relational database where you can 594 00:33:49,294 --> 00:33:51,224 just freely join between things. 595 00:33:51,564 --> 00:33:56,334 That's where you would choose the other approach is that's a useful rule of thumb. 596 00:33:56,777 --> 00:33:57,067 Yeah. 597 00:33:57,067 --> 00:34:00,817 I think the words, that you use distinct boundary, I think that's really nails it. 598 00:34:00,904 --> 00:34:03,904 a, if there's kind of like a document with This is like self contained. 599 00:34:04,054 --> 00:34:05,094 It's distinct. 600 00:34:05,274 --> 00:34:08,724 you mentioned TL draw like, and actually, I mean, I think this gets 601 00:34:08,724 --> 00:34:12,744 to another point is that you can use both in the same application. 602 00:34:13,074 --> 00:34:17,074 So TL draw uses zero and their own document sync engine. 603 00:34:17,904 --> 00:34:21,194 Figma has built their own sync engine for both. 604 00:34:21,657 --> 00:34:23,037 and they're distinct sync engines. 605 00:34:23,382 --> 00:34:24,942 They can be used in tandem as well, 606 00:34:25,405 --> 00:34:29,929 right I mean, that gets us to a really interesting, topic more generally, which 607 00:34:29,929 --> 00:34:32,499 is combining multiple sync engines. 608 00:34:32,539 --> 00:34:37,549 And I think for people who've been dabbling in local-first, that might be 609 00:34:37,559 --> 00:34:42,439 more intuitive, but I think for, people who are just very new to, the local-first 610 00:34:42,459 --> 00:34:47,719 space, it's hard enough to wrap your head around, choosing the right sync engine. 611 00:34:47,719 --> 00:34:50,889 Now you're telling us, wait, you should choose multiple. 612 00:34:51,229 --> 00:34:54,712 Can you motivate a little bit more of like, how to think about that? 613 00:34:55,215 --> 00:34:57,655 so I think of it as like the app layer and the document layer. 614 00:34:57,685 --> 00:35:00,745 If you have a document based application, there's, you know, if you have a 615 00:35:00,755 --> 00:35:03,585 file viewer, for example, I think of that as app layer, you're not in 616 00:35:03,585 --> 00:35:04,905 a specific document at that moment, 617 00:35:05,335 --> 00:35:09,225 like in Figma where I'm on the home screen and I see my various projects. 618 00:35:09,895 --> 00:35:11,265 Yeah, exactly. 619 00:35:11,338 --> 00:35:16,318 and I think there's nothing that forces that part to be real time synced. 620 00:35:16,621 --> 00:35:19,631 In a lot of cases, I think a traditional Postgres database 621 00:35:20,201 --> 00:35:21,351 goes a long way for that. 622 00:35:21,755 --> 00:35:25,895 and then, but then once you're in the document, that's where I think you, you 623 00:35:25,895 --> 00:35:29,941 do kind of need a sync engine because, it's the type of thing that if you have 624 00:35:30,031 --> 00:35:33,701 two Google Docs open in two different tabs, you expect them to be in sync, 625 00:35:33,711 --> 00:35:35,101 even if you're just a single user. 626 00:35:35,473 --> 00:35:38,033 I think that actually motivates like 98 percent of the value of 627 00:35:38,033 --> 00:35:41,143 local-first is just somebody who has the same document open in two 628 00:35:41,143 --> 00:35:42,573 tabs and they've got 100 tabs open. 629 00:35:43,086 --> 00:35:48,886 I think that that's less of a given expectation these days for like a 630 00:35:48,886 --> 00:35:50,406 project view or something like that. 631 00:35:50,406 --> 00:35:52,800 I think that It's a nice surprise when that is in sync. 632 00:35:52,830 --> 00:35:56,800 And I think it is becoming the status quo, but I think that overall it's. 633 00:35:57,051 --> 00:36:00,761 less of an expectation that, Oh, you might have to refresh your Figma 634 00:36:00,761 --> 00:36:06,141 project, to sort of see the new assets that come up or that kind of thing. 635 00:36:06,568 --> 00:36:10,738 so yeah, but it is, I do think, and there's been a bit of Twitter debate 636 00:36:10,738 --> 00:36:13,898 about this lately, but like whether the same sync engine can handle both. 637 00:36:14,271 --> 00:36:18,003 I think that there are things that you are going to need transactions for, and if you 638 00:36:18,003 --> 00:36:21,890 need transactions, you're going to need a database with a single that is effectively 639 00:36:21,890 --> 00:36:23,480 a single bottleneck on updates. 640 00:36:23,960 --> 00:36:27,150 At the same time, if you have lots of documents, you don't want those documents 641 00:36:27,180 --> 00:36:28,850 to be bottlenecked in a single point. 642 00:36:29,290 --> 00:36:33,986 So I think unless there's a solution that offers both distributed and centralized 643 00:36:33,986 --> 00:36:36,316 with transactions, you kind of need both. 644 00:36:36,735 --> 00:36:37,085 Got it. 645 00:36:37,095 --> 00:36:42,155 So, if you're thinking more about the leaning into the document aspect of 646 00:36:42,155 --> 00:36:47,558 it, or even, when you say like, that something is bottleneck, let's say we 647 00:36:47,568 --> 00:36:50,415 also embrace the, database aspect of it. 648 00:36:50,875 --> 00:36:52,335 Maybe you have different. 649 00:36:52,630 --> 00:36:58,280 Workspaces, and, I think there's still like one aspect of like drawing 650 00:36:58,280 --> 00:37:03,486 boundaries around some body of data, where you say like, Hey, within 651 00:37:03,496 --> 00:37:08,886 that boundary, I care about certain constraints, maybe that there shouldn't 652 00:37:08,886 --> 00:37:11,546 be more than 10 documents ever. 653 00:37:11,941 --> 00:37:16,321 Or maybe you want to enforce some constraints around like 654 00:37:16,411 --> 00:37:18,811 users, access control, et cetera. 655 00:37:19,201 --> 00:37:23,841 can you share any sort of learnings or advice about how 656 00:37:23,841 --> 00:37:25,921 to approach this entire topic? 657 00:37:25,951 --> 00:37:31,561 Like, how do you decide this is a useful boundary about like how data should be 658 00:37:31,601 --> 00:37:34,901 modeled at and fragmented or petitioned. 659 00:37:35,371 --> 00:37:39,575 And what are some of the dimensions that should be taken into consideration here? 660 00:37:40,031 --> 00:37:43,791 So I think in general, if it's not obvious what a document 661 00:37:43,791 --> 00:37:47,441 should be in an application, then it's probably the document model 662 00:37:47,441 --> 00:37:49,261 is probably not the right fit. 663 00:37:49,431 --> 00:37:53,188 I think things like Figma where, you know, you're, in a document at a time, like. 664 00:37:53,763 --> 00:37:55,803 You might have a different document in another tab, but 665 00:37:55,803 --> 00:37:59,353 you don't have two documents in the same tab concurrently open. 666 00:37:59,733 --> 00:38:01,223 it's taking up the whole screen. 667 00:38:01,233 --> 00:38:05,593 Like, I think that there's certain heuristics like that, that just 668 00:38:05,593 --> 00:38:08,793 tell you, like, this is definitely a document model application. 669 00:38:09,213 --> 00:38:10,893 Same with Google Drive or Google Docs. 670 00:38:11,006 --> 00:38:12,196 you kind of have one thing. 671 00:38:12,511 --> 00:38:13,381 Open at once, 672 00:38:13,851 --> 00:38:15,231 where would you put Linear? 673 00:38:15,261 --> 00:38:21,138 Since you could, for example, put each Linear issue into its own document. 674 00:38:21,168 --> 00:38:23,678 Why might that be a reasonable approach? 675 00:38:23,745 --> 00:38:24,145 where is this? 676 00:38:24,145 --> 00:38:24,845 Where might have not? 677 00:38:25,531 --> 00:38:27,661 I think I could see. 678 00:38:28,191 --> 00:38:33,361 That being reasonable, if there, if you really care about the tickets themselves 679 00:38:33,401 --> 00:38:37,751 being, you know, multiple people editing a ticket at one time and seeing the text. 680 00:38:37,751 --> 00:38:41,705 And, if you really wanted to make that kind of a first class experience. 681 00:38:41,735 --> 00:38:46,945 But in general, I think that, Linear just screams kind of database approach to me. 682 00:38:47,275 --> 00:38:51,061 although I do, I know they are, I believe using Yjs, for some of the issue. 683 00:38:51,423 --> 00:38:55,473 text now could be wrong, but I think they do use it or a CRDT. 684 00:38:55,706 --> 00:38:58,116 it might be a different CRDT, but I think they're using some sort 685 00:38:58,116 --> 00:38:59,906 of collaborative text editor. 686 00:39:00,557 --> 00:39:05,827 so given that you've seen quite a couple of different customers and products 687 00:39:05,847 --> 00:39:11,597 build their own sync engines, any sort of interesting, almost second order effects 688 00:39:11,637 --> 00:39:17,967 that you've seen there, unexpected things, new challenges that you didn't see in, 689 00:39:18,257 --> 00:39:21,167 in previous applications, things like. 690 00:39:21,392 --> 00:39:25,232 Database migrations or other things, which sort of challenges 691 00:39:25,922 --> 00:39:27,102 and problems have you seen? 692 00:39:27,716 --> 00:39:32,606 Yeah, I think whenever you're dealing with data on S3, data migrations do 693 00:39:32,606 --> 00:39:35,876 become really interesting because you're not just sort of writing a 694 00:39:36,026 --> 00:39:38,526 database query and issuing an update. 695 00:39:39,556 --> 00:39:43,156 Usually some form of gradual lazy migration. 696 00:39:43,156 --> 00:39:46,686 So it's kind of like the application that's reading the data has to know 697 00:39:46,686 --> 00:39:50,166 how to transition from version one to two and two to three and then 698 00:39:50,736 --> 00:39:52,176 kind of apply those consecutively. 699 00:39:52,466 --> 00:39:57,286 And so that logic tends to linger around in the application for as long 700 00:39:57,286 --> 00:39:59,346 as you have old documents to support. 701 00:39:59,719 --> 00:40:04,599 and I think there's ways to do schema migrations or schema changes that 702 00:40:04,599 --> 00:40:06,049 don't require a migration as well. 703 00:40:06,049 --> 00:40:09,981 Like, I think that the, It was at Google and we, you know, there 704 00:40:09,981 --> 00:40:12,331 were certain rules about what you could do with protocol buffers. 705 00:40:12,734 --> 00:40:16,144 that would ensure that they were always backward and forward compatible. 706 00:40:16,291 --> 00:40:20,811 and so I think, you know, things like a required field always has to be required. 707 00:40:20,811 --> 00:40:21,111 And so. 708 00:40:21,854 --> 00:40:25,511 Deciding being delicate of when you call a field required. 709 00:40:25,957 --> 00:40:28,707 there's certain kind of things you can do at the schema design level and schema 710 00:40:28,707 --> 00:40:34,561 migration or schema change migration level that you can avoid kind of having 711 00:40:34,561 --> 00:40:36,031 to implement any sort of migration. 712 00:40:36,041 --> 00:40:39,211 It can kind of be more access time oriented. 713 00:40:39,691 --> 00:40:43,281 So I think doing that has been where I've seen. 714 00:40:43,831 --> 00:40:46,751 It will be successful with that, in terms of second order effects, I 715 00:40:46,751 --> 00:40:50,541 think kind of goes back to like, once you have the sync server, people are 716 00:40:50,541 --> 00:40:54,211 like, oh, this is now a place where I can trigger this notification or I 717 00:40:54,211 --> 00:40:59,837 can do this check or I can, you know, so I think we've sort of seen these, 718 00:41:00,257 --> 00:41:02,077 these backends kind of grow in scope. 719 00:41:02,244 --> 00:41:04,974 you know, we want that to be first class part of the application that 720 00:41:04,974 --> 00:41:06,504 can do whatever you want it to do. 721 00:41:07,046 --> 00:41:08,076 That makes a lot of sense. 722 00:41:08,116 --> 00:41:14,023 And yeah, I think this is, an area that, has already caused a lot of, headaches, 723 00:41:14,073 --> 00:41:18,393 schema migrations, data migrations in general, but now that we are rethinking 724 00:41:18,403 --> 00:41:24,833 the data architectures at large here, we also need to rethink that part and 725 00:41:24,843 --> 00:41:29,313 like you've mentioned, when you have all the data in a single Postgres database, 726 00:41:29,323 --> 00:41:33,961 then you can at least like apply like your old playbooks there, but now if all 727 00:41:33,961 --> 00:41:39,748 of your data is in an S3 bucket, laid out in whatever way, now you do need a 728 00:41:39,748 --> 00:41:41,878 different new approach to deal with that. 729 00:41:41,968 --> 00:41:46,441 And, That is one way to deal with it, to bake in the migration 730 00:41:46,441 --> 00:41:48,201 logic into your app logic. 731 00:41:48,701 --> 00:41:52,831 But, that is also, I think that also comes with its own downsides. 732 00:41:52,831 --> 00:41:58,081 This way you're like litter some of that code that was once very clear. 733 00:41:58,341 --> 00:42:02,041 and now you make it less clear because you need to account for. 734 00:42:02,331 --> 00:42:07,101 That historical evolution, a project that I want to shout out here is the 735 00:42:07,111 --> 00:42:12,848 project, Cambria by the folks at In I've actually studied this project myself quite 736 00:42:12,848 --> 00:42:17,718 intensively and I've rebuilt it, myself a few times once even on a type level 737 00:42:17,738 --> 00:42:20,425 just to, provide a nice type save API. 738 00:42:21,480 --> 00:42:25,570 Given that the original implementation rather lets you specify those 739 00:42:25,570 --> 00:42:27,760 sort of projection rules in YAML. 740 00:42:28,160 --> 00:42:31,630 But, I've heard some rumors that they're thinking of like rebooting 741 00:42:31,660 --> 00:42:32,970 that project at some point. 742 00:42:32,970 --> 00:42:34,370 So fingers crossed for that. 743 00:42:34,970 --> 00:42:39,250 And yeah, another approach that I'm investigating heavily myself, 744 00:42:39,290 --> 00:42:42,050 given I have my fair share of like. 745 00:42:42,185 --> 00:42:48,081 Database migration traumas, that I tried to remedy with, starting Prisma, 746 00:42:48,661 --> 00:42:52,065 but now I'm, trying a different approach with event sourcing. 747 00:42:52,525 --> 00:42:57,960 Where if you basically split up your documents your database 748 00:42:58,280 --> 00:43:02,900 into a dedicated write model and derive the read model from it. 749 00:43:02,930 --> 00:43:07,336 The core insight here is basically that if you split this up into two 750 00:43:07,336 --> 00:43:11,566 parts, the schema for your read model, that is typically the thing. 751 00:43:11,936 --> 00:43:16,916 That changes orders of magnitudes more often where you have different kind of 752 00:43:16,917 --> 00:43:21,276 queries that you want to do different sort of aggregations and where you want 753 00:43:21,276 --> 00:43:25,376 to maybe change the database layout to make certain queries faster and more 754 00:43:25,376 --> 00:43:29,236 efficient and then the write operations. 755 00:43:29,551 --> 00:43:34,641 Those are much more bound to the domain of when stuff actually happens. 756 00:43:34,941 --> 00:43:37,781 So, and that's changes way less over time. 757 00:43:37,781 --> 00:43:42,350 Like, maybe you want to capture, someone's preference on email, 758 00:43:42,351 --> 00:43:47,441 marketing emails on, on signup, but historically you can way easier say, 759 00:43:47,441 --> 00:43:49,431 like, actually we default to no. 760 00:43:49,905 --> 00:43:52,135 but a user signup event. 761 00:43:52,345 --> 00:43:55,785 Is always valid and way easier to upgrade. 762 00:43:56,175 --> 00:44:00,835 And then you can basically reapply all prior events into the new read 763 00:44:00,835 --> 00:44:03,665 model that you can change very easily. 764 00:44:03,665 --> 00:44:06,495 And you can even have like multiple read models all at once. 765 00:44:06,915 --> 00:44:11,581 So, that is what I'm exploring right now on the umbrella of Livestore. 766 00:44:12,061 --> 00:44:16,268 But, that also comes then requires that rigor to split it 767 00:44:16,308 --> 00:44:17,938 up into a read and write model. 768 00:44:18,398 --> 00:44:20,208 But yeah, curious whether you have thoughts on that. 769 00:44:20,756 --> 00:44:21,866 Yeah, that's really interesting. 770 00:44:21,866 --> 00:44:27,166 I think that event sourcing in general does sort of simplify migrations. 771 00:44:27,176 --> 00:44:30,706 If you're willing to kind of go back over the event source log and regenerate, 772 00:44:30,726 --> 00:44:35,096 because then as long as you represented all of the data that matters, then you 773 00:44:35,106 --> 00:44:37,961 can essentially just add fields as. 774 00:44:38,151 --> 00:44:38,891 As needed to 775 00:44:39,408 --> 00:44:44,708 another problem that emerges in that world is like, if your domain produces 776 00:44:44,728 --> 00:44:50,448 a lot of events, so let's say you build a TL draw and whenever you move 777 00:44:50,448 --> 00:44:55,391 a rectangle, that creates, you could model it in a way that when you let go 778 00:44:55,391 --> 00:44:58,861 of the rectangle that creates an event, but you could even model it in a way. 779 00:44:59,161 --> 00:45:03,995 Where, like whenever the browser registered a new move event, dragging 780 00:45:03,995 --> 00:45:10,435 it can cause 5, 000 events and that can lead to a very long history of events. 781 00:45:10,445 --> 00:45:13,415 So now you gotta keep that in mind as well. 782 00:45:13,965 --> 00:45:18,501 And, whereas in the traditional mixed read and write model approach, you 783 00:45:18,501 --> 00:45:23,878 would basically just overwrite the position and it would not necessarily 784 00:45:24,068 --> 00:45:25,828 cause the database to explode. 785 00:45:26,071 --> 00:45:27,581 because you have too much data. 786 00:45:27,945 --> 00:45:30,898 but yeah, it's all about trade offs that that is like, what 787 00:45:30,898 --> 00:45:32,428 data management is all about. 788 00:45:32,786 --> 00:45:37,626 maybe a slightly different aspect about data that, you've also written about, 789 00:45:37,916 --> 00:45:41,056 which is in regards to encrypting data. 790 00:45:41,526 --> 00:45:44,863 So, you've written a great blog post about that. 791 00:45:45,183 --> 00:45:48,666 can you tell us more about that blog post and, what it's about? 792 00:45:49,040 --> 00:45:52,280 Yeah, so this came out of when we were with Y-Sweet. 793 00:45:52,300 --> 00:45:56,595 We wanted to do We wanted to have store the data locally in the 794 00:45:56,595 --> 00:45:58,215 client, at least as an option. 795 00:45:58,711 --> 00:46:01,351 so we looked at the options that were available or, you know, local 796 00:46:01,351 --> 00:46:06,625 storage, indexed db, opfs, origin, private file system, realized that 797 00:46:06,655 --> 00:46:10,255 indexed db was really the kind of the right way to go for this right now. 798 00:46:10,375 --> 00:46:14,255 have high hopes on opfs, but they're still, I mean, they 799 00:46:14,255 --> 00:46:16,335 all kind of have flaws, but. 800 00:46:16,715 --> 00:46:20,315 Index DB is like the best people know the flaws the best, I guess, 801 00:46:20,425 --> 00:46:21,685 and how to work around them. 802 00:46:21,695 --> 00:46:23,148 So, looked at index DB. 803 00:46:23,148 --> 00:46:27,488 But the problem that we found with all of them is that all of them store 804 00:46:27,488 --> 00:46:32,568 the data in plain text, and that's not just a theoretical problem. 805 00:46:32,568 --> 00:46:34,438 There is at least a couple months ago. 806 00:46:34,438 --> 00:46:39,868 Now, there was some, you know, NPM and pie pie modules out there that 807 00:46:39,868 --> 00:46:43,558 would read some application data from these plain text sources. 808 00:46:43,991 --> 00:46:45,911 it's kind of a real problem that people have identified. 809 00:46:46,856 --> 00:46:47,946 And has been exploited. 810 00:46:48,370 --> 00:46:51,370 so we wanted to make sure that we provided an option that at least as, 811 00:46:51,410 --> 00:46:54,160 as best as possible would prevent that. 812 00:46:54,666 --> 00:46:57,023 so we said, okay, well, browsers have web crypto. 813 00:46:57,033 --> 00:46:58,323 We can encrypt all this. 814 00:46:58,663 --> 00:47:01,163 but then there's this problem of where do you store the key? 815 00:47:01,250 --> 00:47:04,090 because you could start on on the server, but then kind of defeats 816 00:47:04,090 --> 00:47:07,446 the purpose if you're offline, of then accessing that data. 817 00:47:07,916 --> 00:47:09,746 So realize that. 818 00:47:10,260 --> 00:47:16,333 don't really have a good way to store a key kind of credential. 819 00:47:16,703 --> 00:47:21,753 we've got like WebAuthn, but WebAuthn is a bit more secure, like, which is where 820 00:47:21,753 --> 00:47:23,253 you have pass keys and things like that. 821 00:47:23,513 --> 00:47:24,863 It's a bit more opinionated. 822 00:47:24,873 --> 00:47:29,590 It uses the operating systems key chain, but it, doesn't really expose that to 823 00:47:29,590 --> 00:47:33,690 you as any sort of low level API that you can store your own secrets in. 824 00:47:34,181 --> 00:47:37,861 What has started happening is that some browsers, particularly Chromium 825 00:47:37,901 --> 00:47:44,025 based browsers, Google Chrome, Edge, Rave, have built in something called 826 00:47:44,025 --> 00:47:48,805 App-Bound encryption, and they're just using this for cookies, but the idea 827 00:47:48,805 --> 00:47:54,295 is that the browser will store, cookies in, you know, on disk as they always 828 00:47:54,305 --> 00:47:59,785 have, but they'll be encrypted on disk, and then the symmetric key to that will 829 00:47:59,785 --> 00:48:05,463 be stored in the, Operating systems keychain and the operating system is set 830 00:48:05,463 --> 00:48:09,453 up to at least in theory, and there's been some vulnerabilities here, too. 831 00:48:09,453 --> 00:48:14,036 But, at least in theory, only give that private key back to 832 00:48:14,036 --> 00:48:18,365 the browser process itself not to another process that attempts to 833 00:48:18,585 --> 00:48:20,180 impersonate, the browser process. 834 00:48:20,710 --> 00:48:24,436 So what we landed on, which was pretty surprising to me, that this was kind 835 00:48:24,436 --> 00:48:26,976 of the best available path right now. 836 00:48:27,566 --> 00:48:33,056 But if you enable local storage, we encrypt it stored in index DB and 837 00:48:33,056 --> 00:48:35,166 then store the key in a cookie and. 838 00:48:35,796 --> 00:48:39,776 Kind of piggyback on that being App-Bound encrypted in at least 839 00:48:39,776 --> 00:48:40,736 in browsers to support it. 840 00:48:41,200 --> 00:48:42,470 That is very interesting. 841 00:48:42,470 --> 00:48:46,770 Yeah, I've been studying, cryptography, particularly in a browser context, 842 00:48:46,780 --> 00:48:49,510 also a bit more for various reasons. 843 00:48:49,550 --> 00:48:55,380 I am, trying to see what would it take to, do the entire, sync. 844 00:48:55,617 --> 00:49:00,951 messages for Livestore, what would it be, for them to be enter and encrypted, 845 00:49:01,301 --> 00:49:06,591 but the hard part is not the encryption, but the hard part is the end to end 846 00:49:07,011 --> 00:49:11,505 where, the various ends own their keys. 847 00:49:11,505 --> 00:49:14,910 And there's a, we should do an entire episode just about that. 848 00:49:14,943 --> 00:49:18,619 what's difficult about it, but, it can all be distilled down to 849 00:49:18,619 --> 00:49:23,096 the hard part about, anything cryptography related as key management. 850 00:49:23,449 --> 00:49:27,769 And you can either around the side of like being a little bit more loose with like 851 00:49:27,769 --> 00:49:32,616 how you manage keys, but that defies a lot of the, purposes and the benefits here. 852 00:49:32,889 --> 00:49:38,269 but then also the, browser makes that really, really tricky because it has very 853 00:49:38,269 --> 00:49:43,846 constrained APIs and historically it's always been rather a web document viewer 854 00:49:43,906 --> 00:49:49,514 than a fully fledged application platform and, we're getting the building blocks. 855 00:49:49,514 --> 00:49:52,327 I mean, you can, use the, web crypto API. 856 00:49:52,611 --> 00:49:57,891 I'm also using the Libsodium projects, compiled to WASM, which is very 857 00:49:57,891 --> 00:50:00,041 powerful and gives you a couple. 858 00:50:00,518 --> 00:50:05,468 of advanced, algorithms, et cetera, that you can use for, symmetric or 859 00:50:05,468 --> 00:50:08,348 asymmetric encryption, signing, et cetera. 860 00:50:08,751 --> 00:50:13,148 and pass keys, I think are also like, a super important foundation. 861 00:50:13,663 --> 00:50:16,288 But, they also get you just so far. 862 00:50:16,288 --> 00:50:20,248 And I think they don't really help you for the encryption as such, 863 00:50:20,258 --> 00:50:23,018 but rather for signing messages. 864 00:50:23,028 --> 00:50:25,518 So I think we're still lacking a few building blocks. 865 00:50:25,788 --> 00:50:30,775 So very excited to hear about this what, what it was again, App-Bound. 866 00:50:31,275 --> 00:50:37,785 App-Bound encryption, so ideally at some point, this goes even beyond cookies that, 867 00:50:37,838 --> 00:50:41,378 this can be applied for other storage mechanisms, but I like the approach 868 00:50:41,668 --> 00:50:46,101 to, basically encrypt it and then you reduce it to the key management problem 869 00:50:46,401 --> 00:50:52,181 and that you put into a cookie, which also, there's another question, which is 870 00:50:52,211 --> 00:50:54,631 what happens if that cookie goes away? 871 00:50:55,048 --> 00:50:57,378 did you figure out a, an answer for that? 872 00:50:58,065 --> 00:50:58,745 we don't. 873 00:50:58,775 --> 00:51:02,945 We just set it to a long expiration, but it's the thinking there was like, 874 00:51:02,945 --> 00:51:08,448 if the user is clearing their cookies on that tab or on that hosting, they 875 00:51:08,448 --> 00:51:10,718 probably want to destroy the data. 876 00:51:10,778 --> 00:51:13,128 And so are they, you know, they want to be logged out. 877 00:51:13,400 --> 00:51:17,013 so we actually saw it as the right thing to do to, bind it. 878 00:51:17,343 --> 00:51:21,143 The other nice thing about that is like, unlike indexed DB cookies can 879 00:51:21,143 --> 00:51:22,413 actually have an expiration date. 880 00:51:22,413 --> 00:51:24,933 So we could set an expiration of a week. 881 00:51:25,133 --> 00:51:28,343 we're still relying on the browser to enforce that, but if the browser enforces 882 00:51:28,353 --> 00:51:33,083 that, and then, you know, two weeks later, that person is fully hacked, including 883 00:51:33,083 --> 00:51:36,613 their operating system key chain, the browser, at least in theory, will have 884 00:51:36,803 --> 00:51:40,483 deleted that private key and then the data that's in IndexedDB will be gone. 885 00:51:40,803 --> 00:51:43,533 So that's actually, funny enough, additional functionality. 886 00:51:43,533 --> 00:51:45,703 It was just incidental to the, to using cookies for that. 887 00:51:46,163 --> 00:51:46,623 Right. 888 00:51:46,686 --> 00:51:49,436 I like this trick a lot and I got to look into it. 889 00:51:49,756 --> 00:51:54,370 One thing to point out still is, you've mentioned that this mechanism is only 890 00:51:54,370 --> 00:52:00,563 available in Chromium browsers anyway, but, cookies and IndexedDB, OPFS, et 891 00:52:00,563 --> 00:52:05,270 cetera, all of that is available in other browsers and namely Safari as well. 892 00:52:05,490 --> 00:52:11,483 One thing that, people find out the hard way about Safari is that it automatically 893 00:52:11,503 --> 00:52:16,363 deletes a user's data after seven days if they haven't visited that website. 894 00:52:16,913 --> 00:52:21,673 So if you're building a fully local-first web experience where 895 00:52:21,673 --> 00:52:26,686 someone, creates some precious data, in Safari and maybe doesn't sync it 896 00:52:26,686 --> 00:52:31,906 yet to somewhere else, go on vacation, come back and poof, the data is gone. 897 00:52:32,196 --> 00:52:36,676 So I think as app builders, we need to be aware of that and 898 00:52:36,686 --> 00:52:38,476 detect, Hey, is this Safari? 899 00:52:38,886 --> 00:52:42,577 And in Safari, make this part of the product experience show sort of like 900 00:52:42,713 --> 00:52:44,926 a message, like, Hey, be careful. 901 00:52:44,966 --> 00:52:46,226 Your data might go away. 902 00:52:46,586 --> 00:52:48,436 There are ways to remedy that. 903 00:52:48,506 --> 00:52:53,510 And, to, for example, if you make the Safari app, a, progressive web 904 00:52:53,510 --> 00:52:56,170 app by adding it to the home screen. 905 00:52:56,330 --> 00:52:57,910 That limitation goes away. 906 00:52:58,214 --> 00:53:03,903 but app builders need to be aware that they can make the app users aware. 907 00:53:04,156 --> 00:53:08,370 it's just something that, I think is important to, note. 908 00:53:08,880 --> 00:53:11,590 Yeah, I think that's an example of a number of cases where the 909 00:53:11,590 --> 00:53:15,480 browsers are just not optimized for local-first apps, unfortunately. 910 00:53:15,676 --> 00:53:21,416 you know, the, I think the ability to just store low level access to the operating 911 00:53:21,416 --> 00:53:23,436 systems key chain is another, where. 912 00:53:23,906 --> 00:53:28,416 Browsers have improved a ton in terms of what they expose of the APIs, but I 913 00:53:28,416 --> 00:53:31,876 think they're still lagging when it comes to that storage and encrypted storage. 914 00:53:32,426 --> 00:53:33,466 Yeah, totally. 915 00:53:34,006 --> 00:53:38,793 So, maybe slightly, moving to another browser related topic. 916 00:53:39,010 --> 00:53:43,910 you've been both through your work, Through your prior role, and 917 00:53:43,920 --> 00:53:47,270 also as part of Jamsocket, you've been dealing with quite a bit 918 00:53:47,270 --> 00:53:51,130 of WebAssembly, any interesting story to share about WebAssembly? 919 00:53:51,733 --> 00:53:53,103 guess I really wanted. 920 00:53:53,768 --> 00:53:55,518 I wanted to build the company around WebAssembly. 921 00:53:55,518 --> 00:53:59,568 I wanted WebAssembly to take off, particularly like server side, 922 00:53:59,568 --> 00:54:03,698 client side, that kind of having isomorphic client side server 923 00:54:03,698 --> 00:54:05,628 side code would be a big thing. 924 00:54:05,858 --> 00:54:10,188 And I've, I guess, just generally soured on WebAssembly a little bit. 925 00:54:10,330 --> 00:54:14,540 I think that it where I've seen it work really well is when it's 926 00:54:14,750 --> 00:54:17,760 in the application layer and you kind of have an application. 927 00:54:18,160 --> 00:54:21,810 there's a couple examples I like to go to that are like effectively the same model. 928 00:54:21,893 --> 00:54:24,186 the same kind of architecture, Figma. 929 00:54:24,186 --> 00:54:27,976 There's a company called Modify a few others that I'm, I'm blanking on, but the 930 00:54:28,066 --> 00:54:36,783 architecture is essentially a JavaScript UI, with a, webAssembly, WebGL, WebGPU 931 00:54:36,823 --> 00:54:41,386 kind of rendered canvas, behind it, so like Figma, you know, the core engine 932 00:54:41,386 --> 00:54:46,030 is, I believe, in C, talking to WebGL, with Modify, it's in Rust and WebGPU, 933 00:54:47,586 --> 00:54:52,536 but it's literally like, The application is layered that way that on screen, 934 00:54:52,586 --> 00:54:55,125 there is the canvas behind the UI. 935 00:54:55,125 --> 00:54:57,833 They're written in two different languages and they just talk to each other. 936 00:54:58,170 --> 00:55:01,883 so I think that is the most promising architecture that I see for WebAssembly, 937 00:55:02,426 --> 00:55:05,306 where I think it's been harder. 938 00:55:05,531 --> 00:55:09,981 To get right is building something like a library that is ultimately consumed 939 00:55:09,991 --> 00:55:15,071 by JavaScript developers, but written in WebAssembly, I think there's just so much 940 00:55:15,071 --> 00:55:19,641 friction still in the bundling that, I've kind of soured on that as an approach. 941 00:55:19,915 --> 00:55:20,295 Right. 942 00:55:20,455 --> 00:55:25,335 I mean, I agree in that regard that I wish there was already, we'd be further 943 00:55:25,345 --> 00:55:30,615 along with WebAssembly, but I think it's a bit of a chicken egg problem that 944 00:55:30,615 --> 00:55:33,135 we need more inspiring applications. 945 00:55:33,475 --> 00:55:36,705 That makes people feel like, wow, that is possible. 946 00:55:36,818 --> 00:55:38,838 I didn't recognize that this was the web. 947 00:55:39,162 --> 00:55:40,391 it feels so fast. 948 00:55:40,391 --> 00:55:45,031 And I think that is still true and, more true than, than ever 949 00:55:45,051 --> 00:55:46,688 that WebAssembly, I think. 950 00:55:46,803 --> 00:55:48,993 Can unlock whole new experiences. 951 00:55:49,013 --> 00:55:53,293 And there is a few Lighthouse examples like Figma that stand out here. 952 00:55:53,303 --> 00:55:58,546 Also a big shout out, to the folks building Makepad, which is 953 00:55:58,596 --> 00:56:03,416 a super ambitious project, which is, basically the same way as like. 954 00:56:03,710 --> 00:56:07,530 I'm probably going to do it, I don't do it justice by pitching it, but, 955 00:56:07,886 --> 00:56:12,536 I just want to speak to the ambition where it's basically like Unreal Engine 956 00:56:12,546 --> 00:56:14,586 is sort of like it's full engine. 957 00:56:14,596 --> 00:56:20,260 They, they're building their own platform and including, like a, a rendering layer 958 00:56:20,520 --> 00:56:26,430 and, sort of like as a few people think about, think that MakePad is an editor. 959 00:56:26,700 --> 00:56:29,750 No, MakePad has just as an example app. 960 00:56:30,090 --> 00:56:34,510 Build an editor in which they build make pad, which is just so phenomenal. 961 00:56:34,790 --> 00:56:38,993 So, and make pad is just such an incredibly fast app. 962 00:56:38,993 --> 00:56:41,373 So you should definitely check it out, go to make pad. 963 00:56:41,553 --> 00:56:47,356 dev and then press the option key, to see like how the entire code editor expands. 964 00:56:47,356 --> 00:56:51,296 So apps like that get me very excited about what's possible with 965 00:56:51,296 --> 00:56:54,896 WASM, but, they're fully, they're building everything in Rust. 966 00:56:54,896 --> 00:56:57,430 They're fully leaning into everything, there. 967 00:56:57,480 --> 00:57:02,043 And I think the either or, where you want to like, combined one step at a time. 968 00:57:02,053 --> 00:57:07,013 I think that's a. Tooling problem, partially it's also a trade off 969 00:57:07,033 --> 00:57:12,173 problem where if you move a lot of data back and forth between WASM and 970 00:57:12,173 --> 00:57:14,383 JavaScript, that doesn't come for free. 971 00:57:14,783 --> 00:57:17,566 So I think, you got to keep that in mind. 972 00:57:17,846 --> 00:57:22,226 I've seen a few, I think the, the RepliCache folks actually in the past have 973 00:57:22,226 --> 00:57:26,796 written a lot of their stuff in Rust and then moved to JavaScript because of that 974 00:57:27,136 --> 00:57:29,573 boundary crossing being, too expensive. 975 00:57:30,248 --> 00:57:35,851 But, I think not every use case suffers from that problem, but, I want to turn 976 00:57:35,851 --> 00:57:42,558 it around and, invite anyone who is excited about WebAssembly as, seeing 977 00:57:42,558 --> 00:57:46,858 that as an opportunity to make things significantly better, like working 978 00:57:46,858 --> 00:57:52,058 on projects like WasmBindGen or other things, I think the Deno folks are 979 00:57:52,078 --> 00:57:56,766 pushing heavily on that, so I'm seeing this glass half full and I think the 980 00:57:56,776 --> 00:57:58,326 glass is going to get full pretty soon. 981 00:57:58,856 --> 00:58:03,601 Yeah, I think to your point about like, the JavaScript WebAssembly boundary 982 00:58:03,601 --> 00:58:07,871 crossing, and I think that it comes down to just placing that boundary in the right 983 00:58:07,871 --> 00:58:12,898 place when it comes to, applications like the Figma model of sort of JavaScript 984 00:58:12,908 --> 00:58:17,915 front end with, renderer in WebAssembly, make pad is is a great example. 985 00:58:17,915 --> 00:58:20,765 I think of going like all the way in on WebAssembly. 986 00:58:21,125 --> 00:58:22,605 Another one's called Remix. 987 00:58:22,682 --> 00:58:26,052 and I think what's notable about both cases is that to do that 988 00:58:26,052 --> 00:58:30,482 well, they've had to basically be living in the GUI toolkit layer. 989 00:58:30,482 --> 00:58:33,172 Like, they've been writing their own code or adapting a 990 00:58:33,172 --> 00:58:34,242 lot of their own code for it. 991 00:58:34,252 --> 00:58:36,487 So I think that's, Not for the faint of heart. 992 00:58:36,537 --> 00:58:41,183 I think that people who have done it have built amazing software, but what comes 993 00:58:41,183 --> 00:58:45,253 up more often when I talk to people is like they there's a scarcity of rust 994 00:58:45,263 --> 00:58:50,533 developers and they want to optimize the rust developers to working on kind of the 995 00:58:50,533 --> 00:58:56,123 engine component and then be able to hire React developers and Svelte developers and 996 00:58:56,453 --> 00:59:03,108 kind of front end web developers to work on the GUI where it may not be Like, you 997 00:59:03,108 --> 00:59:04,958 know, think about Figma's UI components. 998 00:59:04,958 --> 00:59:07,953 Like they're not super performance sensitive in the way that the canvas is. 999 00:59:08,379 --> 00:59:09,159 Yeah, totally. 1000 00:59:09,189 --> 00:59:14,296 I think it just takes, some bold thinkers and this is not something where you're 1001 00:59:14,296 --> 00:59:18,846 gonna rebuild the world in two weeks, this is really something you gotta, 1002 00:59:19,183 --> 00:59:22,213 put in the five, 10 years possibly. 1003 00:59:22,544 --> 00:59:28,168 to really build something phenomenal, but I think the, rewards are massive and, 1004 00:59:28,231 --> 00:59:32,991 I'm really looking forward to getting kind of alternatives to something like 1005 00:59:33,021 --> 00:59:37,671 React that provide different trade offs and that allow you to build like really, 1006 00:59:37,671 --> 00:59:41,941 really high performance applications and fundamentally React biases towards 1007 00:59:41,951 --> 00:59:47,836 simplicity and biases towards that you can, Prevent, not so experienced 1008 00:59:47,876 --> 00:59:52,756 engineers to, hurt themselves or others and drag the application down. 1009 00:59:53,096 --> 00:59:57,096 But I think there's a different, trade off space as well, where you bias more 1010 00:59:57,096 --> 01:00:00,656 towards performance and you need to know a little bit more what you're doing. 1011 01:00:01,381 --> 01:00:06,951 And particularly now with AI being on the horizon, I think we can rethink 1012 01:00:06,971 --> 01:00:11,381 a lot of trade offs significantly where engineering team sizes, maybe, 1013 01:00:11,624 --> 01:00:15,778 get reduced as well, but that's the topic for another conversation. 1014 01:00:16,093 --> 01:00:21,693 But, related though, in regards to AI, you've recently also launched a new 1015 01:00:21,703 --> 01:00:25,026 project, that is certainly adjacent to AI. 1016 01:00:25,026 --> 01:00:26,356 It's called ForeverVM. 1017 01:00:26,736 --> 01:00:29,576 can you share a little bit more what that is about? 1018 01:00:29,793 --> 01:00:30,072 Yeah. 1019 01:00:30,072 --> 01:00:32,802 So pretty much from the beginning with Jamsocket, one of the ways we've seen 1020 01:00:32,802 --> 01:00:37,782 people use it because we run these sandbox processes on demand is people 1021 01:00:37,782 --> 01:00:39,852 have run LLM generated code in them. 1022 01:00:39,916 --> 01:00:40,166 actually. 1023 01:00:40,691 --> 01:00:42,621 Going back to the beginning, it wasn't even LLM generated. 1024 01:00:42,691 --> 01:00:44,471 This was sort of pre chat GPT. 1025 01:00:44,837 --> 01:00:47,757 it was things like Jupyter notebooks, but over time we see 1026 01:00:47,757 --> 01:00:49,647 more and more LLM generated code. 1027 01:00:50,037 --> 01:00:51,427 and it's, you know, it's good. 1028 01:00:51,447 --> 01:00:54,247 I think we're, we're like competitive with other products for that, but we 1029 01:00:54,407 --> 01:00:58,497 kind of realized, first of all, we're not really positioning the product that way. 1030 01:00:58,731 --> 01:00:59,351 but also. 1031 01:00:59,776 --> 01:01:02,726 We're not building the product necessarily to be like the best 1032 01:01:02,736 --> 01:01:04,286 for that from first principles. 1033 01:01:04,296 --> 01:01:08,436 Like if we were just say, like, I want an LLM to be able to execute code. 1034 01:01:08,706 --> 01:01:10,426 What would that look like from first principles? 1035 01:01:10,426 --> 01:01:13,696 And we kind of thought, well, we don't really care about the session. 1036 01:01:13,696 --> 01:01:17,121 We don't really care about, you know, we want it to From the LLM's point of 1037 01:01:17,121 --> 01:01:19,221 view, feel like it can always run code. 1038 01:01:19,221 --> 01:01:22,981 It doesn't have to start a sandbox and stop a sandbox when it's done to cut 1039 01:01:22,981 --> 01:01:24,171 down on costs and things like that. 1040 01:01:24,171 --> 01:01:29,241 We, we kind of like cut out the rest of it, make that into the abstraction and 1041 01:01:29,241 --> 01:01:32,901 build it, frankly, into something that we can position for those products so 1042 01:01:32,901 --> 01:01:35,941 that we're not confusing people who are like, I thought you did sync engines. 1043 01:01:36,294 --> 01:01:40,164 now you're telling me running AI code and it's like, architecturally, they 1044 01:01:40,164 --> 01:01:43,064 can actually be fairly similar, but, we wanted to build a product around that. 1045 01:01:43,084 --> 01:01:45,582 So We have forever VM, it is. 1046 01:01:46,422 --> 01:01:47,202 Way to think about it. 1047 01:01:47,202 --> 01:01:52,352 It's like an API that runs Python code in a unbounded session. 1048 01:01:52,469 --> 01:01:56,359 so by that, I mean, if you, kind of make an API call and get a machine 1049 01:01:56,369 --> 01:02:02,139 ID, maybe ABC 123, you can run instructions on that machine set a 1050 01:02:02,149 --> 01:02:03,549 equals three or something like that. 1051 01:02:03,974 --> 01:02:07,864 Two years from now, if you kept that machine around, you can query 1052 01:02:07,864 --> 01:02:12,174 the value of a, you know, a plus five, and then you get back a value. 1053 01:02:12,257 --> 01:02:16,611 and the way we're doing that behind the scenes is using, memory snapshotting 1054 01:02:16,661 --> 01:02:18,651 of the underlying Python process. 1055 01:02:19,021 --> 01:02:23,176 So we kind of from the ground up architected the whole system 1056 01:02:23,176 --> 01:02:24,386 around this and it's kind of neat 1057 01:02:24,932 --> 01:02:25,752 fascinating. 1058 01:02:25,752 --> 01:02:25,992 Yeah. 1059 01:02:26,012 --> 01:02:30,712 My mind is also going to other technologies like mentioned Temporal 1060 01:02:30,732 --> 01:02:35,632 before, but there's also really fascinating project called Golem VM, 1061 01:02:35,882 --> 01:02:41,756 which I think is also, Also employing some really interesting tricks, to use WASM 1062 01:02:41,796 --> 01:02:47,426 and knowledge about, the WASM memory to make sort of checkpoints where you can 1063 01:02:47,696 --> 01:02:51,426 restore and resume computation or retry. 1064 01:02:51,846 --> 01:02:56,707 And yeah, I love that, Yeah, we, we get some bolder ideas out there. 1065 01:02:56,997 --> 01:03:02,354 and particularly now when there is the cost of writing code has come 1066 01:03:02,354 --> 01:03:07,447 down so much and, now it's also people write that code who know even 1067 01:03:07,447 --> 01:03:09,207 less about whether it's good or not. 1068 01:03:09,527 --> 01:03:14,842 So we need to put it into boxes that are somewhat blast safe. 1069 01:03:15,086 --> 01:03:18,996 but also long, like durable in a way that doesn't break the bank. 1070 01:03:19,406 --> 01:03:24,456 And I love how that is like an entirely different product, but yet leverages all 1071 01:03:24,456 --> 01:03:28,969 the benefits and all the, foundations that he's built with Jamsocket, or with, 1072 01:03:29,029 --> 01:03:30,892 I guess with Plain for that matter. 1073 01:03:31,182 --> 01:03:32,332 That is very, very cool. 1074 01:03:33,287 --> 01:03:34,057 Yeah, thanks. 1075 01:03:34,074 --> 01:03:38,984 one of the things that's been really cool to see is that if we give an LLM 1076 01:03:39,254 --> 01:03:42,964 the ability to write this code and get responses back very quickly, like kind 1077 01:03:42,964 --> 01:03:48,847 of just treat it as a local-repl, that the AIs can kind of do more like they get 1078 01:03:48,847 --> 01:03:52,837 that fast feedback loop and they can make mistakes and correct them almost faster 1079 01:03:52,837 --> 01:03:56,677 than, and in some cases we've observed them doing this faster than a reasoning 1080 01:03:56,677 --> 01:03:59,367 model could kind of just generate the right code in the first place. 1081 01:03:59,377 --> 01:04:00,167 So that's been pretty neat. 1082 01:04:00,847 --> 01:04:01,377 Nice. 1083 01:04:02,167 --> 01:04:06,117 Any other things that you would like to share with the audience? 1084 01:04:06,387 --> 01:04:11,030 if you want to find me online, I'm, paulgb on Twitter or X and paulbutler. 1085 01:04:11,030 --> 01:04:12,730 org on BlueSky. 1086 01:04:13,307 --> 01:04:13,727 jamsocket. 1087 01:04:13,747 --> 01:04:16,227 com is the site, jamsockethq on Twitter. 1088 01:04:16,627 --> 01:04:18,337 also on BlueSky is jamsocket. 1089 01:04:18,337 --> 01:04:18,727 com. 1090 01:04:19,180 --> 01:04:20,160 and, yeah, forevervm. 1091 01:04:20,430 --> 01:04:22,140 com is the product we were just talking about. 1092 01:04:22,690 --> 01:04:23,130 Perfect. 1093 01:04:23,130 --> 01:04:26,660 We're going to put links to all of those things in the show notes. 1094 01:04:27,100 --> 01:04:29,800 Paul, thank you so much for coming on the show today. 1095 01:04:29,854 --> 01:04:34,634 I've learned a lot about so many different topics and yeah, really enjoyed it. 1096 01:04:34,654 --> 01:04:35,064 Thank you. 1097 01:04:35,964 --> 01:04:36,684 Thank you, Johannes. 1098 01:04:36,684 --> 01:04:39,794 And really looking forward to seeing you at local-first in Berlin this year. 1099 01:04:40,264 --> 01:04:40,664 Perfect. 1100 01:04:40,704 --> 01:04:41,194 See you then. 1101 01:04:41,754 --> 01:04:42,349 See you then. 1102 01:04:42,834 --> 01:04:45,414 Thank you for listening to the localfirst.fm podcast. 1103 01:04:45,594 --> 01:04:48,684 If you've enjoyed this episode and haven't done so already, please 1104 01:04:48,684 --> 01:04:49,974 subscribe and leave a review. 1105 01:04:50,364 --> 01:04:52,884 Please also share this episode with your friends and colleagues. 1106 01:04:53,274 --> 01:04:56,274 Spreading the word about the podcast is a great way to support 1107 01:04:56,274 --> 01:04:57,984 it and to help me keep it going. 1108 01:04:58,644 --> 01:05:02,064 A special thanks again to Jazz for supporting this podcast. 1109 01:05:02,364 --> 01:05:03,324 I'll see you next time.