Latest Posts (20 found)

Bending Emacs - Episode 7: Eshell built-in commands

With my recent rinku post and Bending Emacs episode 6 both fresh in mind, I figured I may as well make another Bending Emacs episode, so here we are: Bending Emacs Episode 7: Eshell built-in commands Check out the rinku post for a rundown of things covered in the video. Liked the video? Please let me know. Got feedback? Leave me some comments . Please go like my video , share with others, and subscribe to my channel . If there's enough interest, I'll continue making more videos! Enjoying this content or my projects ? I am an indie dev. Help make it sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my iOS apps too ;)

0 views
xenodium Yesterday

Rinku: CLI link previews

In my last Bending Emacs episode, I talked about overlays and used them to render link previews in an Emacs buffer. While the overlays merely render an image, the actual link preview image is generated by rinku , a tiny command line utility I built recently. leverages macOS APIs to do the actual heavy lifting, rendering/capturing a view off screen, and saving to disk. Similarly, it can fetch preview metadata, also saving the related thumbnail to disk. In both cases, outputs to JSON. By default, fetches metadata for you. In this instance, the image looks a little something like this: On the other hand, the flag generates a preview, very much like the ones you see in native macOS and iOS apps. Similarly, the preview renders as follows: While overlays is one way to integrate anywhere in Emacs, I had been meaning to look into what I can do for eshell in particular. Eshell is just another buffer , and while overlays could do the job, I wanted a shell-like experience. After all, I already knew we can echo images into an eshell buffer . Before getting to on , there's a related hack I'd been meaning to get to for some time… While we're all likely familiar with the cat command, I remember being a little surprised to find that offers an alternative elisp implementation. Surprised too? Go check it! Where am I going with this? Well, if eshell's command is an elisp implementation, we know its internals are up for grabs , so we can technically extend it to display images too. is just another function, so we can advice it to add image superpowers. I was pleasantly surprised at how little code was needed. It basically scans for image arguments to handle within advice and otherwise delegates to 's original implementation. And with that, we can see our freshly powered-up command in action: By now, you may wonder why the detour when the post was really about ? You see, this is Emacs, and everything compounds! We can now leverage our revamped command to give similar superpowers to , by merely adding an function. As we now know, outputs things to JSON, so we can use to parse the process output and subsequently feed the image path to . can also output link titles, so we can show that too whenever possible. With that, we can see the lot in action: While non-Emacs users are often puzzled by how frequently we bring user flows and integrations on to our beloved editor, once you learn a little elisp, you start realising how relatively easily things can integrate with one another and pretty much everything is up for grabs . Reckon and these tips will be useful to you? Enjoying this blog or my projects ? I am an 👉 indie dev 👈. Help make it sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my iOS apps too ;)

0 views
xenodium 3 days ago

Bending Emacs - Episode 6: Overlays

The Bending Emacs series continues with a new a new episode. Bending Emacs Episode 6: Overlays Today we had a quick intro to overlays. Here's the snippet I used for adding snippets: Similarly, this is what we used for removing the overlay. Of the experiments, you can find: Hope you enjoyed the video! Liked the video? Please let me know. Got feedback? Leave me some comments . Please go like my video , share with others, and subscribe to my channel . If there's enough interest, I'll continue making more videos! Enjoying this content or my projects ? I am an indie dev. Help make it sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my iOS apps too ;) Redaction snippet at the related blog post . Dired media metadata at Ready Player's ready-player-dired.el . Link previews: While I don't have elisp to share for link previews just yet, I did release a tiny thumbnail utility named rinku ;)

0 views
xenodium 6 days ago

WhatsApp from you know where

