agnos.is

The agnos.is blog

Published: 2024-02-12T14:23:06+01:00

The capsule build system now uses the Just tool to make it easier to use gempost.

Gempost (GitHub) Just (GitHub)

The entire current content of the file is below. I will expand this over time to enable templating of static pages, and other things.

@ensure:
	which gempost >/dev/null 2>&1  || cargo install gempost
	which tera >/dev/null 2>&1 || cargo install tera-cli

build: ensure
	gempost build -c ./capsule-main.yaml
	gempost build -c ./astroponic-garden.yaml

post TITLE: ensure
	gempost new -c capsule-main.yaml -t "{{TITLE}}" "{{ lowercase(replace(TITLE, ' ', '-')) }}"

plant TITLE: ensure
	gempost new -c astroponic-garden.yaml -t "{{TITLE}}" "{{ lowercase(replace(TITLE, ' ', '-')) }}"

deploy MESSAGE: build
	git add .
	git commit -m "{{ MESSAGE }}"

Filed under: capsule

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-02-24T20:02:14+01:00

My beliefs in open source extend further than just software. I believe the principles behind the free software movement can be applied to most industries, in and out of the hardware space. Two things I have strong opinions on, that I've noticed myself repeating over the past few years:

  • 90% of what Apple does should be illegal.
  • Anything that can be connected to or interacted with in some way should be required to have a public API or standard.

These would be fundamental regulatory changes that would drastically alter society in ways both big and small.

90% of What Apple Does Should be Illegal

Something of a ridiculous clickbait way of putting this idea. In reality, it is more about a consumer-first focus and protecting the rights of the users of devices and software. The Digital Markets Act of the EU, as well as the EU forcing USB-C and replaceable batteries in mobile phones are perfect examples of this idea in action. Especially the Digital Markets Act.

Apple markets themselves as a company that produces user-friendly and privacy-respecting products. I argue that this is not true. Apple produces products that are EASY TO USE, which is different than user-friendly. Apple's products are actually user-hostile, locking you in to a specific way of doing things, and not playing well with any kind of interoperability. Almost everything they do is profit-driven, not user driven. This is noticeably true in their hardware. Dongles, removal of the headphone jack, strange proprietary cables.

Regulation fixed this.

More regulation is needed. Right to repair, for example, should not be done by companies out of the goodness of their hearts. It should be a legally required mandate.

Everything Should Have an Open Standard

Or, the Death of Reverse Engineering

I came up with this thought after dealing with many devices that can only be fully configured or used by making use of some official app (which almost always is hoovering up data). It is absolutely ridiculous that things you own cannot be used the way you want without submitting to onerous and possibly illegal terms of service. Everything has an app now. Almost everything doesn't need an app. Most internet-of-things (IoT) devices don't need to be connected to a cloud.

Local-first, open standards first. If it can be connected to, the manufacturer should be required to publish (or adhere to) some standard API/specification and make it possible to connect to and manipulate the device using that API or specification. A simple example is an electric scooter. Many of them have official apps that allow changing of acceleration sensitivity, max speed, etc over Bluetooth. There is zero reason for this to require a specific app. This could be both a standard protocol AND standard API.

Why should something like this be required?

  • Product longevity. Less e-waste.
  • Increased competition. Businesses can build on top of one another with new features.
  • Real ownership. No more buying a thing to own but not REALLY owning it.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-02-15T20:42:38+01:00

Update: HTML fonts now changed to sans-serif, with dotted underline links.

Thanks to the power of the wonderful tool gem-web-cli, the HTML version of this website is now accessible!

https://www.npmjs.com/package/gmi-web-cli

This tool does 99% of the heavy lifting. It converts the gmi files in-place to HTML that looks pretty much like the native Gemini rendering does. I kept the basic style, because I think it looks fine. I may change the fonts around, as I'm not a huge fan of the serifs. The CSS is simple yet doesn't look entirely out of place in the modern world, and it is mobile-friendly.

Anatomy of the Website Generation

I integrated gmi-web into the repository's Dockerfile and the justfile that does all the templating and building. The gmi-web does not handle every link on the site, so some light application of sed was required to get all the links properly converted to their corresponding HTTP versions. The gemlog and individual blog posts have its own specific sed fixes, and additionally a “hostname fix” is applied across all pages on the site to make sure that any agnos.is links point to the HTTPS site and not the Gemini site.

This makes gem-web-cli the third main tool used in the creation of this site, along with gempost and tera-cli. The justfile has grown to 115 lines, which is still miniscule compared to writing a full application to manage this in a more specific/“elegant” fashion. I may reach that point anyway, though, as tera-cli has some very specific limitations that make it annoying to template the page files. Namely, templating pages requires kludging them into a YAML format so the tera CLI tool will understand how to template them.

I might wind up creating just a more general version of the tera CLI tool to fit my needs, rather than a full-on set of changes. But in any case, with the HTML version of the website available, the main goals of this project are now complete! The website will continue to evolve and be updated, but I think I can go a long way with the current setup.

Features of this Site

