Latest Posts (20 found)
xenodium 1 weeks ago

Bending Emacs - Episode 9: World times

A new year, a new Bending Emacs episode, so here it goes: Bending Emacs Episode 9: Time around the world Emacs comes with a built-in world clock: To customize displayed timezones, use: Each entry requires a valid timezone string (as per entries in your system's ) and a display label. I wanted a slightly different experience than the built-in command ( more details here ), so I built the time-zones package. is available on MELPA , so you can install with: Toggle help with the key add cities with the key. Shifting time is possible via the / keys, in addition to a other features available via the help menu. 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 ;)

0 views
xenodium 2 weeks ago

My 2025 review as an indie dev

In 2024, I took the leap to go indie full-time. By 2025, that shift enabled me to focus exclusively on building tools I care about, from a blogging platform, iOS apps, and macOS utilities, to Emacs packages. It also gave me the space to write regularly, covering topics like Emacs tips, development tutorials for macOS and iOS, a few cooking detours, and even launching a new YouTube channel . The rest of this post walks through some of the highlights from 2025. If you’ve found my work useful, consider sponsoring . Now let’s jump in. For well over a decade, my blogging setup consisted of a handful of Elisp functions cobbled together over the years. While they did the job just fine, I couldn't shake the feeling that I could do better, and maybe even offer a blogging platform without the yucky bits of the modern web. At the beginning of the year, I launched LMNO.lol . Today, my xenodium.com blog proudly runs on LMNO.lol . LMNO.lol blogs render pretty much anywhere (Emacs and terminals included, of course). 2026 is a great year to start a blog ! Custom domains totally welcome. Sure, there are plenty of journaling and note-taking apps out there. For one reason or another, none of them stuck for me (including my own apps). That is, until I learned a thing or two from social media. With that in mind, Journelly was born : like tweeting, but for your eyes only . With the right user experience, I felt compelled to write things down all the time. Saving to Markdown and Org markup was the mighty sweet cherry on the cake. As a Japanese language learning noob, what better way to procrastinate than by building yet another Kana-practicing iOS app? Turns out, it kinda did the job. Here's mochi invaders , a fun way to practice your Kana 2025 brought us the likes of Claude Code, Gemini CLI, Goose, Codex, and many more AI/LLM CLI agents. While CLI utilities have their appeal, I wanted a native Emacs integration, so I simply ignored agents for quite some time. I was initially tempted to write my own Emacs agent, but ultimately decided against it. My hope was that agent providers would somehow converge to offer editor integration, so I could focus on building an Emacs integration while leveraging the solid work from many teams producing agents. With LLM APIs historically fragmented, my hope for agent convergence seemed fairly far-fetched. To my surprise, ACP ( Agent Client Protocol ) was announced by Zed and Google folks . This was the cue I had been waiting for, so I set out to build acp.el , a UX agnostic elisp library, followed by an actual client: agent-shell . I'm fairly happy with how 's been shaping up. This is my most popular package from 2025, receiving lots of user feedback . If you're curious about the feature-set, I've written about 's progress from early on: While agent-shell is the new kid on the block, chatgpt-shell received DeepSeek, Open Router, Kagi, and Perplexity support , in addition to a handful of other improvements and bugfixes. While most of what I share usually ends up as a blog post, this year I decided to try something new. I started the Bending Emacs YouTube channel and posted 8 episodes: Enjoying the content? Leave me a comment or subscribe to my channel . While I enthusiastically joined the Emacs Carnival , I didn't quite manage monthly posts. Having said that, when I did participate, I went all in, documenting my org experience over the last decade . Ok well… I also joined in with my elevator pitch ;) While migrating workflows to Emacs makes them extra portable across platforms, I've also accumulated a bunch of tweaks enhancing your Emacs experience on macOS . While we're talking macOS, I typically like my desktop free from distractions, which includes hiding the status bar. Having said that, I don't want to lose track of time, and for that, I built EverTime , an ever-present floating clock (available via Homebrew). Emacs ships with a perfectly functional world clock, available via , but I wanted a little more, so I built time-zones . Also covered in: For better or worse, I rely on WhatsApp Messenger. Migrating to a different client or protocol just isn't viable for me, so I did the next best thing and built wasabi , an Emacs client ;) While not a trivial task, wuzapi and whatsmeow offered a huge leg up. I wanted tighter Emacs integration, so I upstreamed a handful of patches to add JSON-RPC support, plus easier macOS installation via Homebrew . Details covered in a couple of posts: While both macOS and iOS offer APIs for generating URL previews, they also let you fetch rich page metadata. I built rinku , a tiny command-line utility, and showed how to wire it all up via eshell for a nifty shell experience. With similar magic, you can also get a neat experience. I always liked the idea of generating some sort of art or graphics from a code base, so I built one , a utility to transform images into character art using text from your codebase. Also covered in a short blog post . Emacs is just about the perfect porcelain for command-line utilities. With little ceremony, you can integrate almost any CLI tool. Magit remains the gold standard for CLI integration. While trimming videos doesn't typically spring to mind as an Emacs use case, I was pleasantly surprised by the possibilities . While I've built my fair share of Emacs packages , I'm still fairly new at submitting Emacs features upstream. This year, I landed my send-to (aka sharing on macOS) patch . While the proposal did spark quite the discussion , I'm glad I stuck with it. Both Eli and Stefan were amazingly helpful. This year, I also wanted to experiment with dictating into my Emacs text buffers, but unfortunately dictation had regressed in Emacs 30 . Bummer. But hey, it gave me a new opportunity to submit another patch upstream . Ready Player , my Emacs media-playing package received further improvements like starring media (via Emacs bookmarks), enabling further customizations, and other bug fixes. Also showcased a tour of its features . Hope you enjoyed my 2025 contributions. Sponsor the work. agent-shell 0.25 updates agent-shell 0.17 improvements + MELPA agent-shell 0.5 improvements Introducing Emacs agent-shell (powered by ACP) Introducing acp.el So you want ACP (Agent Client Protocol) for Emacs? Bending Emacs - Episode 1: Applying CLI utils Bending Emacs - Episode 2: From vanilla to your flavor Bending Emacs - Episode 3: Git clone (the lazy way) Bending Emacs - Episode 4: Batch renaming files Bending Emacs - Episode 5: Ready Player Mode Bending Emacs - Episode 6: Overlays Bending Emacs - Episode 7: Eshell built-in commands Bending Emacs - Episode 8: completing-read time-zones now on MELPA. Do I have your support? Emacs time-zones WhatsApp from you know where Want a WhatsApp Emacs client? Commits: 1,095 Issues created: 37 PRs reviewed: 106 Average commits per day: ~3 EverTime - An ever present clock for macOS acp.el - An ACP implementation in Emacs lisp agent-shell - A native Emacs buffer to interact with LLM agents powered by ACP diverted - Identify temporary Emacs diversions and return to original location emacs-materialized-theme - An Emacs theme derived from Material homebrew-evertime - EverTime formula for the Homebrew package manager homebrew-one - Homebrew recipe for one homebrew-rinku - Homebrew recipe for rinku one - Transform images into character art using text from your codebase rinku - Generate link previews from the command line (macOS) time-zones - View time at any city across the world in Emacs video-trimmer - A video-trimming utility for Emacs wasabi - A WhatsApp Emacs client powered by wuzapi and whatsmeow Journelly 1.3 released: Hello Markdown! agent-shell 0.25 updates Bending Emacs - Episode 8: completing-read At one with your code Bending Emacs - Episode 7: Eshell built-in commands Rinku: CLI link previews Bending Emacs - Episode 6: Overlays WhatsApp from you know where Want a WhatsApp Emacs client? Will you fund it? Bending Emacs - Episode 5: Ready Player Mode agent-shell 0.17 improvements + MELPA time-zones now on MELPA. Do I have your support? Bending Emacs - Episode 4: Batch renaming files Emacs time-zones Bending Emacs - Episode 3: Git clone (the lazy way) agent-shell 0.5 improvements Bending Emacs - Episode 2: From vanilla to your flavor Bending Emacs - Episode 1: Applying CLI utils Introducing Emacs agent-shell (powered by ACP) Introducing acp.el So you want ACP (Agent Client Protocol) for Emacs? Diverted mode Who moved my text? Dired buffers with media overlays Brisket recipe A tiny upgrade to the LLM model picker Emacs elevator pitch Emacs as your video-trimming tool macOS dictation returns to Emacs (fix merged) Writing experience: My decade with Org Interactive ordering of dired items Patching your Homebrew's Emacs Plus (macOS) Emacs send-to (aka macOS sharing) merged upstream Mochi Invaders now on the App Store Markdown is coming to Journelly EverTime available via Homebrew Journelly 1.2 released Ranking Officer now on the App Store Awesome Emacs on macOS Journelly 1.1 released LLM text chat is everywhere. Who's optimizing its UX? A richer Journelly org capture template Journelly: like tweeting but for your eyes only (in plain text) Journelly vs Emacs: Why Not Both? The Mac Observer showcases Journelly Journelly open for beta DeepSeek, Open Router, Kagi, and Perplexity join the chat Keychron K3 Pro: F1-F12 as default macOS keys E-ink bookmarks Sourdough bookmarks Cardamom Buns recipe A tour of Ready Player Mode A platform that moulds to your needs Blogging minus the yucky bits of the modern web

