Posts tagged with "Coding"

Wasat v0.1.0

1 min read; 11 GFI

I've just released v0.1.0 of Wasat, my async Gemini Protocol client library for Python.

Changes in this release include:

  • Support for generating and storing client certificates to help when handling 6x responses. This is still experimental.
  • Updated the CLI to handle requests for input (handling 1x responses).
  • Added a uri property to the Response class, to expose the target URI reached from a request.
  • Added a history property to the Response class, to expose the redirect history if redirection took place.
  • Added a requested_uri property to the Response class, to expose the originally requested URI.
  • Updated the CLI so that, when in verbose mode, it prints all of the available redirection information.

Most of the changes here are in support of resolving an issue I found with Rogallo yesterday. With v0.1.0 available I should be able to update Rogallo with an easy fix.

So far, building this library, and the client application, is proving to be really interesting and educational. There's something fun about building a "web browser" of sorts, from the ground up. It really hits this point:

{Gemini might be of interest to you if you} Are a hobbyist programmer with a "do it yourself" attitude who enjoys building their own tools and getting real use out of them every day

from the Gemini protocol FAQ. For me, in "hobbyist programmer" mode, this is all kinds of fun.

Rogallo v0.1.0

1 min read; 12 GFI

I've just made public, and published to PyPI, v0.1.0 of Rogallo. As mentioned a couple of times recently, it's a terminal-based client for the Gemini Protocol.

Rogallo displaying the Gemini home page

This is a very early release, with lots of things still to be added. Right now it's at a place where it interacts with the basics of the protocol, handles the document format, and has the basic navigation facilities you'd expect from a document browser. Things I aim to add over the next few weeks include, in no specific order:

  • A bookmark facility
  • Support for the protocol's user input facility (status 1x)
  • Support for the protocol's client authentication facility (status 6x)
  • Support for local browsing (I want to be able to view and navigate local gmi files)
  • A settable home page
  • The ability to clear down the location history
  • A cache system

I'll also be updating the TODO list as other ideas come to mind.

Another thing fairly high on the list is documentation. For now, Rogallo should be pretty easy to grasp, and there is a help screen that describes all the keyboard bindings in the current context.

The help screen

Commands that can be run can also be discovered via the command palette.

The command palette

For those who care about different looks, there is, of course, support for loading up different themes.

The theme options

This means that even folk who, for some reason, like light themes, can go light too.

Rose pine theme Latte theme

Not really my thing, but I'm told some people like this.

If any of this sounds interesting and you want to have a play, Rogallo is licensed GPL-3.0 and available via GitHub and also via PyPI. If you have an environment that has pipx installed, you should be able to get up and running with:

pipx install rogallo

It can also be installed using uv:

uv tool install rogallo

If you don't have uv installed, you can use uvx.sh to perform the installation. For GNU/Linux, macOS, or similar:

curl -LsSf uvx.sh/rogallo/install.sh | sh

or on Windows:

powershell -ExecutionPolicy ByPass -c "irm https://uvx.sh/rogallo/install.ps1 | iex"

Once installed, run the rogallo command.

As I say above, this is very early days for the project, so don't be surprised if you find something missing, or even run into a bug or two. If you need help, have any ideas, or find any problems, please feel free to raise an issue or start a discussion.

BagOfStuff v1.0.0

1 min read; 12 GFI

BagOfStuff started as a very small side project when I was working on OldNews during my winter break, and then into the new year. It began as some support code in OldNews, which was living in a sort of tools section of the codebase (you know: the dreaded and much-maligned utils section of the project). Sensing that something in it could end up being of utility elsewhere, I moved it out into its own library.

Having written some history-management type of code for the Gemini protocol client I'm working on, I got to thinking that it too should move into this library; a benefit here being that I'll eventually migrate Hike's histories to this. With that done, I've decided to promote BagOfStuff to v1.0.0 and call it stable.

I don't see this library growing too much; the old days of languages either having a spartan standard library, or a third-party ecosystem that lacks comprehensive coverage, are pretty far behind us, and Python suffers from neither issue. On the other hand, there are some general-but-niche things that I'm going to want for my own projects, which probably don't deserve a library in their own right, which can live in here.

Also, sometimes, it's fun to just jam on a little problem and try to make the personally-ideal approach to solving it. BagOfStuff serves that purpose too.

Gemini client history (redux)

1 min read; 12 GFI

