<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Jeff Lindsay</title>
    <description>The latest articles on Forem by Jeff Lindsay (@progrium).</description>
    <link>https://forem.com/progrium</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F11207%2Ffa43f37a-3d44-40ac-9610-cd9cd1494f16.jpg</url>
      <title>Forem: Jeff Lindsay</title>
      <link>https://forem.com/progrium</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/progrium"/>
    <language>en</language>
    <item>
      <title>Why a static site generator on Apptron is revolutionary</title>
      <dc:creator>Jeff Lindsay</dc:creator>
      <pubDate>Wed, 11 Mar 2026 19:02:21 +0000</pubDate>
      <link>https://forem.com/progrium/why-a-static-site-generator-on-apptron-is-revolutionary-12nk</link>
      <guid>https://forem.com/progrium/why-a-static-site-generator-on-apptron-is-revolutionary-12nk</guid>
      <description>&lt;p&gt;We're building on the &lt;a href="https://dev.to/progrium/zero-effort-offline-static-websites-with-apptron-47m6"&gt;last Apptron demo&lt;/a&gt; by introducing a static site generator to show that workflow. This is also a brief intro to the Taragen site generator we made that we might build into the system, a la Jekyll on GitHub Pages.&lt;/p&gt;

&lt;p&gt;By installing Taragen, though, we can start to see what makes Apptron particularly special. The Taragen we download isn't a Wasm build, it's a Linux executable...&lt;/p&gt;

&lt;p&gt;Check it out:&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/wH0qW29W20Q"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

</description>
      <category>linux</category>
      <category>webdev</category>
      <category>go</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Zero-effort offline static websites with Apptron</title>
      <dc:creator>Jeff Lindsay</dc:creator>
      <pubDate>Tue, 10 Mar 2026 23:20:49 +0000</pubDate>
      <link>https://forem.com/progrium/zero-effort-offline-static-websites-with-apptron-47m6</link>
      <guid>https://forem.com/progrium/zero-effort-offline-static-websites-with-apptron-47m6</guid>
      <description>&lt;p&gt;&lt;a href="https://apptron.dev/" rel="noopener noreferrer"&gt;Apptron&lt;/a&gt; can do many things, but I've never seen a faster way to publish static files to the web than Apptron. You can just copy files to &lt;code&gt;/public&lt;/code&gt; or edit them there directly.&lt;/p&gt;

&lt;p&gt;What's more, it's the only platform that will magically make your site work offline. Time to move my blog off GitHub Pages.&lt;/p&gt;

&lt;p&gt;Take a look:&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/9PTRllJa1KY"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>html</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Apptron 0.7: Offline Sites, Console Embeds, and Much More</title>
      <dc:creator>Jeff Lindsay</dc:creator>
      <pubDate>Tue, 10 Mar 2026 00:28:49 +0000</pubDate>
      <link>https://forem.com/progrium/apptron-07-offline-sites-console-embeds-and-much-more-2a0f</link>
      <guid>https://forem.com/progrium/apptron-07-offline-sites-console-embeds-and-much-more-2a0f</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/tractordev/apptron" rel="noopener noreferrer"&gt;Apptron&lt;/a&gt; has become the center of all my projects. It's where everything is being put together and is itself a new kind of software platform. If you haven't been following closely, you may have missed it. So below are the release notes of our latest release.&lt;/p&gt;




&lt;p&gt;This is our biggest release yet! Lots of fixes and UX improvements, but also lots of new little features here and there. For example, the &lt;code&gt;/web/dl&lt;/code&gt; mount is a new write-only filesystem that will cause files written to it to be downloaded by the browser. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffuwze9gyk2lonb1imkuo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffuwze9gyk2lonb1imkuo.gif" alt="clip2" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's also now an &lt;code&gt;open&lt;/code&gt; command that will let you edit files that aren't in &lt;code&gt;/project&lt;/code&gt;, which is what the file explorer shows by default. If you use &lt;code&gt;open&lt;/code&gt; on a directory, it will add it as a new root in the explorer. &lt;/p&gt;

&lt;p&gt;Lots more if you read the full changelog below, but first are some details on the major improvements in this release.&lt;/p&gt;

&lt;h2&gt;
  
  
  Console Mode Embeds
&lt;/h2&gt;

&lt;p&gt;Embedding your environment on other pages with the embed snippet code previously just meant you could embed more or less the exact editor UX of visiting the environment directly. Now you can choose if you want "Editor Mode" or "Console Mode" for your embed. &lt;/p&gt;

&lt;p&gt;Editor Mode is the same as before, giving you the default editor experience (though now without the Apptron topbar). Console Mode gives you just the terminal, making it really easy to create interactive playgrounds for CLI programs, or just run arbitrary Wasm/Linux on any web page.&lt;/p&gt;

&lt;p&gt;Like before, you can put a &lt;code&gt;.apptron/envrc&lt;/code&gt; file in your project (which can now also be &lt;code&gt;.envrc&lt;/code&gt; in your project), allowing you to hook into right before you get a prompt. You can use it to run commands to customize the shell at startup like a project-level &lt;code&gt;.profile&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;You'd still get the "Welcome to Apptron" banner text with information about your session before &lt;code&gt;.envrc&lt;/code&gt; is run. But now you can customize this by creating a &lt;code&gt;.banner&lt;/code&gt; or &lt;code&gt;.apptron/banner&lt;/code&gt; file, which will run &lt;em&gt;instead&lt;/em&gt; of the default banner. For example, creating an empty file will cause no banner to be shown. &lt;/p&gt;

&lt;p&gt;This all gives you full control over how the terminal session looks and is set up. You can even run different code in different contexts. For example, there is an environment variable &lt;code&gt;ENV_MODE&lt;/code&gt; that is either &lt;code&gt;edit&lt;/code&gt; or &lt;code&gt;console&lt;/code&gt;. When loaded as an embed, there will be a variable set called &lt;code&gt;ENV_EMBED&lt;/code&gt;.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Offline Public Sites
&lt;/h2&gt;

&lt;p&gt;Apptron environments give you one of the fastest ways to publish a static site by just changing what's in the &lt;code&gt;/public&lt;/code&gt; mount. Now by default, those static sites will work offline after visiting with no extra effort. &lt;/p&gt;

&lt;p&gt;If you have a &lt;code&gt;/public/index.html&lt;/code&gt;, we inject JavaScript to install a dynamic service worker that starts to cache all assets in &lt;code&gt;/public&lt;/code&gt; in the background. Now after visiting the homepage, the entire site will then still be accessible and load when you are offline. &lt;/p&gt;

&lt;p&gt;This is really cool and I've not seen any other platform do this, despite it being pretty low hanging fruit. Caching is always tricky,  though, and the default refresh-ahead strategy used at the moment means you'll have to reload a page twice to see changes. Please try this feature to help us work these sorts of issues out. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.youtube.com/watch?v=9PTRllJa1KY" rel="noopener noreferrer"&gt;Check out the demo video&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Improvements
&lt;/h2&gt;