0 views
xenodium 3 weeks ago

Journelly 1.3 released: Hello Markdown!

Journelly 1.3 available on the App Store Journelly feels like tweeting but for your eyes only. A fresh take on frictionless note-taking or journaling for iOS, powered by plain text (Markdown + Org). Check out journelly.com for details. Journelly v1.3 brings Markdown support (the most requested feature) along with Simplified Chinese localization and other new enhancements. By far the most requested feature. Thank you to everyone who reached out, shared interest, and helped beta test early builds. Whether you're a fan of Markdown or an Org-mode enthusiast, Journelly lets you store entries in your preferred format. You can now choose your favorite markup on first launch or via the app menu. While on topic, I also run lmno.lol , a Markdown-powered blogging service. Simple and focused, without the frustrating parts of the modern web. Custom domains welcome. My xenodium.com blog runs off lmno.lol . Simplified Chinese (简体中文) is now available, joining Journelly's list of supported languages: A home screen widget is now available, offering quick access to three key actions right from the home screen. Prefer clear buttons over swipe gestures? You can now enable Discoverable Mode under “Menu > View.” This new mode makes features more visible and easier to navigate, perfect for folks favoring more explicit interaction over gestures or subtle hints. For Org users: Journelly now renders both quote and code blocks. The entry list received a little refresh to make better use of screen space. Bottom-aligned controls also make for easier one-handed use. Since launch , Journelly has remained a single-payment app. No subscriptions . I get it, subscriptions are no fun. That said, sustainable development is tough without regular downloads . I'm hoping the new Markdown support helps Journelly reach a wider audience. Help Journelly grow: Hope you enjoy the v1.3 update. Thank you for using Journelly and supporting indie development 💛💙❤️ Save cooking recipes, movies, music, restaurants, coffee shops… Jot down your thoughts. Save your favorite quotes. Use it as a journal, memo book, or notes. Write your shopping lists. Document your travels. Simplified Chinese (简体中文) Leave a review on the App Store . Share Journelly with your friends.