Working with the site is still pleasant:

  • Fully static website, generated in both HTML and Gemtext.
  • Served over Gemini and HTTP.
  • All content managed in Git.
  • Updates deployed in seconds after push.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-03-13T21:08:04+01:00

Story: The Quiet Fire

I have finally gotten around to updating the writing and world-building page with a short story. This is an story I wrote recently. It paints a vague image of a desolate, apocalyptic future, but tinged with hope. The intention of the story is that it speaks multiple messages, some of which the reader themselves might have to discover in their own minds. I wrote the story for a specific reason, and it has a specific meaning to me. Several meanings, in fact. But hopefully, by sharing it, people can find their own meanings too. It is a melancholy story, but with a hopeful nod towards an undefined future.

I am also building up the list of campaign settings and other fictional worlds I've created over the years, which will be added to the writing section soon as well (very likely as links to external sites). Many of these campaign settings have been hosted on various forums or self-hosted wiki sites over the years, but I've taken them all down by this point, or they were turned off by the hosting provider. I would like to host their content on Gemini, but at least in the beginning, it will be far easier to get them up and running more or less in their original forms (Gollum wikis and statically generated websites).

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-02-14T22:36:15+01:00

It is so annoying to encode video in the modern age. There's dozens of different codecs, and dozens of different containers. I am using Pitivi to edit and encode a video that should run everywhere. The first attempt ran on my machine but not phones. The next attempt ran almost everywhere, except it doesn't have sound on Macs or iPhones. The third attempt was just janky and didn't work at all.

  • Attempt 1: Pitivi MP4 with H264 and MP2 audio
  • Attempt 2: Reencode above into MP4 using vLC
  • Attempt 3: MP4 with H264 and AC-3 audio

The fourth attempt will be MKV H264 converted to MP4 with ffmpeg. If THAT doesn't work, I will do something more exotic like WebM or even Ogg Theora! There is an Ogg JS plugin which can be embedded into web pages to play Ogg files...

This post will be updated once a successful combination of codecs and steps to produce a video that works everywhere has been found.

2024-02-19: Update – AAC Audio Works!

The video had to be encoded with AAC audio to work properly on Apple devices out of the box. The magic combination for the future is thus H.264 and AAC audio.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-02-10T22:19:42+01:00

After having spent the past few days getting the capsule set up and wiring up build tools to automate updates to the site, I am almost ready to declare the basic design of the capsule complete.

Organized!

With Gemini being as purposefully limited as it is, there is only so much “design” one can do. However, there are still cleanliness and organizational concerns for the content. I have grouped and arranged things in what I think is a logical manner, and will use this as a foundation for adding more content to the capsule.

I have a simple homepage that allows visitors to drill deeper quickly. I envision adding multiple top-level links to different interest categories, beyond just the focus on open source software. In addition to software development, I have an interest in micromobility, electric vehicles of all sorts, creative writing and world building, and more. As I hope to make this site my main digital presence in the world, I want to explore all of those things here.

What Do I Plan to Use Gemini For?

Some people use Gemini as a dumping ground for interesting stuff they find. Others use it as a new way to gather people together online in smaller, focused communities. Others are using it as a place to make posts that are more rough around the edges, and not ready for “prime time” on the regular Web.

I want to use Gemini as a place to create a content-driven digital presence. This sounds lofty, but all it really means is that I intend for it to be my primary means of presenting myself to the online world. It's a cross between marketing myself, getting my thoughts into the open, journaling away troubles, and having something to keep idle hands busy (but not too busy).

During the entirety of this design and setup phase, I noticed that my focus is still mainly content-driven. I have spent more time thinking about -WHAT- to put up here, and gathering the motivation to do it, than thinking about -HOW- to arrange what I've put here. And I consider that a win.

Filed under: capsule, gemini

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-02-12T00:26:51+01:00

The Astroponic Garden section of my capsule now has its own dedicated Gemfeed.

The Astroponic Garden

The garden is my approach to “digital gardening” in Geminispace. I use it as a small stream of consciousness to think up topics or tasks for the capsule. The addition of the dedicated Gemfeed was achieved by creating a secondary gempost config file and pointing it to a new posts directory for the garden, and then building the capsule using the main config file along with the secondary config file. This was slightly tricky, as simply running gempost build will wipe out the output directory.

  • First, I run gempost build using the main config file.
  • I had to make a separate output directory for the garden.
  • Then I rsync it into the main output directory.

I also had to add a .gitignore file to garden/static, which is the directory that holds any static files for the astroponic garden (there are none). The static files directory is required, so I had to give it something, and giving it the main static directory will copy all of the site's content over twice.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-03-05T19:55:51+01:00

The AI-driven text-based adventure game has finally hit an important milestone: the implementation of hyper-specific GBNF grammar constraints at runtime!

https://git.agnos.is/projectmoon/ai-game

This allows restricting the output of the LLM to very specific values at a per-field level. It took quite a long time to implement this properly, as I don't have that much free time on my hands due to family obligations and job searching. The implementation went through several major iterations before I finally got it right.

  • Basic limiting of primitive fields.
  • Limiting fields but comparing based on rule text.
  • Proper recursive output of rules and sorting to de-duplicate.