While there are plenty of messaging alternatives out there, for better or worse, WhatsApp remains a necessity for some of us. With that in mind, I looked for ways to bring WhatsApp messaging to the comfort of my beloved text editor. As mentioned in my initial findings , WhatsApp on Emacs is totally doable with the help of wuzapi and whatsmeow , which offer a huge leg up. Today, I introduce a super early version of Wasabi , a native Emacs interface for WhatsApp messaging. I wanted installation/setup to be as simple as possible. Ideally, you install a single Emacs package and off you go. While leveraging XMPP is rather appealing in reusing existing Emacs messaging packages, I felt setting up a WhatsApp gateway or related infrastructure to be somewhat at odds with 's simple installation goal. Having said that, wuzapi / whatsmeow offer a great middle ground. You install a single binary dependency, along with , and you're ready to go. This isn't too different from the git + magit combo. As of now, 's installation/setup boils down to two steps if you're on macOS: While you may try Homebrew on Linux, you're likely to prefer your native package manager. If that fails, building wuzapi from source is also an option. While runs as a RESTful API service + webhooks , I wanted to simplify the Emacs integration by using json-rpc over standard I/O, enabling us to leverage incoming notifications in place of . I floated the idea of adding json-rpc to wuzapi to 's author Nicolas, and to my delight, he was keen on it. He's now merged my initial proof of concept , and I followed up with a handful of additional patches (all merged now): With the latest Wasabi Emacs package and wuzapi binary, you now get the initial WhatsApp experience I've been working towards. At present, you can send/receive messages to/from 1:1 or group chats. You can also download/view images as well as videos. Viewing reactions is also supported. Needless to say, you may find some initial rough edges in addition to missing features. Having said that, I'd love to hear your feedback and experience. As mentioned is currently available on GitHub . I've now put in quite a bit of effort prototyping things, upstreaming changes to , and building the first iteration of wasabi . I gotta say, it feels great to be able to quickly message and catch up with different chats from the comfort of Emacs. Having said that, it's taken a lot of work to get here and will require plenty more to get to a polished and featureful experience. Since going full-time indie dev, I have the flexibility to work on projects of choice, but that's only to an extent. If I cannot make the project sustainable, I'll eventually move to work on something else that is. If you're keen on Wasabi 's offering, please consider sponsoring the effort , and please reach out to voice your interest ( Mastodon / Twitter / Reddit / Bluesky ). Reckon a WhatsApp Emacs client would help you stay focused at work (less time on your phone)? Ask your employer to sponsor it too ;-) Add JSON-RPC 2.0 stdio mode (via -mode=stdio) for communication Expose more HTTP endpoints as JSON-RPCs . Enable setting a custom data directory via -datadir=/path/to/data . Add Homebrew recipe/installation .

0 views
xenodium 2 weeks ago

Want a WhatsApp Emacs client? Will you fund it?

Like it or not, WhatsApp is a necessity for some of us. I wish it weren't the case, but here we are. Given the circumstances, I wish I could use WhatsApp a little more on my terms. And by that, I mean from an Emacs client, of course. Surely I'm not the only one who feels this way, right? Right?! Fortunately, I'm not alone . With that in mind, I've been hard at work prototyping, exploring what's feasible. Spoiler alert: it's totally possible, though will require a fair bit of work. Thankfully, two wonderful projects offer a huge leg up: wuzapi and whatsmeow . wuzapi offers a REST API on top of whatsmeow , a Go library leveraging WhatsApp's multi-device web API. Last week, I prototyped sending a WhatsApp message using 's API. I got there fairly quickly by onboarding myself on to using its web interface and wiring shell-maker to send an HTTP message request via . While these two were enough for a quick demo, they won't cut it for a polished Emacs experience. While I can make REST work, I would like a simpler integration under the hood. REST is fine for outgoing messages, but then I need to integrate webhooks for incoming events. No biggie, can be done, but now I have to deal with two local services opening a couple of ports. Can we simplify a little? Yes we can. You may have seen me talk about agent-shell , my Emacs package implementing Agent Client Protocol (ACP) … Why is this relevant, you may ask? Well, after building a native Emacs implementation, I learned a bit about json-rpc over standard I/O. The simplicity here is that we can bring bidirectional communication to an Emacs-owned process. No need for multiple channels handling incoming vs outgoing messages. So where's this all going? I've been prototyping some patches on top of wuzapi to expose over standard I/O (as an alternative to ). This prototype goes far beyond my initial experiment with sending messages, and yet the Emacs integration is considerably simpler, not to mention looking very promising. Here's a demo showing incoming WhatsApp messages, received via , all through a single Emacs-owned process. Look ma, no ports! These early prototypes are encouraging, but we've only scratched the surface. Before you can send and receive messages, you need to onboard users to the WhatsApp Emacs client. That is, you need to create a user, manage/connect to a session, authorize via a QR code, and more. You'll want this flow to be realiable and that's just onboarding. From there, you'll need to manage contacts, chats, multiple message types, incoming notifications… the list goes on. That's just the Emacs side. As mentioned, I've also been patching . My plan is to upstream these changes , rather than maintaining a fork. I've prototyped quite a few things now, including the onboarding experience with QR code scanning. At this point, I feel fairly optimistic about feasibility, which is all pretty exciting! But there's a bunch of work needed. Since going full-time indie dev, I have the time available (for now), but it's hard to justify this effort without aiming for some level of sustainability. If you're interested in making this a reality, please consider sponsoring the effort , and please reach out to voice your interest ( Mastodon / Twitter / Reddit / Bluesky ). Reckon a WhatsApp Emacs client would help you stay focused at work (less time on your phone)? Ask your employer to sponsor it too ;-)