0 views
xenodium 3 weeks ago

agent-shell 0.25 updates

It's been a little while since the last agent-shell blog post detailing changes , so we're naturally due another one detailing the latest features. A native Emacs shell to interact with any LLM agent powered by ACP ( Agent Client Protocol ). Let's go through the latest changes… The biggest change is the new experimental viewport/compose mode. While agent-shell's comint shell experience has its benefits, some folks may opt for a more familiar buffer experience, that is less shell-like. There are perhaps 3 defining characteristics in the new viewport/compose feature: A dedicated compose buffer : You get a full, multiline buffer dedicated to crafting prompts. I personally find this mode of operation more natural (no need to watch out for accidental submissions via RET), but also opens up the possibility to enable your favourite minor modes that may not play nice with . You can launch compose buffers via , edit your prompt, and when you're ready, submit with the familiar binding. Viewport : I've experimented with shell viewports before and also added a similar experience to chatgpt-shell . This compose/viewport UX quickly became my primary way of interacting with non-agent LLMs. This is a read-only buffer typically displaying the latest agent interaction. Use to navigate through current interaction items. Use to switch through pages/interactions. Auto-modal : Compose and viewport modes complement each other and offer automatic transition between read-only and editable (compose) buffers. From a viewport, you can always press to reply to the latest interaction. When replying, you automatically go into edit/compose mode. When submitting via , you automatically transition into viewport (read-only) mode. While you can use at any time to compose multi-line prompts and send from the shell, to get the hybrid experience, you need to enable with . From then on, will favor the experience. You can always jump between viewport and shell with . buffers now offer the ability to queue additional prompts if the agent is busy. Use and to queue and remove requests. You can now change models via ( ), when supported by the agent. For Anthropic users, we now have and to set default agent model and modes. You can view available values by expanding shell handshake items. If keen on using defaults for a different agent, please file a feature request . By default, launching via prompts users to select one of the supported agents. You can now skip this by setting your preferred agent ( thank you Jonathan ). While shell-maker automatically prompts users to save content when killing buffers, its integration was a little clunky with agents. Elle Najt's -specific implementation is now enable by default, saving Markdown transcripts to . When launching new shells, you should see a message like: You can always open the current transcript via . To disable the new transcript generation use: Jonathan Jin introduced , enabling folks to add MCP servers to their agents. For example: You can now search across shell nodes, including collapsed ones. When using isearch ( swiper too), matching nodes are now automatically expanded. When invoking , active region, flymake errors, dired and image buffers are now automatically considered and brought over to buffers to be included while crafting prompts. There's one more. From a viewport buffer, selecting a region and pressing "r" (for reply) brings the selection over to the compose buffer as blockquoted text. We've migrated Cursor agent support to use Mike Moore's ACP Adapter . Install with: Thank you to all contributors for these improvements! Beyond what's showcased, much love and effort's been poured into polishing the experience. Interested in the nitty-gritty? Have a look through the 122 commits since the last blog post. If agent-shell or acp.el are useful to you, please consider sponsoring development. LLM tokens aren't free, and neither is the time dedicated to building this stuff ;-) Paul Nelson built agent-shell-attention.el offering a mode line attention indicator. Julian Hirn built agent-review introducing a streamlined workflow. #106 : Use replace-buffer-contents instead of erase-buffer/insert #127 : No longer possible to select the Anthropic model used by Claude Code #142 : [bug] Crash during message streaming: markdown overlay receives nil positions #143 : gemini 0.17.1 requires authMethod to authenticate (fix by Andrea ) #144 : Make collapsible indicator keymap customizable #145 : Unable to enter Plan Mode until after first message is sent #150 : Warning (undo): Buffer 'Codex Agent @ …' undo info was 25664948 bytes long #154 : Gemini CLI doesn't need authorization if already logged in #125 : Fix error when viewing proposed diffs ( Nat Page ) #129 : Support setting a preferred agent config ( Jonathan Jin ) #138 : Enable specifying MCP server configurations via custom variable ( Jonathan Jin ) #139 : Document MCP server config functionality ( Jonathan Jin ) #140 : README: Add MELPA badge + expand install instructions ( Jonathan Jin ) #141 : Add keybindings to cycle/set session mode ( Jonathan Jin ) #149 : Use fixed-pitch for ascii art logos ( Mark A. Hershberger ) #155 : Give the new custom flag to gemini for skipping the authorization ( ccQpein )