&lt;p&gt;It is an ongoing effort to maximize what we can get out of the embedded-like performance and memory constraints of Wasm and the browser. Two big improvements in this release, though both with plenty of room for further improvement, apply to network speed and environment building. &lt;/p&gt;

&lt;p&gt;We upgraded our deployment's network gateway on Cloudflare Containers to the current max available of &lt;code&gt;standard-4&lt;/code&gt; and that gave us a 4x improvement in throughput. This mostly means downloading files and installing packages will be faster.&lt;/p&gt;

&lt;p&gt;We also finally integrated our copy-on-write filesystem so that changes to an environment via &lt;code&gt;envbuild&lt;/code&gt; are layered on top of the base system with every session. This was to make sure those environments got updates to the base system, but also turns out to make larger builds finish up to twice as fast. &lt;/p&gt;

&lt;h2&gt;
  
  
  Changelog
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Additions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;add new project welcome readme (#221)&lt;/li&gt;
&lt;li&gt;add default service worker to cache public site assets for offline&lt;/li&gt;
&lt;li&gt;add custom 404 support to public sites&lt;/li&gt;
&lt;li&gt;add Embed Mode option to get new &lt;code&gt;console&lt;/code&gt; embed&lt;/li&gt;
&lt;li&gt;add &lt;code&gt;open&lt;/code&gt; command for non-project files (#230)&lt;/li&gt;
&lt;li&gt;add support for &lt;code&gt;.apptron&lt;/code&gt; files as dotfiles in project root&lt;/li&gt;
&lt;li&gt;add &lt;code&gt;.apptron/banner&lt;/code&gt; or &lt;code&gt;.banner&lt;/code&gt; to customize shell banner&lt;/li&gt;
&lt;li&gt;add support for &lt;code&gt;?topbar=0&lt;/code&gt; to hide topbar&lt;/li&gt;
&lt;li&gt;add sponsor dialog from account dropdown (#247, #225)&lt;/li&gt;
&lt;li&gt;add feedback form dialog from topbar (#247, #224)&lt;/li&gt;
&lt;li&gt;add bundle caching that clears on login (#163)&lt;/li&gt;
&lt;li&gt;add publish helper command (#227)&lt;/li&gt;
&lt;li&gt;add loopback network device&lt;/li&gt;
&lt;li&gt;add &lt;code&gt;/web/dl&lt;/code&gt; filesystem for triggering downloads&lt;/li&gt;
&lt;li&gt;add &lt;code&gt;ENV_MODE&lt;/code&gt; environment variable (edit or console)&lt;/li&gt;
&lt;li&gt;add kernel modules for audio support in vm&lt;/li&gt;
&lt;li&gt;add confirmation dialog on project delete (#262, #267)&lt;/li&gt;
&lt;li&gt;add toast notification on project delete (#238)&lt;/li&gt;
&lt;li&gt;add loading indicators to buttons (#244, #203, #234, #202)&lt;/li&gt;
&lt;li&gt;add help text in publish tab of share dialog (#195, #249)&lt;/li&gt;
&lt;li&gt;add improved copy button in share dialog (#242)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Changes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;use copy-on-write for custom environments (#217) (2x envbuild speedup, cuts seconds from pageload)&lt;/li&gt;
&lt;li&gt;improve network throughput (#159) (4x speedup)&lt;/li&gt;
&lt;li&gt;change starting directory to /project&lt;/li&gt;
&lt;li&gt;refactor share dialog architecture (#245, #222)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Bugfixes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;fix project file truncation/corruption (#232, #157)&lt;/li&gt;
&lt;li&gt;fix first-time publish failure (#231)&lt;/li&gt;
&lt;li&gt;fix inability to publish project root (#244, #233)&lt;/li&gt;
&lt;li&gt;fix broken markdown preview (#229)&lt;/li&gt;
&lt;li&gt;fix offscreen login component in smaller windows (#269, #268)&lt;/li&gt;
&lt;li&gt;fix broken UI in share dialog (#266)&lt;/li&gt;
&lt;li&gt;fix broken dropdown dismissal behavior (#240, #214)&lt;/li&gt;
&lt;li&gt;fix broken apptron logo link (#228)&lt;/li&gt;
&lt;li&gt;fix short project name limit (#208)&lt;/li&gt;
&lt;li&gt;fix login failure when session expires (#210, #243)&lt;/li&gt;
&lt;li&gt;fix broken state after changing project settings (#167)&lt;/li&gt;
&lt;li&gt;fix dangerous username change in account dialog (#239, #246)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Full Changelog&lt;/strong&gt;: &lt;a href="https://github.com/tractordev/apptron/compare/v0.6.0...v0.7.0" rel="noopener noreferrer"&gt;https://github.com/tractordev/apptron/compare/v0.6.0...v0.7.0&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;As usual, we'd love you to try it out and file issues you run into. A huge thanks to our &lt;a href="https://github.com/sponsors/progrium" rel="noopener noreferrer"&gt;GitHub Sponsors&lt;/a&gt; who are now our only source of funding. Consider sponsoring to make sure we can sustainably see these projects all the way through and get that "Megazord" moment that's been 6 years in the making...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7boc6qwjn2pdfp6ox7z.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7boc6qwjn2pdfp6ox7z.gif" alt="power-rangers-dino-thunder-power-rangers" width="374" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>go</category>
      <category>vscode</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Turning VS Code into a Product Framework</title>
      <dc:creator>Jeff Lindsay</dc:creator>
      <pubDate>Mon, 28 Jul 2025 18:33:43 +0000</pubDate>
      <link>https://forem.com/progrium/turning-vs-code-into-a-product-framework-28hg</link>
      <guid>https://forem.com/progrium/turning-vs-code-into-a-product-framework-28hg</guid>
      <description>&lt;p&gt;Visual Studio Code is no longer just a developer tool. It’s now a highly malleable and embeddable product platform. Looking at it beyond a code editor, it's actually a general-purpose application shell with a familiar UI, plugin system, command framework, and cross-platform runtime. Recently it's been used as the platform for several major AI products, but more quietly it's also been used for much more, from cloud IDEs to domain-specific editors and internal dev tools.&lt;/p&gt;

&lt;p&gt;In this series of posts, I’ll show how I’ve been turning VS Code into a reusable module; something you can embed, extend, and ship as part of your own product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why VS Code as a Platform?
&lt;/h2&gt;

&lt;p&gt;I never thought the developer ecosystem would embrace a single editor as much as it has VS Code. Its dominance as a general-purpose coding environment is undeniable. This popularity and familiarity is one reason to build on it, but there are other attributes that make it a solid building block:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Generalized Design:&lt;/strong&gt; It was designed not just as an editor, but as an integrated environment for various tools involved in the development workflow and beyond.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Highly Extensible:&lt;/strong&gt; Its extension API allows for deep customization, from minor modifications to total transformations, even into non-code oriented tooling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MIT License:&lt;/strong&gt; The permissive MIT license means you can freely adapt and distribute it, provided you don't call it VS Code. The open source project is officially called "Code - OSS"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Given its intended purpose is for software development, you might think this limits it to being a framework for devtools and code adjacent domains. Really, though, you can disable and rip all of that out and still have a great shell for applications that use the same general shape of its user interface. It might not be a fit for all products, but any application built around tabbed views, user-customizable sidebars, and is advanced enough to need a command palette would be a good candidate.&lt;/p&gt;

&lt;p&gt;Even then, having integrated code editing abilities might be more of a benefit for non-development applications than you might think. Any professional knowledge tool these days needs some level of integration and extensibility. Imagine giving power users the ability to build these in-app. An embedded VS Code could just be used for this mode of your application. Imagine a game that comes with its own modding environment. Development environments are incredibly intricate systems to build, so having the most familiar of them that you can embed in your application is a huge win.  &lt;/p&gt;

&lt;p&gt;However, there is another argument that some kind of development environment might be worth including in your application, if not building on top of one directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Embracing the Future of AI Agents
&lt;/h2&gt;

&lt;p&gt;Rather obnoxiously, AI is everywhere. For the foreseeable future, we are going to be working with more and more AI. But also for the foreseeable future, &lt;strong&gt;code will remain significantly cheaper to run than AI&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Luckily, AI is pretty good at writing code. To me, this points to an eventuality where most AI agents will be automating with code rather than direct control. This is great for a lot of reasons, which I can get into another time if people are interested. For now I just want to point out that any application or system that involves agentic AI will likely need a development environment and editor as a sort of "admin backend" for a behind-the-scenes code generating agent. &lt;/p&gt;

&lt;p&gt;As of right now, the leading AI co-development environment, regardless of model or coding agent technology, is VS Code. So if you're interested in building agentic AI products or involving code generating agentic AI in your product, it might be worth thinking about how you can embed an environment like VS Code in your product. &lt;/p&gt;

&lt;h2&gt;
  
  
  Maybe Avoid Forking VS Code
&lt;/h2&gt;

&lt;p&gt;Let's say you're in on using the VS Code open source project in your product. Your first thought might be to fork it, essentially adopting it wholesale. After all, that's what Cursor and Windsurf did! Well here are some quick stats that might be good to know about the VS Code project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Massive Codebase:&lt;/strong&gt; Currently it contains 1.3 million lines of TypeScript. This is comparable to the codebase of Grand Theft Auto III.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensive Dependencies:&lt;/strong&gt; Right now I count over 900 dependencies, which is a lot even for your average already-too-many-dependencies Node.js project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bloated Project Size:&lt;/strong&gt; After a full &lt;code&gt;npm install&lt;/code&gt;, the project directory expands to a hefty 2.6GB. Not sure what all of that is, but almost 1 gig of that is &lt;code&gt;node_modules&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is what you'd be inheriting and you haven't even started your application. On a high-end machine like my M3 Max, it takes around 30 minutes just to build the frontend. It takes 50 minutes on GitHub Actions. Why? I don't know, but maybe this is partly why they're porting the TypeScript compiler to Go.&lt;/p&gt;

&lt;p&gt;Maybe you're just one person, like me, and this already seems overwhelming. Even for a small team, such a large and complex codebase and all those dependencies is rather prohibitive. Or maybe your team isn't interested in working with TypeScript, let alone 1.3 million lines of it. Or maybe, like me, you'd like to avoid Node.js and all those dependencies like the plague. &lt;/p&gt;

&lt;p&gt;So is it already game over or is there an alternative approach? Well, since I'm also on this path as one developer with just a handful of GitHub sponsors funding this work, I had to find one. Because building an alternative to VS Code from scratch is also not an option for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Towards Another Approach
&lt;/h2&gt;

&lt;p&gt;Thanks to VS Code's extensibility, there's a good chance the majority of what we'd want to change or add, we could do through extensions. This means changes to the codebase could at least be minimized to a few patches, making a full fork potentially unnecessary. We'd still need a build of VS Code we can configure and ideally embed in our application. It turns out there is a little known official option for this, but I'll have to explain some background on how it works.&lt;/p&gt;

&lt;p&gt;VS Code is an &lt;a href="https://www.electronjs.org/" rel="noopener noreferrer"&gt;Electron&lt;/a&gt; app, which means it's mostly a web frontend that runs inside a webview in a native window. That's essentially a browser window without the chrome that just runs VS Code. What can't run in the webview is run in Node.js outside the webview. Electron provides a framework for this with cross-platform APIs to common native functionality like webview windows, menus, etc. The webview frontend talks to the Node.js backend via RPC and that's generally how most Electron apps work.&lt;/p&gt;

&lt;p&gt;For VS Code, what runs outside the webview are subsystems for filesystem and shell access, the ability to run subprocesses for language servers, and extensions themselves that are typically run in a separate Node.js process. This will come up later.&lt;/p&gt;

&lt;p&gt;Despite being made to allow an app to be built with web technologies, most Electron apps become quite coupled to Electron and Node.js. When people started building cloud IDEs where Electron didn't make sense and you could just view the frontend in your browser, they couldn't use VS Code because of this coupling. Eventually, thanks to projects like &lt;a href="https://github.com/gitpod-io/openvscode-server" rel="noopener noreferrer"&gt;openvscode-server&lt;/a&gt;, which patched VS Code to run as a normal web app in a Docker container, VS Code took many of these changes upstream and began to decouple VS Code from Electron.&lt;/p&gt;

&lt;h2&gt;
  
  
  VS Code for the Web
&lt;/h2&gt;

&lt;p&gt;This decoupling led to &lt;a href="https://code.visualstudio.com/docs/setup/vscode-web" rel="noopener noreferrer"&gt;VS Code for the Web&lt;/a&gt;, a build target of VS Code that can run almost entirely in a webview or browser without the Node.js backend. Where openvscode-server decoupled it from Electron, VS Code for the Web even decoupled it from its own Node.js backend. In other words, it's a build of the VS Code editor that's just static files you can serve with any HTTP server.&lt;/p&gt;

&lt;p&gt;When compressed into a zip file, &lt;strong&gt;the result is an 18MB artifact that could be deployed or embedded anywhere&lt;/strong&gt;. In fact, there is a public deployment of VS Code for the Web at &lt;a href="https://vscode.dev/" rel="noopener noreferrer"&gt;vscode.dev&lt;/a&gt;, and even a semi-secret version deployed for GitHub. While logged in to GitHub, if you hit period (.) while on any repository, you're taken to that repository opened in an instance of VS Code for the Web. This is different from a GitHub Codespace, which runs a full backend and development environment in the cloud, similar to what you can do with openvscode-server. The reason it's different gets at the core limitations of VS Code for the Web:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No shell or direct filesystem access&lt;/li&gt;
&lt;li&gt;No extensions that use Node.js APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It might be obvious but they both have to do with not having the Node.js backend. One of the major changes they made to support this build target was to make an extension host that runs in-browser using web workers, so extensions can only do what can be done in a browser web worker. Luckily, most of the core extensions have been ported to work in web workers. &lt;/p&gt;

&lt;p&gt;Unfortunately, most third-party extensions are likely to use at least one Node.js module or NPM package. This hurts most for language extensions that typically use Node.js to run an LSP server subprocess. So if you need to support specific third-party extensions, you'll have to fork them and find a way to make them work. Better than forking all of VS Code?&lt;/p&gt;

&lt;p&gt;The lack of shell and filesystem are pretty easy to fix because both can be provided by extensions. We can just have a kind of "system extension" that gets a filesystem and shell over WebSocket.&lt;/p&gt;

&lt;h2&gt;
  
  
  Embed and Extend
&lt;/h2&gt;

&lt;p&gt;With VS Code for the Web we get an 18MB editor "module" in a single file that we can embed in our apps and then extend with extensions. While it comes with some limitations, I believe it opens up even more possibilities. We could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;serve it from any CDN or static host for the cloud. &lt;/li&gt;
&lt;li&gt;use it on the desktop through any webview wrapper like Electron, Tauri, etc. &lt;/li&gt;
&lt;li&gt;serve it in an application of any language to access via the browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It becomes trivial enough to embed as a built-in editor for whatever application you're building. And it's extensible and malleable enough to become any number of different non-code editors, like a DAW for audio, or a CAD tool, or a game engine editor.&lt;/p&gt;

&lt;p&gt;In the following posts for this series, we'll build a cross-platform desktop code editor in Go using this approach. Effectively a clone of VS Code that you can use as a foundation for your own application, without all the baggage of building directly on a fork of the VS Code project.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>vscode</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The Spirit of Plan 9 on the Web</title>
      <dc:creator>Jeff Lindsay</dc:creator>
      <pubDate>Tue, 06 May 2025 18:11:33 +0000</pubDate>
      <link>https://forem.com/progrium/the-spirit-of-plan-9-on-the-web-5g7k</link>
      <guid>https://forem.com/progrium/the-spirit-of-plan-9-on-the-web-5g7k</guid>
      <description>&lt;p&gt;If you go back to the &lt;a href="https://www.slideshare.net/slideshow/web-hooks/263894" rel="noopener noreferrer"&gt;first talk ever given on webhooks&lt;/a&gt;, it opens on the command-line. Specifically the Unix shell, focusing on one of its defining features: pipes. The idea was that pipes brought a new level of compositionality to programs, and webhooks could bring a new level of compositionality to web apps. Perhaps you could say I was trying to bring the spirit of Unix to the web.&lt;/p&gt;

&lt;p&gt;With this &lt;a href="https://github.com/tractordev/wanix/releases/tag/v0.3-preview" rel="noopener noreferrer"&gt;last release of Wanix&lt;/a&gt;, I'm at it again. This time with the successor to Unix, a little known operating system called &lt;a href="https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs" rel="noopener noreferrer"&gt;Plan 9 from Bell Labs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Plan 9 has been on my mind for quite a while. In fact, around the time of that first talk on webhooks, the team behind Unix and Plan 9 was being re-assembled to create the Go programming language. I pretty instantly fell in love with the Go worldview, which turns out to be an outgrowth of the Unix and Plan 9 values of simplicity, pragmatism, economy, and ultimately compositionality.&lt;/p&gt;

&lt;p&gt;Like Unix, the Plan 9 environment is really made for programmers and system operators. I'll leave a deeper explanation of what makes Plan 9 great for another post, but I do get into it a bit in the demo video for Wanix:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/kGBeT8lwbo0"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;While I wanted to incorporate Plan 9 ideas into Wanix from the beginning, it wasn't until we rebuilt it from scratch with that intention that the magic really starts to come through. That's what this preview release is about.&lt;/p&gt;

&lt;p&gt;Wanix is a whole new beast now. It's no longer a singular computing environment that runs in the browser. It's now a primitive for building environments in general. The demo shows a shell environment, but this environment is not the point. It's just a way to bootstrap Wanix so you can use and explore it interactively.&lt;/p&gt;

&lt;p&gt;The point of this preview release is to get this primitive out there. I have my uses for Wanix, and I plan to share them with the final 0.3 release, but until then I wanted to let it all percolate. Maybe inspire people to get creative with their own use cases. &lt;/p&gt;

&lt;p&gt;Here's a quick rundown of Wanix features in this release:&lt;/p&gt;

&lt;h4&gt;
  
  
  Plan 9 inspired design
&lt;/h4&gt;

&lt;p&gt;With the original intention to enable exploring Plan 9 ideas on modern platforms, we've ended up with a radically simple architecture around per-process namespaces composed of file service capabilities using similar design patterns to those found in Plan 9.&lt;/p&gt;

&lt;h4&gt;
  
  
  Single executable toolchain
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;wanix&lt;/code&gt; executable includes everything needed to produce Wanix environments.&lt;/p&gt;

&lt;h4&gt;
  
  
  Filesystem is the only API
&lt;/h4&gt;

&lt;p&gt;The Wanix microkernel is now simply a VFS module with several built-in file services exposed via a standard filesystem API. This ends up making the module itself a file service.&lt;/p&gt;

&lt;h4&gt;
  
  
  Built-in Linux shell
&lt;/h4&gt;

&lt;p&gt;Using the built-in file service primitives, Wanix can bootstrap a Linux-compatible shell based on Busybox. It comes with several helper commands for working with built-in file services.&lt;/p&gt;

&lt;h4&gt;
  
  
  Tasks and namespaces
&lt;/h4&gt;

&lt;p&gt;The Wanix unit of compute is a task, which is equivalent and compatible with POSIX processes but allows for different execution strategies. Each task has its own "namespace," which is the customizable filesystem exposed to the task.&lt;/p&gt;

&lt;h4&gt;
  
  
  Core file services
&lt;/h4&gt;

&lt;p&gt;Wanix includes two singleton file services: one to manage tasks (similar to procfs), and one to manage "capabilities" which are user allocated file services. Built-in capabilities include: tarfs, tmpfs, and loopback.&lt;/p&gt;

&lt;h4&gt;
  
  
  Web file services
&lt;/h4&gt;

&lt;p&gt;With future non-browser deployments in mind, all web related file services are packaged in a web module, which is also built-in but not considered core. This module includes these work-in-progress file services:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;strong&gt;opfs&lt;/strong&gt;: For working with the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/File_System_API/Origin_private_file_system" rel="noopener noreferrer"&gt;OPFS&lt;/a&gt; browser storage API&lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;dom&lt;/strong&gt;: For inspecting and manipulating the DOM&lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;worker&lt;/strong&gt;: For managing &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API" rel="noopener noreferrer"&gt;web workers&lt;/a&gt;
&lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;pickerfs&lt;/strong&gt;: Capability wrapping the &lt;code&gt;window.showDirectoryPicker()&lt;/code&gt; method (not available yet in Safari and Firefox)&lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;ws&lt;/strong&gt;: Capability for working with WebSocket connections&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;sw&lt;/strong&gt;: For configuring the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API" rel="noopener noreferrer"&gt;service worker&lt;/a&gt;, which is used by the system now to cache all resources needed to run Wanix allowing offline usage, as well as exposing virtual URLs to the root namespace.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Go programmers might also appreciate the filesystem toolkit we've been working on since before Wanix. It builds on the &lt;code&gt;fs.FS&lt;/code&gt; abstraction in the standard library and gives you DSL-like utilities for defining virtual filesystems like the file services in Wanix. More on that in a dedicated post as well. &lt;/p&gt;

&lt;p&gt;So far, the feedback has been really positive. I appreciate everybody taking the time to process it. There's still lots to do. Wanix is itself its own universe, but it's just one layer of the Tractor project. After a little vacation I'll be back to continue work on both fronts. As usual, I'd love help.&lt;/p&gt;

&lt;p&gt;Speaking of help, shout-out to &lt;a href="https://joel.franusic.com/" rel="noopener noreferrer"&gt;Joël Franusic&lt;/a&gt; for the help and support. And as usual, big thanks to my &lt;a href="https://github.com/sponsors/progrium" rel="noopener noreferrer"&gt;GitHub sponsors&lt;/a&gt; for making this possible.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>webdev</category>
      <category>devops</category>
      <category>go</category>
    </item>
    <item>
      <title>How I build simple Mac apps using Go</title>
      <dc:creator>Jeff Lindsay</dc:creator>
      <pubDate>Mon, 15 Jul 2024 20:41:57 +0000</pubDate>
      <link>https://forem.com/progrium/how-i-build-simple-mac-apps-using-go-104j</link>
      <guid>https://forem.com/progrium/how-i-build-simple-mac-apps-using-go-104j</guid>
      <description>&lt;p&gt;I started &lt;a href="https://github.com/progrium/darwinkit" rel="noopener noreferrer"&gt;DarwinKit&lt;/a&gt; a few years ago because there were no bindings to native Mac APIs for Go. We've slowly turned the project into bindings and generation tooling to someday reach full coverage of all Apple APIs. The &lt;a href="https://github.com/progrium/darwinkit/releases/tag/v0.5.0" rel="noopener noreferrer"&gt;release of v0.5.0 last week&lt;/a&gt; is the largest the project has seen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bindings for &lt;a href="https://pkg.go.dev/github.com/progrium/darwinkit/macos@main#section-directories" rel="noopener noreferrer"&gt;33 frameworks&lt;/a&gt; with near complete coverage:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;2,353&lt;/strong&gt; classes &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;23,822&lt;/strong&gt; methods and properties&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;9,519&lt;/strong&gt; constants/enums&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;543&lt;/strong&gt; structs&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Automatic conversion and use of native Go builtin types in APIs&lt;/li&gt;

&lt;li&gt;Support for block arguments as Go functions with properly typed arguments&lt;/li&gt;

&lt;li&gt;Pre-made delegate implementations you can simply set Go functions on&lt;/li&gt;

&lt;li&gt;1-to-1 mapping to Objective-C symbols while still idiomatic to Go&lt;/li&gt;

&lt;li&gt;Documentation for all symbols including a link to official Apple docs on that symbol&lt;/li&gt;

&lt;li&gt;Growing collection of &lt;a href="https://github.com/sponsors/darwinkitdev" rel="noopener noreferrer"&gt;high-quality example starter apps&lt;/a&gt; for sponsors&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc36egye1ccifj4fsaber.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc36egye1ccifj4fsaber.png" alt="Demo Screenshots"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a quick example using DarwinKit to build a native webview window application in a few lines of Go:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/progrium/darwinkit/objc"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/progrium/darwinkit/macos"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/progrium/darwinkit/macos/appkit"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/progrium/darwinkit/macos/foundation"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/progrium/darwinkit/macos/webkit"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// runs macOS application event loop with a callback on success&lt;/span&gt;
    &lt;span class="n"&gt;macos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="n"&gt;appkit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delegate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;appkit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ApplicationDelegate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetActivationPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;appkit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ApplicationActivationPolicyRegular&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ActivateIgnoringOtherApps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;foundation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;URL_URLWithString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://github.com/sponsors/darwinkitdev"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;foundation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewURLRequestWithURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;frame&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;foundation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rect&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;foundation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Size&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;1440&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;900&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;

        &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;webkit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewWebViewConfiguration&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;wv&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;webkit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewWebViewWithFrameConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;wv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoadRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;appkit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewWindowWithContentRectStyleMaskBackingDefer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;appkit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClosableWindowMask&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;appkit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TitledWindowMask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;appkit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BackingStoreBuffered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;objc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Retain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetContentView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MakeKeyAndOrderFront&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;delegate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetApplicationShouldTerminateAfterLastWindowClosed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;appkit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In less than 40 lines we made a native Mac app without opening XCode or using Objective-C. I think this might now be the best bindings project in existence for Apple APIs. Possibly even the best way to make small utilities on the Mac. And soon even other Apple devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future
&lt;/h2&gt;

&lt;p&gt;There is one big missing piece to DarwinKit: there are no bindings to Apple framework &lt;em&gt;functions&lt;/em&gt;. Luckily, most frameworks are built with OOP, which we have great bindings for now. But some frameworks, especially lower-level frameworks, are mostly functions. While there is a workaround that involves using CGO (which DarwinKit is trying to help you avoid), we're working on generating native Go function bindings for every framework function. &lt;/p&gt;

&lt;p&gt;The other big thing we're working towards is making DarwinKit not use CGO at all! Using &lt;a href="https://github.com/ebitengine/purego" rel="noopener noreferrer"&gt;purego&lt;/a&gt;, we can call into Apple frameworks without involving CGO. This will improve build time, make smaller binaries, and allow DarwinKit to be used in programs that need to avoid CGO for whatever reason.&lt;/p&gt;

&lt;p&gt;For iOS and mobile devs out there, I really want to get this working for iOS. In fact, it already should! But we generate bindings for MacOS for now. If anybody wants to help bring this to iOS to let people make Apple mobile apps with Go, please reach out!&lt;/p&gt;

&lt;p&gt;Until then, try building an app with what we've got so far. Let me know how it goes! &lt;/p&gt;

</description>
      <category>go</category>
      <category>showdev</category>
      <category>mac</category>
      <category>ios</category>
    </item>
    <item>
      <title>Treehouse 0.3.0: Fields, Live Search, and References</title>
      <dc:creator>Jeff Lindsay</dc:creator>
      <pubDate>Thu, 18 May 2023 19:03:29 +0000</pubDate>
      <link>https://forem.com/progrium/treehouse-030-fields-live-search-and-references-5gjd</link>
      <guid>https://forem.com/progrium/treehouse-030-fields-live-search-and-references-5gjd</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/PjWibMkKBOE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  New Node Types: Fields, Live Search, and References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/treehousedev/treehouse/releases/tag/0.3.0" rel="noopener noreferrer"&gt;This release&lt;/a&gt; we added some exciting new features: Fields, Live Search, and References. These new node types represent our first step into becoming much more than a simple outliner. Quality of live improvements include making the node menu easier to click, initial work towards a mobile view, and improving interactivity of the command palette. We also cleaned up all our UI elements to match our design system, allowing for better custom CSS support.&lt;/p&gt;

&lt;h3&gt;
  
  
  New Feature: Fields
&lt;/h3&gt;

&lt;p&gt;A field is a node that can store a key-value pair. This introduces structured data to your nodes, letting you create nodes as data records. You can also search for nodes by field. This initial pass supports text values, but we'll soon provide more value types. &lt;/p&gt;

&lt;p&gt;To turn a node into a field:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Indent underneath the node you want to contain the field, and type the field name&lt;/li&gt;
&lt;li&gt;Command/Control + K to open the command palette, and choose "Create Field"&lt;/li&gt;
&lt;li&gt;Add your field value in the value section&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  New Feature: Live Search
&lt;/h3&gt;

&lt;p&gt;Live Search allows you to create search nodes where the children are auto-updating search results. Simply type a keyword, or use the format "fieldname:value" to filter by fields. The Live Search nodes will update automatically as your workspace content changes. This is a powerful way to view your data in new configurations.&lt;/p&gt;

&lt;p&gt;To create a Live Search:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new node where you want your search node, and type your search value&lt;/li&gt;
&lt;li&gt;Command/Control + K to open the command palette, and choose "Create Search Node"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Tips: Search terms are case-insensitive, and you can filter on multiple fields (uses AND, not OR) like so: "fieldname:value fieldname:value".&lt;/p&gt;

&lt;h3&gt;
  
  
  New Feature: References
&lt;/h3&gt;

&lt;p&gt;References are nodes that refer to another node and its children inline. They're sort of like symlinks on the filesystem. This lets you have a node exist in multiple places at once. References are differentiated from normal nodes with a dashed outline around their outline bullet. Deleting a reference node does not delete the node it points to. You may notice that Live Search results are reference nodes!&lt;/p&gt;

&lt;p&gt;To create a reference node:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select the node you want to make a reference to&lt;/li&gt;
&lt;li&gt;Command/Control + K to open the command palette, and choose "Create Reference"&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Bugfixes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Command palette now uses normalized title &lt;a href="https://github.com/treehousedev/treehouse/issues/117" rel="noopener noreferrer"&gt;#117&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Command palette supports mouse interactivity &lt;a href="https://github.com/treehousedev/treehouse/issues/102" rel="noopener noreferrer"&gt;#102&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Components no longer fail with bundled library &lt;a href="https://github.com/treehousedev/treehouse/issues/119" rel="noopener noreferrer"&gt;#119&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Ensure Node IDs are unique &lt;a href="https://github.com/treehousedev/treehouse/issues/104" rel="noopener noreferrer"&gt;#104&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Reference sub-nodes now include fields &lt;a href="https://github.com/treehousedev/treehouse/issues/121" rel="noopener noreferrer"&gt;#121&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Search nodes no longer production workspace &lt;a href="https://github.com/treehousedev/treehouse/issues/118" rel="noopener noreferrer"&gt;#118&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Prevent indenting/outdenting a field node &lt;a href="https://github.com/treehousedev/treehouse/issues/116" rel="noopener noreferrer"&gt;#116&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Enhancements and Chores
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;New feature: Field nodes&lt;/li&gt;
&lt;li&gt;New feature: Live Search nodes&lt;/li&gt;
&lt;li&gt;New feature: Reference nodes&lt;/li&gt;
&lt;li&gt;Clear out non-existent node keys in workspace document under expanded &lt;a href="https://github.com/treehousedev/treehouse/issues/120" rel="noopener noreferrer"&gt;#120&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Don't show bullet for empty nodes &lt;a href="https://github.com/treehousedev/treehouse/issues/31" rel="noopener noreferrer"&gt;#31&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Allow hovering over menu area to show menu &lt;a href="https://github.com/treehousedev/treehouse/issues/76" rel="noopener noreferrer"&gt;#76&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Clean up styles on search bar, palette, quick add, menu, buttons &lt;a href="https://github.com/treehousedev/treehouse/issues/81" rel="noopener noreferrer"&gt;#81&lt;/a&gt;, &lt;a href="https://github.com/treehousedev/treehouse/issues/85" rel="noopener noreferrer"&gt;#85&lt;/a&gt;, &lt;a href="https://github.com/treehousedev/treehouse/issues/96" rel="noopener noreferrer"&gt;#96&lt;/a&gt;, &lt;a href="https://github.com/treehousedev/treehouse/issues/108" rel="noopener noreferrer"&gt;#108&lt;/a&gt;, &lt;a href="https://github.com/treehousedev/treehouse/issues/110" rel="noopener noreferrer"&gt;#110&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Show placeholder text for empty field key/value inputs &lt;a href="https://github.com/treehousedev/treehouse/issues/135" rel="noopener noreferrer"&gt;#135&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Implement initial version of mobile web app &lt;a href="https://github.com/treehousedev/treehouse/issues/103" rel="noopener noreferrer"&gt;#103&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>showdev</category>
      <category>css</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Pulling from the best tools for thought</title>
      <dc:creator>Jeff Lindsay</dc:creator>
      <pubDate>Thu, 27 Apr 2023 23:04:08 +0000</pubDate>
      <link>https://forem.com/progrium/pulling-from-the-best-tools-for-thought-5eap</link>
      <guid>https://forem.com/progrium/pulling-from-the-best-tools-for-thought-5eap</guid>
      <description>&lt;p&gt;Over the past few months, we've built the &lt;a href="https://treehouse.sh" rel="noopener noreferrer"&gt;Treehouse frontend framework&lt;/a&gt; into an elegant, quality outliner that's open source, extensible, and gives you control of your data. I’d like to share some of the design influences for the Treehouse frontend, which should give a sense of the unique direction Treehouse is going from here. &lt;/p&gt;

&lt;p&gt;The biggest influences for Treehouse are Tana, Notion, and Obsidian. These three represent the state of the art of personal and collaborative information management, sometimes simplified as note-taking tools. However, "note-taking tools" sells them short as they go beyond note-taking and information management. For lack of a better descriptor, many consider them &lt;a href="https://www.forthought.tools/" rel="noopener noreferrer"&gt;tools for thought&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Notes to Tools for Thought
&lt;/h2&gt;

&lt;p&gt;For most, note-taking brings to mind simple apps like Apple Notes and Google Keep, or even just a text file editor. These work well for people because they're already there and focus on quick and easy plain text capture. We could call this casual note-taking. &lt;/p&gt;

&lt;p&gt;Back in the 2000s, hosted and self-hosted wikis became popular for easy, collaborative web publishing and knowledge management. Like Wikipedia, they could be used to build out hyperlinked knowledge repositories. Many wiki-based tools focused on their use as personal notebooks, one of the most influential examples being &lt;a href="https://tiddlywiki.com/" rel="noopener noreferrer"&gt;TiddlyWiki&lt;/a&gt;. The simple versatility of the wiki laid the groundwork for what we call "tools for thought" today.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F8lwvLU4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://treehouse.sh/photos/blog/tiddlywiki.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F8lwvLU4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://treehouse.sh/photos/blog/tiddlywiki.png" alt="TiddlyWiki screenshot" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When &lt;a href="https://www.notion.so/" rel="noopener noreferrer"&gt;Notion&lt;/a&gt; appeared in the mid-2010s, it built on the idea of the wiki and introduced structured data management with flexible views that &lt;em&gt;effectively gave you integrated, customizable versions of other productivity tools&lt;/em&gt;. Notion, Airtable, and others helped bring in the age of no-code and low-code tools, allowing knowledge workers and entrepreneurs to build their own "apps" or solutions to problems without traditionally building software. Notion brought it all together in a simple, user-friendly experience based around the core idea of wiki-like information management.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ljjuGTlg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://treehouse.sh/photos/blog/notion.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ljjuGTlg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://treehouse.sh/photos/blog/notion.jpeg" alt="Notion screenshot" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Meanwhile, a separate paradigm of note-taking tools emerged, focusing on the nested, tree-like structure of the outline. Perhaps inspired by tools like &lt;a href="https://www.omnigroup.com/omnioutliner/" rel="noopener noreferrer"&gt;OmniOutliner&lt;/a&gt; and &lt;a href="https://orgmode.org/" rel="noopener noreferrer"&gt;Org Mode&lt;/a&gt; for Emacs of the 2000s, &lt;a href="https://workflowy.com/" rel="noopener noreferrer"&gt;Workflowy&lt;/a&gt; appeared in 2010 as a no-frills web-based outliner. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h41xJQ2q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://treehouse.sh/photos/blog/workflowy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h41xJQ2q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://treehouse.sh/photos/blog/workflowy.png" alt="Workflowy screenshot" width="800" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://obsidian.md/" rel="noopener noreferrer"&gt;Obsidian&lt;/a&gt; arrived in 2020 and is a local app focusing on Markdown files stored on your filesystem. Obsidian has a large plugin ecosystem giving it a wide breadth of features, but it’s especially appealing to those that want to own their data. If you strip away the plugins, Obsidian is a pretty simple hyperlinked Markdown editor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ybmIUplU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://treehouse.sh/photos/blog/obsidian.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ybmIUplU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://treehouse.sh/photos/blog/obsidian.png" alt="Obsidian screenshot" width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most recently, a tool in early access called &lt;a href="https://tana.inc/" rel="noopener noreferrer"&gt;Tana&lt;/a&gt; caught my attention. Their key innovation is taking the linked outline model of Workflowy and introducing schemas for nodes, making them into structured data. This gives Tana the embedded database functionality of Notion and Airtable, a step towards bringing the two paradigms of note-taking software together towards powerful, malleable tools for thought.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5KRDqeBF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://treehouse.sh/photos/blog/tana.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5KRDqeBF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://treehouse.sh/photos/blog/tana.webp" alt="Tana screenshot" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Treehouse Fits In
&lt;/h2&gt;

&lt;p&gt;By now there's no shortage of options in this space, both as SaaS and open source. Take a look at this growing &lt;a href="https://noteapps.info/" rel="noopener noreferrer"&gt;encyclopedia of note-taking tools&lt;/a&gt;. Like Notion and Tana, many of the apps listed are much more than note-taking tools. Some lean into the framing of "collaborative documents", and some are just categorized more generally as "productivity tools". Tana goes so far as to say "the everything OS". &lt;/p&gt;

&lt;p&gt;Note-taking is just the beginning. It's a tangible gateway for something more powerful inherent to computing. Ever since Engelbart's &lt;a href="https://en.wikipedia.org/wiki/The_Mother_of_All_Demos" rel="noopener noreferrer"&gt;mother of all demos&lt;/a&gt;, the computing revolution seems to start with powerful tools for thought, which are, at minimum, good note-taking tools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PEoknR3N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://treehouse.sh/photos/blog/nls.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PEoknR3N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://treehouse.sh/photos/blog/nls.jpeg" alt="Engelbart using NLS" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Treehouse is a frontend and starter kit for anybody else that wants to explore this space with us. We will release a standalone product based on it soon, but most of the user-facing development will be done in the open source Treehouse project. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YNp678CW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://treehouse.sh/photos/hero-image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YNp678CW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://treehouse.sh/photos/hero-image.png" alt="Treehouse screenshot" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today with Treehouse you can build your own Workflowy equivalent, but soon it will become more comparable to Tana and Notion with the open extensibility of Obsidian. That alone is pretty exciting to have in a minimal open source project, but I can't wait to show you what will come next. &lt;/p&gt;

&lt;h2&gt;
  
  
  Coming Soon
&lt;/h2&gt;

&lt;p&gt;In the next post, I'll start getting technical and share details on the Treehouse project stack and architecture. If you can't wait, we do have &lt;a href="https://treehouse.sh/docs/dev/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; for you to check out. &lt;/p&gt;

&lt;p&gt;Thanks for reading, and a big thanks to my &lt;a href="https://github.com/sponsors/progrium" rel="noopener noreferrer"&gt;sponsors&lt;/a&gt; for supporting this kind of open source work. Share your thoughts and favorite note-taking tools in the &lt;a href="https://github.com/treehousedev/treehouse/discussions/95" rel="noopener noreferrer"&gt;discussion thread&lt;/a&gt; for this post.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Treehouse release 0.2.0 with CSS design system</title>
      <dc:creator>Jeff Lindsay</dc:creator>
      <pubDate>Tue, 28 Mar 2023 18:19:09 +0000</pubDate>
      <link>https://forem.com/progrium/treehouse-release-020-with-css-design-system-42hn</link>
      <guid>https://forem.com/progrium/treehouse-release-020-with-css-design-system-42hn</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/wj4uai9yUJ0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  New design system, GitHub session locking, and documentation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/treehousedev/treehouse/releases/tag/0.2.0" rel="noopener noreferrer"&gt;This release&lt;/a&gt; is a refinement of our initial release, fixing a number of bugs and adding interaction improvements. The look and feel of the UI was also updated with the start of a new CSS design system based on custom properties. Session locking was added for the live demo and GitHub backend so multiple devices/browsers/tabs don't clobber changes of each other. Documentation also got an upgrade with the start of a &lt;a href="https://treehouse.sh/docs/quickstart/" rel="noopener noreferrer"&gt;full guide&lt;/a&gt; on the website. &lt;/p&gt;

&lt;h2&gt;
  
  
  Bugfixes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Autosave error when switching between devices &lt;a href="https://github.com/treehousedev/treehouse/issues/32" rel="noopener noreferrer"&gt;#32&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Deleting a node doesn't delete child nodes &lt;a href="https://github.com/treehousedev/treehouse/issues/25" rel="noopener noreferrer"&gt;#25&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Hitting return should produce a new node directly below the above node &lt;a href="https://github.com/treehousedev/treehouse/issues/29" rel="noopener noreferrer"&gt;#29&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;TypeError exception when switching back from new panel &lt;a href="https://github.com/treehousedev/treehouse/issues/65" rel="noopener noreferrer"&gt;#65&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Support emojis &lt;a href="https://github.com/treehousedev/treehouse/issues/52" rel="noopener noreferrer"&gt;#52&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Enhancements and Chores
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Typography and layout improvements to application &lt;a href="https://github.com/treehousedev/treehouse/issues/37" rel="noopener noreferrer"&gt;#37&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Add keyboard shortcut to move nodes up or down &lt;a href="https://github.com/treehousedev/treehouse/issues/28" rel="noopener noreferrer"&gt;#28&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Prevent backspace to delete if there are child nodes &lt;a href="https://github.com/treehousedev/treehouse/issues/15" rel="noopener noreferrer"&gt;#15&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Allow renaming the workspace &lt;a href="https://github.com/treehousedev/treehouse/issues/23" rel="noopener noreferrer"&gt;#23&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Clicking outside of the search bar/command palette should close it &lt;a href="https://github.com/treehousedev/treehouse/issues/48" rel="noopener noreferrer"&gt;#48&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Workspace/workbench separation &lt;a href="https://github.com/treehousedev/treehouse/issues/39" rel="noopener noreferrer"&gt;#39&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Add API docs &lt;a href="https://github.com/treehousedev/treehouse/issues/34" rel="noopener noreferrer"&gt;#34&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Set up versioned library bundle &lt;a href="https://github.com/treehousedev/treehouse/issues/41" rel="noopener noreferrer"&gt;#41&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Allow backspace to delete an empty child node &lt;a href="https://github.com/treehousedev/treehouse/issues/53" rel="noopener noreferrer"&gt;#53&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Save last location on reloads &lt;a href="https://github.com/treehousedev/treehouse/issues/54" rel="noopener noreferrer"&gt;#54&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Hide buttons to move a panel up/down &lt;a href="https://github.com/treehousedev/treehouse/issues/49" rel="noopener noreferrer"&gt;#49&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>showdev</category>
      <category>css</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Build your own Tana clone with this new frontend</title>
      <dc:creator>Jeff Lindsay</dc:creator>
      <pubDate>Thu, 02 Mar 2023 16:53:59 +0000</pubDate>
      <link>https://forem.com/progrium/build-your-own-tana-clone-with-this-new-frontend-15ao</link>
      <guid>https://forem.com/progrium/build-your-own-tana-clone-with-this-new-frontend-15ao</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/wtJCYlR2_ys"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/treehousedev/treehouse" rel="noopener noreferrer"&gt;Treehouse GitHub project&lt;/a&gt; (pls star!)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://progrium.xyz/blog/2023/welcome-to-treehouse/" rel="noopener noreferrer"&gt;Announcement blog post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://eepurl.com/iluc5v" rel="noopener noreferrer"&gt;Mailing list&lt;/a&gt; if you're into that&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>showdev</category>
      <category>opensource</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Apptron Demo: HTML5 Background Apps</title>
      <dc:creator>Jeff Lindsay</dc:creator>
      <pubDate>Fri, 19 Aug 2022 15:31:01 +0000</pubDate>
      <link>https://forem.com/progrium/apptron-demo-html5-background-apps-35io</link>
      <guid>https://forem.com/progrium/apptron-demo-html5-background-apps-35io</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/i9nNUOHF7G4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this week's demo I built a background application using HTML and &lt;a href="https://progrium.com/blog/apptron-announcement/" rel="noopener noreferrer"&gt;Apptron&lt;/a&gt;. It may seem weird to involve a webview at all for a background app, which is why this was not a use case I had planned, but I was pleasantly surprised to discover how this turned out.&lt;/p&gt;

&lt;p&gt;In the last demo, we made an app indicator background utility as a shell script. This week we re-create it using JavaScript in an HTML file. With &lt;code&gt;apptron build&lt;/code&gt; we can make it into a standalone executable. This workflow was originally intended for quick webview apps, but because we can let the JavaScript of the page run while the window is hidden, we effectively get a background application. &lt;/p&gt;

&lt;p&gt;Apptron wasn't made just for webview apps. I wanted to expose other native APIs that let you hook into more pre-built UI elements the operating system provides. For now this covers the common ones like app indicators, dialogs, and desktop notifications. In the future I'd like to expose APIs to let you add new items to system menus, control panels, and other places the OS lets developers hook into. These are important to make scriptable so you can easily leverage them for simple workflow hacks. When it's easy to throw that kind of thing together, you don't need to find "an app for that," you can just imagine what would work for you and make it happen.&lt;/p&gt;

&lt;p&gt;If this is also a world you want to see, &lt;a href="https://tractor.dev/apptron/" rel="noopener noreferrer"&gt;join Apptron early access&lt;/a&gt; and help us get this thing out. See you next demo!&lt;/p&gt;

&lt;p&gt;-jeff&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>html</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Apptron Demo: Shell Scriptable Native APIs</title>
      <dc:creator>Jeff Lindsay</dc:creator>
      <pubDate>Fri, 05 Aug 2022 21:45:03 +0000</pubDate>
      <link>https://forem.com/progrium/apptron-demo-shell-scriptable-native-apis-3o8p</link>
      <guid>https://forem.com/progrium/apptron-demo-shell-scriptable-native-apis-3o8p</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/UHFS4STFYXM"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this demo I show off the rest of the &lt;a href="https://progrium.com/blog/apptron-announcement/" rel="noopener noreferrer"&gt;Apptron&lt;/a&gt; CLI, which exposes most of the cross-platform APIs as commands. These commands make great shell scriptable utilities, and you can see how they've been designed to facilitate this. By the end, we'll have created an app indicator (systray) icon and menu that's created and driven by a shell script.&lt;/p&gt;

&lt;p&gt;There is a whole class of power users that doesn't always want to take the time to "write a program," let alone learn how. Since the functionality is right there, why not expose it in a way that's useful for these folks? Sysadmins and devops engineers often spend most of their time at a command prompt, so this feature goes out to all of them.&lt;/p&gt;

&lt;p&gt;It turns out having a CLI interface to the APIs also makes it easy to do basic regression testing for the project. It also provides a kind of accessible listing of functionality. And! It helps with our polyglot primitive goal, working as a stopgap before having native library support for a language, since nearly all languages can "shell out". &lt;/p&gt;

&lt;p&gt;As I mentioned in the video, this is a strategy I like to use when making generative primitives: maximize utility by providing multiple ways to access features. Like being language agnostic, this helps meet users where they are, and reach users you might not otherwise. There's also often a dominant context people think of for some functionality, so showing it in a new or surprising context helps break people out of existing thought patterns and imagine new possibilities. &lt;/p&gt;

&lt;p&gt;Let's see what possibilities open up with the next demo! In the meantime, &lt;a href="https://tractor.dev/apptron/" rel="noopener noreferrer"&gt;join early access&lt;/a&gt; to explore Apptron on your own.&lt;/p&gt;

&lt;p&gt;-jeff&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>html</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