0 views
xenodium 3 weeks ago

agent-shell 0.17 improvements + MELPA

While it's only been a few weeks since the last agent-shell post , there are plenty of new updates to share. What's agent-shell again? A native Emacs shell to interact with any LLM agent powered by ACP ( Agent Client Protocol ). Before getting to the latest and greatest, I'd like to say thank you to new and existing sponsors backing my projects. While the work going in remains largely unsustainable, your contributions are indeed helping me get closer to sustainability. Thank you! If you benefit from my content and projects, please consider sponsoring to make the work sustainable. Work paying for your LLM tokens and other tools? Why not get your employer to sponsor agent-shell also? Now on to the very first update… Both agent-shell and acp.el are now available on MELPA. As such, installation now boils down to: OpenCode and Qwen Code are two of the latest agents to join agent-shell . Both accessible via and through the agent picker, but also directly from and . Adding files as context has seen quite a few improvements in different shapes. Thank you Ian Davidson for contributing embedded context support. Invoke to take a screenshot and automatically send it over to . A little side-note, did you notice the activity indicator in the header bar? Yep. That's new too. While file completion remains experimental, you can enable via: From any file you can now invoke to send the current file to . If region is selected, region information is sent also. Fancy sending a different file other than current one? Invoke with , or just use . , also operates on files (selection or region), DWIM style ;-) You may have noticed paths in section titles are no longer displayed as absolute paths. We're shortening those relative to project roots. While you can invoke with prefix to create new shells, is now available (and more discoverable than ). Cancelling prompt sessions (via ) is much more reliable now. If you experienced a shell getting stuck after cancelling a session, that's because we were missing part of the protocol implementation. This is now implemented. Use the new to automatically insert shell (ie. bash) command output. Initial work for automatically saving markdown transcripts is now in place. We're still iterating on it, but if keen to try things out, you can enable as follows: Text header Applied changes are now displayed inline. The new and can now be used to change the session mode. You can now find out what capabilities and session modes are supported by your agent. Expand either of the two sections. Tired of pressing and to accept changes from the diff buffer? Now just press from the diff viewer to accept all hunks. Same goes for rejecting. No more and . Now just press from the diff buffer. We get a new basic transient menu. Currently available via . We got lots of awesome pull requests from wonderful folks. Thank you for your contributions! Beyond what's been showcased here, much love and effort's been poured into polishing the experience. Interested in the nitty-gritty? Have a look through the 173 commits since the last blog post. If agent-shell or acp.el are useful to you, please consider sponsoring its development. LLM tokens aren't free, and neither is the time dedicated to building this stuff ;-) Arthur Heymans : Add a Package-Requires header ( PR ). Elle Najt : Execute commands in devcontainer ( PR ). Elle Najt : Fix Write tool diff preview for new files ( PR ). Elle Najt : Inline display of historical changes ( PR ). Elle Najt : Live Markdown transcripts ( PR ). Elle Najt : Prompt session mode cycling and modeline display ( PR ). Fritz Grabo : Devcontainer fallback workspace ( PR ). Guilherme Pires : Codex subscription auth ( PR ). Hordur Freyr Yngvason : Make qwen authentication optional ( PR ). Ian Davidson : Embedded context support ( PR ). Julian Hirn : Fix quick-diff window restoration for full-screen ( PR ). Ruslan Kamashev : Hide header line altogether ( PR ). festive-onion : Show Planning mode more reliably ( PR ).