0 views
xenodium 1 months ago

Bending Emacs - Episode 8: completing-read

Nearly a couple of weeks since the last Bending Emacs episode, so here's a new episode: Bending Emacs Episode 8: completing-read In this video, we take a look at the humble but mighty completing-read function. We can use it to craft our purpose-built tools, whether in pure elisp or to interact with command-line utilities. Of interest, I also highlighted the great elisp-demos package, which extends your help buffers with sample snippets. Here are some of the snippets we played with: Pick a queen: Our own hashing function with an algo picker: A first look at integrating completing read with a CLI util: Also got creative with BluetoothConnector on macOS and . Some of my completing-read uses: Emacs: quickly killing processes . Emacs: insert and render SF symbols . macOS open with . macOS set default app . macOS share (the unhinged way). ready-player search. 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 ;) Emacs: quickly killing processes . Emacs: insert and render SF symbols . macOS open with . macOS set default app . macOS share (the unhinged way). ready-player search. Hope you enjoyed the video!

10 views
xenodium 1 months ago

At one with your code

While in the mood to goof around with Emacs, CLI, and image rendering , I've revised an idea to generate some sort of art from your codebase (or any text really). That is, given an image, generate a textual representation, potentially using source code as input. With that, here's one : a utility to transform images into character art using text from your codebase. Rather than tell you more about it, best to see it in action. Just a bit of fun. That's all there is to it. While I've only run it on macOS, 's written in Go, so should be fairly portable. I'd love to know if you get it running on Linux. The code's on GitHub . If you're on macOS, I've added a Homebrew on GitHub , so you should just be able to install with: Having fun with ? 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 1 months ago

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 1 months ago

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 1 months 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 1 months 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 months 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 2 months 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 2 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 2 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 2 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 3 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 3 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 3 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 3 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 3 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