The addition of this feature also addresses a bunch of shortcomings in the original implementation of the derive macro. Overall, I am happy with how it works, though not necessarily happy with how long it took.

How the GBNF Derive Macro Works

Before explaining how the limiting works, a quick overview of the derive macro itself is useful. The macro, when added as a derive attribute on a struct, will add a function to the type itself called to_grammar. This function produces a set of valid GBNF rules that allows the LLM to output values according to the shape of the annotated type.

Example:

[derive(Gbnf)]

pub struct CommandResponse {
    pub valid: bool,
    pub text: String
}

//...

let grammar: &'static str = CommandResponse::to_grammar();

When this grammar is given to the LLM, its output will be a JSON value that matches the struct, which can be directly deserialized by serde. This is very powerful, but suffers from a big limitation, which also plagued the original hand-rolled GBNF rules: With a string value, the LLM could still output nonsense, even though it was constrained to a JSON format. So, if it was instructed to set a field to an ID in the scene, it might do that, or it might not.

This is where the new helper attribute #[gbnf_limit] comes in. By adding this helper attribute to a field on a struct annotated with #[derive(Gbnf)], A corresponding “limit struct” is created, which allows the developer to give a set of valid values the LLM can produce for the given fields.

The New GBNF Limit Implementation

The final implementation of this feature makes use of the following:

  • A dynamic trait called GbnfLimitedField.
  • A custom-generated limit struct, created by the derive macro.
  • A new addition to the GBNF types: GbnfLimit.

The GbnfLimit type is a nested enum that mirrors the structure of the type it was derived from. This limit is passed into the initial GbnfComplex type at the root of the GBNF rule hierarchy, and as rules are recursively generated, each rule type looks into the limit struct (or its nested descendants) to see if its values should be limited. If so, the type is wrapped in an opaque “limited GBNF type” that implements the standard AsGrammar trait. These wrapper trait implementations reference the underlying type to create a limit rule, which is either the actual limited values, or a set of nested limited values (if a field of a subtype is limited).

The derive macro takes care of generating the limit struct itself, along with its implementation to convert the limit struct into a GbnfLimit instance. This was the easy part. Almost all of the complexity lay in the code for actually turning GBNF rules into the final text that would be fed to the LLM.

Implementing the limitation feature made very clear numerous flaws in the original GBNF macro implementation, which have now been addressed. Most importantly, the GBNF rules are now generated recursively, with each rule 0 or more dependent rules. This allows proper handling of optional fields, list fields, and of course, limited fields (as well as optional limited fields, and list limited fields!).

Next Steps

The next steps are pretty straightforward:

  • Spin the GBNF code into its own crate, to make it available to others.
  • Attempt to get rid of the requirement to use Boxed dynamic traits for the limit struct.
  • Improve the error reporting from the derive macro.
  • Make proper use of the limiting feature in the game itself!
  • Tests! Game is getting complicated enough that it needs them.

The initial use of the feature in the game itself will simply constrain the LLM to pick from any IDs present in the scene. Later, some prompts will be rewritten, and a more accurate list of IDs can be given to the LLM.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-02-12T21:59:20+01:00

I have been hard at work enhancing my justfile (for the just build tool/command runner) into a barely-readable mess so that it can template the pages of the capsule. This gives a mostly-proper navigation experience throughout all pages on the capsule. There should be a link at the bottom of every page called “Return Home” or “Go Back” or something like that.

The templating of pages is still very limited, so right now the build process only adds the Go Back link to every page. Eventually, I will try to expand the templating to have per-page information and per-page templates (I would probably want a different template for the section pages, for example).

The next large item on the agenda is to get the capsule accessible over HTTP. I am debating on writing my own converter, or attempting to use/modify one that already exists. So far, all of the ones I've evaluated are either too complicated, or do not work exactly how I want them to. I need a converter, because the HTTPS homepage of agnos.is is a static file (installed by the matrix-ansible-deploy playbook). I do not want to mess with that setup, so running a transparent Gemini –> HTML proxy is currently out of the question.

Finally, as part of this update, I've started categorizing the blog posts. This is not really exciting, but could be useful later for building pages that list articles by category.

Filed under: capsule, gemini

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-02-26T20:31:26+01:00

Technoethical Bluetooth 4.0 Adapter

This Bluetooth adapter is one of the only dongles on the market that can run on a fully free OS (AKA, Linux-libre kernel) and isn't stuck on an ancient version of the Bluetooth protocol. I used one for two years before my repeated abuse of it made it completely and utterly fall apart (I bent it a lot and accidentally ripped it out of the USB port one too many times). I have now acquired a replacement.

I found it via the Free Software Foundation's Respects Your Freedom initiative, a list of products that are certified to work on fully free hardware. It's surprisingly hard to find out if Bluetooth dongles work on the libre kernel. Many Bluetooth dongles, even the ones that explicitly support Linux, actually require non-free firmware.

Respects Your Freedom

License: CC-BY-SA-4.0.

Written by: @[email protected]