0 views
xenodium 1 months ago

time-zones now on MELPA. Do I have your support?

A little over a week ago, I introduced time-zones , an Emacs utility to easily check city times around the world. Today, I'm happy to report, the package has been accepted into MELPA . It's been wonderful to see how well time-zones was received on Reddit . ✓ You asked for MELPA publishing and I delivered . ✓ You asked for DST display and I delivered . ✓ You asked for a UTC picker and I delivered . ✓ You asked for UTC offset display and I delivered . ✓ You asked for Windows support and I delivered . ✓ You asked for help and bug fixes and I delivered . Bringing features and improving our beloved text editor takes time and effort. isn't my first package, I've also published a bunch of Emacs packages . Will you help make this work sustainable ?

0 views
xenodium 1 months ago

Bending Emacs - Episode 4: Batch renaming files

I'm now a few weeks into my Bending Emacs series. Today I share a new episode. Bending Emacs Episode 4: Batch renaming files In this video, I show a few ways of batch renaming files. The covered flows are: Liked the video? Please let me know. Got feedback? Leave me some comments . Please go like my video , share with others, and subscribe to my channel . If there's enough interest, I'll continue making more videos! Enjoying this content or my projects ? I am an indie dev. Help make it sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my iOS apps too ;) Dired editable buffers . Multiple cursors using region-bindings-mode to insert numbers via # (I had a tiny blog entry on this). We can batch rename using Keyboard Macros too and insert numbers via macro counters . While I typically use multiple cursors for batch renaming files, I also experimented with dwim-shell-command via M-x dwim-shell-commands-rename-all .

0 views
xenodium 1 months ago

Emacs time-zones

Emacs ships with a perfectly functional world clock, available via . Having said that, there are two things I wish it had: As far as I can tell, these are neither available nor possible on the built-in (please correct me if otherwise), so when my friend across the world recently asked me for the best time to meet, I knew this was the last nudge I needed to get this done. With that, I give you (now on GitHub ). There isn't much to talk about other than accomplishes the above tasks very easily without resorting to writing elisp nor accessing via customize, which I seldom use. As I mentioned, is on GitHub if you'd like to give it a spin. It's super fresh, so please report any issues. Hope you like it. Reckon will be useful to you? Enjoying this blog or my projects ? I am an indie dev. Help make it sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my iOS apps too ;) A quick way to interactively add any city (bonus points for fuzzy search). An easy way to shift the time back and forth.

0 views
xenodium 1 months ago

Bending Emacs - Episode 3: Git clone (the lazy way)

Continuing on the Bending Emacs series, today I share a new episode. Bending Emacs Episode 03: Git clone (the lazy way) In this video, I show my latest iteration on an expedited git clone flow. If this topic sounds familiar, I covered it back in 2020 with my clone git repo from clipboard post. My git clone flow consists of copying a git repo URL to the clipboard and subsequently invoking . Everything else is taken care of for you. I've revisited this command and added a couple of improvements: Configurability (via ). For example: Optional prefixes to change function behavior Automatically place point/cursor at README file. I was going to post the snippet here, though may as well point you over to GitHub where is more likely to remain up-to-date. Note that is now optionally available as part of my dwim-shell-command package. Liked the video? Please let me know. Got feedback? Leave me some comments . Please go like my video , share with others, and subscribe to my channel . If there's enough interest, I'll continue making more videos! Configurability (via ). For example: Optional prefixes to change function behavior : Pick target location . : Pick any directory. Automatically place point/cursor at README file.

0 views
xenodium 1 months ago

agent-shell 0.5 improvements