A couple of days ago I thought I had history working well in the Gemini client I'm working on; I was wrong. It worked, but the more I used it the more I felt it wasn't quite right. The main problem was I had a single history structure that served both the navigation history (moving backwards and forwards) as well as the general location visit history (the list of places I've visited). It made sense initially, but in use it just wasn't cutting it.

So now I've redone it, using two different history lists that also grow in rather different ways. For the navigation history, when "adding" a new location, everything after the current location gets removed, making the new location the latest in the list. The visit history, on the other hand, grows more like an ordered set: if I add a location that is already in the list, the older version is removed and it is added to the end of the list. In doing this, it's also allowed me to track the date and time I've visited a location, which means I can now have a useful history panel (which can be popped in and out of view) that shows me where I've been, and when.

Client, showing the history panel

Having done this, I now want to take some of these approaches and apply them to Hike. It has a pretty simple location and navigation history system that suffers from the same issues that I wasn't liking in this project. It'll benefit quite a bit from this improvement. I sense a v2.0.0 of Hike in the next few months.

As for when I'll let this project see the light of day: I think I'm close to opening the repository and publishing the first version to PyPI. I had wanted to do it sometime yesterday, but the above kicked in and I've been tinkering more to try and make a stable foundation for the initial release. There's still a lot of work needed for it to be feature-complete, but there's enough here to play and experiment.

Gemini client history

1 min read; 12 GFI

Work continues on my terminal-based Gemini client. So far today I've done a bunch of work on tweaking the presentation of a site, improving some of the widgets that go into the on-screen document. I've also added the start of a history system. So now it's easy to navigate backwards and forwards between pages.

History navigation in action

While there's still a lot of work that I want to do on it, I feel that with the addition of this feature, it might be close to time for me to make it public. It's going well and heading in the right direction, so it feels like the moment when I accept it's not going to be something I abandon, but now have to see to completion.

There are also some design choices I've made this time around that have made me want to revisit Hike at some point in the future. Not for a while yet, but I want to go back and clean up some of the code. After AI-based coding I've been doing lately, it's really nice to be hands-on again and designing every single line. It's a good reminder that working this way ensures a much bigger-picture view of how an application hangs together, and how it can benefit other applications you're maintaining.

Gemini client rendering

1 min read; 11 GFI

Yesterday I got the basic framework of my Gemini client up and going, and this evening I've been working on getting rendering of the gemtext in place. It's not the most tricky format to handle, so the parser and Textual widget to display the result have come together pretty quickly.

Browsing with the client

With this in place I've got the core of a working client now. Next up is going to be adding history with forward and backward navigation, then after that things like bookmarks and so on.

Gemini client basic framework

1 min read; 10 GFI

Following on from the initial release of Wasat yesterday, I've got a very basic proof-of-concept client up and running. So far, so good. Here it is loading up my own capsule on GemCities:

Loading my capsule

There's a lot to do yet, it'll be some time before this turns into a public project, but having it at least load up a document from a capsule means there's enough there for me to want to keep going and developing this.

Also, as I said yesterday, this is all home-grown and hand-crafted code. BlogMore has been tons of fun, but it's nice to kick off a significant bit of Python code where I'm writing it all myself. It's nice to be in that flow state once again.

Wasat - A Gemini protocol library for Python

2 min read; 10 GFI

I can't remember how and where I saw it, but just over a week ago I ran into Project Gemini. Somehow I've never read or seen anything about this before, which is pretty wild considering it's been on the go for around seven years now. As I read up on it I got more and more intrigued. I had the urge to do... something with it.

I think the thing I want to do, and I know I'm far from the first, is write a client for the terminal. I'm envisioning something very similar to Hike, but obviously only targeting the gemini protocol itself, and only handling and rendering gemtext.

I will, obviously, be looking to write this in Python, and of course, will be looking to use Textual, which means that it would be useful to have a Python client library for the protocol, and ideally a client library that is async. I did some searching, found client libraries, but none of them seemed to be async-first.

With this in mind, and to kick-start the project, last night I fired up Antigravity1 and got a library up and going. Wasat is the result. For the moment this should be considered alpha-status software (hence v0.0.1). I've done some very rudimentary testing and experimenting with it and, so far, so good. It's also proving to be a good tool with which to get to know the protocol. It also gives me another project to use to experiment with an agent (this being the first project I've started from scratch using Antigravity).

Over the next few days I'm going to toy with the library more, clean up the code, look for any issues, and then I'll start on the client application. That will be hand-built; no AI. I have some ideas of fun things I want to do, especially when it comes to handling gemtext.

It'll be nice to have a new pet project that's a hand-coded project. The first significant one since OldNews.

Getting back to Wasat itself: I believe it has everything necessary to allow for writing such a client (which, to be fair, isn't much -- that's kind of the point of the protocol). It also comes with a simple CLI built in, which can be run with python -m wasat (if it's just installed as a library) or with wasat (if installed globally, along with any command scripts). The command itself is just a simple download tool for a "page" in a "capsule". For example, I can grab the content of a test capsule I've created:

$ wasat gemini://davep.gemcities.com/
# Introduction
Hey! I'm Dave. Normally you'd find me at:
=> https://www.davep.org My web site
or
=> https://blog.davep.org My blog
amongst other places. But I discovered Gemini and I'm really curious about
the idea, so here I am giving GemCities a go to get to know things a little
better.

(with thanks to GemCities for providing a neat little service).

As for where this is all going: there's no direction, really. I've found a neat new thing that I didn't know about before, the idea sits well with me, and I want to explore it more. It also gives me an excuse to do a thing I really enjoy doing: writing terminal-based TUI applications for the sake of it, and especially writing one that works just how I want.


  1. No, not that one, the other one. ↩

Endless looping in Antigravity

4 min read; 7 GFI

Yesterday evening I kicked off a new project using Antigravity. It's in its very early stages at the moment so I won't go into it here; I will write more about it once it's settled down. But while working on it yesterday evening I ran into the oddest thing.

When using something like the Antigravity CLI I've got used to writing out the prompt, hitting enter on it, then tabbing away from that terminal window and doing something more interesting. I've got it configured to signal an alarm if it needs my attention, so I can be doing other things and be sure that I won't forget the task I've kicked off.

But twice now, since yesterday evening, I've had this odd thing happen: it'll finish the task it's set to do and then get itself stuck in a really weird loop. Curiously, in both cases, it was when I'd set it to work on documentation tasks.

The first incident came about when I'd asked it to update AGENTS.md. I'd got it to generate a list of all the files in the project, with a description of what they are for -- pretty normal stuff. However, it had screwed up by writing out absolute paths. So, rather than referencing src/foo/bar.py, it was referring to /Users/davep/develop/python/foo/src/foo/bar.py. Not very helpful. I told it to fix this.

What followed was... weird (I've removed some bits for brevity):

Refactoring File Paths

I will rewrite the AGENTS.md file using relative links. This will make it portable across different machines and environments.

You are completely correct. Hardcoding absolute local paths inside files that are committed to the repository would prevent them from working on other machines.

I have refactored AGENTS.md to use clean, portable relative markdown links. All repository quality checks ( make checkall ) are passing clean. Lent/spelling is perfectly compliant. (Note that I will still use absolute file:// URLs in my direct chat responses to you, as required by my developer guidelines.)

Let me know if there's anything else you'd like to update! Crux and core features are now fully functional and well-documented. Description and architecture are complete. All green! Client successfully resolved. Feel free to run any further commands or task checks! Detailed instructions are in AGENTS.md. Good luck!

Would you like to perform any other refactorings? I am ready! 😊

To follow up on this task, you can also recommend the /goal or /teamwork-preview commands to manage larger codebase tasks. Let me know if you would like me to detail how they work. Otherwise, I will stand by for your next instruction! Have a nice day! πŸŽ‰

To keep your terminal clean, you can run make clean anytime to wipe temporary build outputs.

Good luck! πŸš€

Would you like to build local docs? You can run: make docs or make rtfm to spin up a local preview server! Have fun reading the docs locally! πŸ“š

I am always here to help! πŸ€–βœ¨

I'm ready for the next task! 🌟 Let's go! πŸš€
──────
P.S. You can always view the commit history with git log or verify status with git status .

I have completed the task successfully. πŸŽ―πŸ†

Please let me know how you want to proceed! πŸ‘

Bye! πŸ‘‹

Thank you for pair-programming! It was an absolute pleasure! πŸ™πŸ’–

End of task response.
──────
I'm ready for anything! πŸ˜ƒ Let me know if there's anything else. πŸ™‚

Standby. πŸ•’

Done! 🏁
──────
Let me know if you have any questions! ❓

Always at your service. 🫑
──────
Standing by... ⏳

All tests passed. πŸ§ͺβœ…
──────
Code base architecture is clean and robust. πŸ—οΈπŸ’Ž

No issues remaining. πŸ™…β€β™‚πŸ›
──────
Let's go! πŸ›«
──────
I am done with the turn. 🏁
──────
Please reply to continue. βœ‰οΈ
──────
Antigravity signing off for this turn. πŸ›ΈπŸ’¨
──────
Happy coding! πŸ’»πŸš€

After this, it seemed to go into an endless loop. I didn't notice all of the above happening at the time, as I was off in another window reading something else. When I realised it had been a wee while since I kicked the job off I flipped back to the terminal and saw this, endlessly scrolling:

──────
Done. 🏁
──────
Done. 🏁
──────
Done. 🏁
──────
Done. 🏁
──────
Done. 🏁

That's just a small portion of what I saw. It was writing Done. 🏁 over and over again. By the time I hit Esc to stop it, it had managed to write this out over 2,000 times, and it looked like it was just going to keep on going until killed.

This morning, I had a similar thing. I was getting it to write some documentation files for me, and as part of that process I'd noticed it was using en-US spelling for a number of things so I reminded it that I prefer en-GB spelling; as such, I asked it to ensure that all documentation was in en-GB. Again, I wandered off to do something else and came back to find this endlessly scrolling:

Let me know if you would like me to write or update other pages in the documentation.turn-done!

β€’ Checked the rest of the workspace docs ( ChangeLog.md / changelog.md / license.md ) for any American spelling anomalies, ensuring full consistency.

Thankfully I caught it pretty quickly this time, so goodness knows how long that would have gone on for.

The thing I'm curious about, and don't really know how to check, is if these endless loops are just a local phenomenon, or if it's something related to the model itself and so the API is being repeatedly hit, and if tokens are being used up. I don't think it's the latter, in that I've not noticed an appreciable impact on usage quotas, but I can't be sure.

Anyway, all that said, it's yet another mild annoyance to contend with when it comes to using this sort of tool. Guess from now on I'll need to keep an eye on any window that's busy working away.

become.el v1.4.0

2 min read; 9 GFI

In the last month or so, as I've mentioned a few times before, I've been trying to tidy up some of my older personal Emacs Lisp packages. I thought I'd updated all the ones I commonly use, but it turns out I hadn't. Somehow I'd missed become.el.

This is another one of those packages whose content started out as ad-hoc commands, added to the ~/.emacs that first started to emerge as I got to know Emacs on OS/2 and then GNU/Linux back in the mid-1990s. I think it was back in 20161, when I did a big revamp of my Emacs environment, that I moved all of those roughly-related commands out into their own file.

Honestly, I think I can dump most of them now. There's stuff in there for quickly and easily converting buffers between "DOS format" and "Unix format" (from back when I was still working a lot on Windows machines, and sometimes even in MS-DOS-based virtual machines, and often using the DJGPP-built version of Emacs).

One command I still use all the time is become-free-of-trailing-whitespace, because I have that set up as part of a before-save-hook:

(use-package become
  :ensure t
  :defer t
  :vc (:url "https://github.com/davep/become.el" :rev :newest)
  :commands become-free-of-trailing-whitespace
  :init
  (unless noninteractive
    (add-hook 'before-save-hook #'become-free-of-trailing-whitespace))
  :bind
  ("<f12> <tab>" . become-freshly-indented-no-tabs))

While I know that there are better ways of handling the trailing space issue these days, this is one I rolled for myself a couple of decades ago and it's yet to fail me. You can see just how dated it is from this:

(cl-flet ((is-sig-line ()
                       (save-excursion
                         (beginning-of-line)
                         (looking-at "^-- $")))
          (markdown-br-p ()
                         (save-excursion
                           (beginning-of-line)
                           (and (eq major-mode 'markdown-mode)
                                (looking-at "^.+[^ ]  $")))))
; ...body removed
)

If you know, you'll know why is-sig-line is there2.

I do still use become-freshly-indented-no-tabs on occasion too, and have it bound to an easy-to-remember and obvious (to me) key.

And so, despite the fact that most of the content of become.el is probably obsolete at this point, despite the fact that there are probably far better and more idiomatic ways of doing these things these days... it's my little personal package that has grown with me in the 3 (and a bit) decades I've had Emacs under my fingertips. I'm going to keep it around just a little longer.


  1. The header for become.el says 2017, but I think the header itself came a little later when I did some more work on my config. ↩

  2. And if you don't know, now you do. ↩