While it's only been a few weeks since introducing Emacs agent-shell , we've landed nearly 100 commits and enough improvements to warrant a new blog post. agent-shell now includes support for two additional ACP-capable agents: In addition to starting new shells via agent-specific commands, we now have a unified entry point, enabling selection from a list of supported agents. The agent-specific commands remain available as usual: now provides basic control to toggle display of shell buffers: While provides basic display toggling, Calum MacRae offers a comprehensive sidebar package. Check out agent-shell-sidebar . now has experimental support for running agents inside dev containers. See docs . buffers, proposing changes, get a more polished experience. More notably, diffs get context (thanks to David J. Rosenbaum), single-key patch navigation/acceptance, and file names now displayed in header line. Environment variables can now be loaded from either the Emacs environment, .env files, and/or overridden inline: Different authentication methods are now supported. For example: Check per provider, as available options may differ. On the smaller side, but also contributing to overall polish: While not technically part of , acp.el 's traffic inspection has been getting some love to help users diagnose issues. Thank you for your contributions! Thank you to all sponsors. While LLMs aren't everyone's cup of tea, we're seeing editors across the board evolving to accommodate these new LLM tools. In a somewhat similar vein, LSP integration wasn't for everyone, but for those who did want it, Emacs luckily catered to them. Thank you for helping make this project sustainable while also enabling Emacs to cater to all. If agent-shell or acp.el are useful to you, consider sponsoring its development. LLM tokens aren't free, and neither is the time dedicated to building this stuff ;-) Claude Code Codex via codex-acp (new) Goose (new) : Toggles display of the most recently accessed agent (per project). : Controls how agent shells are displayed when activated. Single-key permission bindings (y/n/!). Improved error messages. Improved task status rendering. Improved TAB navigation. David J. Rosenbaum: Context support in diffs ( PR ). Fritz Grabo: Dev container support ( PR ). Grant Surlyn: Doom Emacs installation instructions ( PR ). Mark A. Hershberger: Goose key improvement ( PR ). Ruslan Kamashev: Customization group fix ( PR ).

0 views
xenodium 1 months ago

Bending Emacs - Episode 2: From vanilla to your flavor

While still finding my footing making Emacs videos, today I'm sharing my second video. Bending Emacs Episode 02: From vanilla to your flavor The video is a little longer than I intended at 14:37, so plan accordingly. In this video, I show some of my favorite UI customizations, with additional tips and tricks along the way. Like my first video, I'm hoping you find unexpected goodies in there despite being familiar with the general topic. Read on for all supporting material… Showcased a handful of ways to evaluate elisp. M-x eval-last-sexp M-x eval-expression M-x eval-buffer M-x org-ctrl-c-ctrl-c (Evaluate org source blocks) Sample snippets: other-emacs.el (minimal, almost vanilla setup): We want to extend source blocks to accept the header argument as follows: So we advice : No text in title bar Transparent titlebar (macOS) A little static welcome screen I cooked up. Liked the video? Please let me know. Got feedback? Leave me some comments . Please go like my video , share with others, and subscribe to my channel . If there's enough interest, I'll continue making more videos! M-x eval-last-sexp M-x eval-expression M-x eval-buffer M-x org-ctrl-c-ctrl-c (Evaluate org source blocks) Sample snippets: M-x describe-function (built-in). M-x helpful-callable (via third-party helpful package).

0 views
xenodium 2 months ago

Bending Emacs - Episode 1: Applying CLI utils

While most of the content I share is typically covered in blog posts, I'm trying something new. Today, I'll share my first episode of Bending Emacs. This video focuses on how I like to apply (or batch-apply) command line utilities. While the video focuses on applying command line utilities, here's a list of all the things I used: Liked the video? Please let me know. Got feedback? Leave me some comments . Please go like my video , share with others, and subscribe to my channel . If there's enough interest, I'll make more videos! Org mode for the presentation itself. ffmpeg does the heavy lifting converting videos to gifs. Asked Claude for the relevant command via chatgpt-shell 's . Browsed the video directory via dired mode. Previewed video thumbnails via ready-player mode. Previewed gifs via image mode 's . Validated the command via eshell . Applied a DWIM shell command via . Duplicated files from via .

0 views
xenodium 2 months ago

Introducing Emacs agent-shell (powered by ACP)

Not long ago, I introduced acp.el , an Emacs lisp implementation of ACP ( Agent Client Protocol ), the agent protocol developed between Zed and Google folks . While I've been happily accessing LLMs from my beloved text editor via chatgpt-shell (a multi-model package I built), I've been fairly slow on the AI agents uptake. Probably a severe case of old-man-shouts-at-cloud sorta thing, but hey I want well-integrated tools in my text editor. When I heard of ACP, I knew this was the thing I was waiting for to play around with agents. With an early acp.el client library in place, I set out to build an Emacs-native agent integration… Today, I have an initial version of agent-shell I can share. is a native Emacs shell, powered by comint-mode (check out Mickey's comint article btw). As such, we don't have to dance between char and line modes to interact with things. is just a regular Emacs buffer like any other you're used to. Thanks to ACP, we can now build agent-agnostic experiences by simply configuring our clients to communicate with their respective agents using a common protocol. As users, we benefit from a single, consistent experience, powered by any agent of our choice. Configuring different agents from boils down which agent we want running in the comms process. Here's an example of Gemini CLI vs Claude Code configuration: I've yet to try other agents. If you get another agent running, I'd love to hear about it. Maybe submit a pull request ? While I've been relying on my acp.el client library, I'm still fairly new to the protocol. I often inspect traffic to see what's going on. After staring at json for far too long, I figured I may as well build some tooling around acp.el to make my life easier. I added a traffic buffer for that. From , you can invoke it via . Developing against paid agents got expensive quickly. Not only expensive, but my edit-compile-run cycle also became boringly slow waiting for agents. While I knew I wanted some sort of fake agent to work against, I didn't want to craft the fake traffic myself. Remember that traffic buffer I showed ya? Well, I can now save that traffic to disk and replay it later. This enabled me to run problematic sessions once and quickly replay multiple times to fix things. While re-playing has its quirks and limitations, it's done the job for now. You can see a Claude Code session below, followed by its replayed counterpart via fake infrastructure. Getting here took quite a bit of work. Having said that, it's only a start. I myself need to get more familiar with agent usage and evolve the package UX however it feels most natural within its new habitat. Lately, I've been experimenting with a quick diff buffer, driven by n/p keys, shown along the permission dialog. While I've implemented enough parts of the Agent Client Protocol Schema to make the package useful, it's hardly complete. I've yet to fully familiarize myself with most protocol features. Both of my new Emacs packages, agent-shell and acp.el , are now available on GitHub. As an agent user, go straight to agent-shell . If you're a package author and would like to build an ACP experience, then give acp.el a try. Both packages are brand new and may have rough edges. Be sure to file bugs or feature requests as needed. I've been heads down, working on these packages for some time. If you're using cloud LLM services, you're likely already paying for tokens. If you find my work useful, please consider routing some of those coins to help fund it. Maybe my tools make you more productive at work? Ask your employer to support the work . These packages not only take time and effort, but also cost me money. Help fund the work .

0 views
xenodium 2 months ago

Introducing acp.el

I recently shared my early Emacs experiments with ACP , the Agent Client Protocol now supported by Gemini CLI and Claude Code LLM agents. While we can already run these agents from Emacs with the likes of vterm , I'm keen to offer an Emacs-native alternative to drive them. To do that, I'm working an a new package: (more on this to be shared soon). While this new Emacs agent shell has an opinionated user experience, it uses ACP under the hood. Being a protocol, it's entirely UI-agnostic. For this, I now have an early version available of the acp.el library. implements Agent Client Protocol for Emacs lisp as per agentclientprotocol.com . While this library is in its infancy, it's enabling me to carry on with my work. lives as a separate library, is UI-agnostic, and can be used by Emacs package authors to build the their desired ACP-powered agent experience. You can instantiate an ACP client and send a request as follows: I'm new at using ACP myself, so I've added a special logging buffer to which enables me to inspect traffic and learn about the exchanges between clients and agents. You can enable logging with: Look out for the buffer, which looks a little like this: If you're keen to experiment with ACP in Emacs lisp and build agent-agnostic packages, take a look at ( now on GitHub ). As mentioned, it's early days for this library, but it's a start. Please file issues and feature requests. If you build anything on top of , lemme know. I'd love to see it in action. I'm working on two new Emacs packages: acp.el (introduced in this post) and (I'll soon share more about that). Please help me make development of these packages sustainable . These packages take time and effort, but also cost me money as I have to pay for LLM tokens throughout testing and development. Please help fund it .

0 views
xenodium 2 months ago

So you want ACP (Agent Client Protocol) for Emacs?

Last week, I was delighted to see the Zed editor shipping beta support for their Claude Code integration . Being an Emacs enthusiast, you may wonder about my excitement. In their demo, the Zed team mentioned the integration is now possible thanks to Agent Client Protocol (ACP) , which they developed in collaboration with Google. This is great news for Emacs users, as it opens the possibilities for deeper native agent integrations in our beloved editor. You can think of ACP as LSP but for LLM agents. While I have a bunch of LLM models integrated into chatgpt-shell (including local ones ), I've yet to make much headway into enabling the models to access smarter context (ie. filesystem or local tools), beyond my initial tool calling experiment . Somehow, I wasn't super excited about tool calling, as it felt like these integrations would fall short when compared to more advanced agents like Anthropic's Claude Code or Google's Gemini CLI . In fact, I haven't been that enthusiastic about these agents, since they offered relatively little API surface to enable deeper Emacs integration (which is where I live!). That is, until ACP came along. With ACP in mind, I'm much more likely to get on board with Emacs-agent integrations. I can now delegate all that complex agent logic to external tools and focus on building a great Emacs experience I'd be happy with. And with that, I had an initial go at prototyping a bare minimum but with enough UX shell goodies to get me excited about it. I chose Gemini for this prototype. You can see it all in its minimal glory: While getting the initials kinda working was relatively straightforward (with everything I already know about building chatgpt-shell), adding support for all ACP features with a delightfully polished Emacs experience will take a bunch of effort. While I'm excited about the prospects, dedicating a chunk of my time to make this happen isn't super feasible. You may have noticed more Emacs-related work/posts from me lately. This is currently possible because I've gone full indie dev. The flexibility is great, but doing Emacs things isn't exactly gonna help pay the bills unless interested folks help fund/support the effort . My shell packages have quite a few enthusiastic users who more often than not, are using my package to talk to paid cloud services from the likes of OpenAI, Anthropic, or Google. I'm looking at you folks! I understand you're sending money to these companies who are providing you with a great service, but also remember the lovely Emacs integrations you use, which also need funding (much more than these well-funded commercial entities). While I'm a fan of chat-like Emacs shells for LLM/agents and would like to build a new agent shell, I also want to dedicate a chunk of this effort to building a UX-agnostic ACP Emacs library (acp.el). This library could be leveraged by me or any other Emacs package author. Enough to take your wallets out and help fund it ?

0 views
xenodium 2 months ago

Diverted mode

James Dyer and I both ran into the same workflow snag when fixing source indentation . He explains it best: Naturally, this is Emacs and were both able to patch our editor to smoothen things out. While I ran into the same snag after selecting an entire buffer (via ), I also faced it with and er/expand-region (awesome package btw). With three cases in mind, I wanted a somewhat generic solution, so I built diverted.el , a little minor mode to identify these momentary diversions and try to bring the point back to the original location. Mind you, this was back in 2019 and until James's post, I hadn't heard of anyone else running into a similar snag. Since then, I kept the package as part of my config. James's post gave me the nudge I needed to move out of my config and into its own GitHub repo . By default, recognizes both and as diversions, but you can also recognize the likes of via . I'm hoping configuring is fairly self-explanatory. To date, I only have , , and as recognized diversions. Read on for a little demo… Notice how point is left at the top of the screen after pressing TAB to indent region. Notice how point is left where it was prior to selecting the function and pressing TAB to indent region. That's it for today. If you want to give a try, head over to GitHub . Reckon will be useful to you? Enjoying this blog or my projects ? I am an 👉 indie dev 👈. Help make it sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my iOS apps too ;) You’re working in a file with inconsistent indentation You want to fix the entire buffer’s formatting You run C-x h (select all) followed by M-x indent-region Your mark is now at the beginning of the buffer, disrupting your workflow

0 views
xenodium 3 months ago

Who moved my text?

I had an annoying chatgpt-shell bug where sometimes the compose buffer's svg header would disappear while text was streaming into the Emacs buffer. There are a number of things that could have gone rogue when streaming and post-processing buffer text, so I wasn't quite sure where to start narrowing things down. I had a feeling I could maybe use something like hook to monitor changes, but that only tells me about the text modified. I wanted to know which of my functions triggered the change, so maybe I could print a few frames from the stack? So that's what I did… Here's an extract from the logs: Buffer claude llm (sonnet-4/Programming)> compose changed: 496-498 | Stack: (backtrace-frames mapcar let my-change-tracker insert save-excursion let save-current-buffer progn if #[(output) ((setq output (or output )) (if (buffer-live-p buffer) (progn (save-current-buffer (set-buffer buffer) (let ((inhibit-read-only t)) (save-excursion (if orig-region-active (progn (delete-region region-beginning region-end) (setq orig-region-active nil))) (goto-char marker) (insert output) (set-marker marker (+ (length output) (marker-position marker))))))))) ((region-end) (region-beginning) (orig-region-active) (marker . #<marker at 496 in *claude llm (sonnet-4/Programming)> compose*>) (buffer . claude llm (sonnet-4/Programming)> compose ))] shell-maker–write-reply… After increasing the number of logged frames, I started seeing bits of my code and… bingo! I found a very suspicious . After spotting this, fixing the bug was trivial. While the bug was annoying, I had been procrastinating on fixing as it could have been a number of things. In this case, printing frames from turned out perfect for narrowing things down. I'll be keeping this in the toolbox. Maybe it can help you too. Learned something new? Enjoying this blog or my projects ? I am an 👉 indie dev 👈. Help make it sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my iOS apps too ;)

0 views
xenodium 3 months ago

Dired buffers with media overlays

It's been well over a year now since I've moved most of my music consumption away from streaming. I started purchasing music again, just so I can play offline at any time (and on my terms). That's not so say I don't stream, but that's now purely reserved for discovery. Most playback happens via Ready Player Mode , a little Emacs player I built when I decided to take playback offline. This post isn't so much about Ready Player and more about a recent dired experience. I had a directory with a handful of mp3s, which I wanted to split into separate album subdirectories. The challenge being the mp3 file names did not include album names. Sorting this out isn't a big task for a music-organization tool, but my brain quickly went hmmm… if dired displayed album metadata, I could just use that to quickly guide me through all the file management I needed. After all, I already know how to use ffprobe to extract relevant metadata, so I could just enhance dired's listing to also show me metadata as overlays. dired-git-info does just that. With that, ready-player-dired-mode was born. After enabling with , I can easily get on with my tiny file reorg without any procrastination whatsoever . I've just pushed ready-player-dired-mode to Ready Player's GitHub repo . It's pretty fresh, so you may (or may not) encounter rough edges. Is Ready Player useful to you? Enjoying this blog or my projects ? I am an 👉 indie dev 👈. Help make my work sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my macOS/iOS apps too ;)

0 views
xenodium 3 months ago

Brisket recipe

On a whim, after seeing a random brisket picture online, I decided today was the day to make my first brisket. Rinse and pat dry. Salt both sides and sear. Crush spices, mix, and apply the rub generously all over the surface of the brisket, pressing gently to ensure it adheres. Wrap up in baking paper, place on tray, and wrap with foil. Bake at 120°C. Roughly 2-3 hours per kilo. 15g Kosher salt (coarse) 15g Black pepper (coarsely ground) 10g Smoked paprika 5g Chipotle powder 5g Onion granules 5g Garlic granules 2g Cumin seeds, toasted and ground 2g S&B hot mustard powder 5g Brown sugar

0 views