agnos.is

The agnos.is blog

Published: 2025-01-18T09:04:30Z

What is Home? Part II

Home is a place, a feeling. It's more than one place. It's where you live currently, but also where you come from. It's where your family is, or was. This is what I said in my blog post about this almost one year ago.

Two and a half years ago, in summer 2022, we moved to a new country. Two and a half years ago, we changed everything about our lives.

I am becoming more at peace with my new home. But it's not perfect. Nothing is. I spent much of the past 2.5 years fighting against this new place, that I now must call home. Coming here, staying here, was not by choice. It was a clouded decision, and I think it was ultimately the wrong decision. But it was still the decision that I agreed with and supported, and I have to live with the consequences of that decision, likely for the next decade or more.

For the past year, I turned inward from depression and being overwhelmed. Now, I am finally starting to come back out of that shell. I am coming to terms with my situation, and even learned to appreciate the country we live in, in a way. It's a nice country, a safe one.

But there is still much to be done. The hard work remains.

Making Peace

I am in the process of making peace with two things:

  • I will never truly consider the place I live now as home. It is a place I must endure.
  • I will endure this place, and even find beauty in it, for the sake of myself and my family.

This started about one year ago, at the end of 2023/beginning of 2024. I recognized that I needed to change my attitude towards where we now live. At the time, I simply couldn't do it. Even now, it's very difficult. This refusal, and the stress resulting from it, has almost destroyed my life on multiple occasions. But for the sake of my own sanity, and the sake of my family, I HAVE to get with the program.

The first breakthrough was when I decided that I would not and could not truly feel at peace where I live now. It was a way out, a way to focus the rage and betrayal that I felt in summer 2022. It's a way to give my feelings a name and make them into something coherent: “I did it. I tried to live here, and I decided it's not for me.” For many people, this would be the point where they returned from where they came. But I cannot do that: I am tied here by family. I am stuck.

Now, I am trying to reconcile my necessary present with that decision to survive, rather than thrive, in this place. There is not one thing I can point to that truly screams “progress in emotional processing!” But I do notice the little differences when I go back to the place I consider my true home. When I am there, I feel a little more detached, and a little bit more desire to return to where I currently live. it's probably the most tangible sign of progress that I've noticed, and it's also what inspired me to write this blog post.

Surviving vs Thriving

Ideally, a person would thrive in a new environment, not merely survive in it. But that's not happening for me. Not yet. Possibly not ever. I thrived in the place where I used to live, and I still thrive there when I return. When I'm there, in many ways it feels like I never left. I get to role-play living there for a week or so before returning to my life as it really is: a life of isolation (somewhat self-imposed) as a stranger in a strange land. I do not speak the language of the country where I live. I do not share the culture of the country where I live (and in fact find several parts of it quite hostile and odd).

I am recovering from culture shock, and still dealing with the aftershocks and tremors of the earthquake that uprooted our lives in mid-2022. I once read it took at least 6 months to feel at home in such a drastically new place, and for some people it might even take two years. For me, it's going to take longer.

Two years ago, this place was a prison that I was dragged into, kicking and screaming. A year ago, it was a prison where I could go to the beach sometimes. Today, everything feels a bit “less foreign.” It's hard to call it “familiar.” But I suppose that would be an easier way to phrase it: “everything feels a bit more familiar.” Today, I wouldn't describe my life as being in a prison. But nor would I classify it as living the dream.

Things aren't like they were where I used to live. There, I thrived! But I also failed. But I conveniently forget those problems most of the time. The human mind is impressive: it warps, distorts, suppresses, and changes. We focus on the good things of our past, and minimize the bad parts. I have romanticized my life in the country we previously lived.

I believe that EVERYTHING I feel and experience today ultimately stems from a breakdown I had 6 years ago, where some 25+ years of stress and trauma finally exploded and spilled out. Stress from my job at the time finally broke what coping mechanisms I had, and ground my psyche to dust.

I've been slowly rebuilding my sense of self and emotional state ever since. A growing family and the move added to this stress, and it felt like taking many steps backward, undoing all the progress I had made. Multiple times.

Progress is Not Linear

I've come to realize that progressing towards a healthier mental state is not a line. It's not a ladder one must climb, where “happiness” is at the top and “depression” is at the bottom. That is too simplistic of a model. It's more like a tree, with many branches. The mental breakdown was somebody chopping down the tree (and perhaps setting it on fire and then throwing it into a wood chipper). But in its place, a new sapling sprouts. A sapling that I have to nurture and regrow into a new Tree of Self.

  • With the new tree comes new branches.
  • Some branches grow faster than others, and they grow higher.
  • You begin your climb from the ground once more, and make your way up the branches.
  • But then you slip from a higher branch and fall to a lower one!

But instead of falling all the way back to the ground, you're still in the tree. You cautiously make your way back over to the branch you were on before you fell, and while you're not as high up in the tree as you were, you're still IN THE TREE.

The Tree of Self

To put things in more concrete terms, let's say one branch is Family. Another is Social Life. Yet another is Self-Worth. Another is Self-Identity. The list can go on, and is probably specific to each person and each situation.

For me, the branch of Family regrew very slowly in the beginning. My life was turned upside down by starting a family, even though I went into it knowing fully well what was going to happen. To quote a famous line:

You are NOT prepared.

Recently, my “Family branch” has started to grow rapidly. I am finding my place as a parent and member of a family. It feeds into my regrowing branch of Self-Identity, which was similarly crushed and ground into nothingness 6 years ago (and then again 2.5 years ago). The branch of Self-Identity seems to grow much more slowly, and perhaps has been sawed off a few times over the past year. Job changes, the move to a new country, moving between houses, and constantly having to re-“find myself” have made it difficult. It's a similar situation for my social life. THAT branch is the hardest to regrow.

Change in Self-Perception

What I have noticed, especially over 2024, is that my perception of self is changing. I am beginning the transition of seeing myself as a victim and prisoner to seeing myself as a survivor. Hopefully I will eventually leave the fog of irrationality and come to see myself as just a person who has made a series of interesting life decisions. On paper, my life looks well-lived: moved across the world, got a new citizenship, and now I'm doing it all again. I'm a citizen of the world! My children even more-so! A successful career (thus far) and family. On paper, everything looks almost perfect!

The worst part about being in this state of anxiety and depression is that you often KNOW it's all irrational and not (entirely) true. But you can't stop yourself from thinking it must be true. It goes in cycles of rationality and irrationality. But the depression and anxiety do come from somewhere. It's important to remember that not EVERYTHING is just in my head.

The journey back towards happiness is very long, and very difficult. But I'm slowly getting there. Hopefully, a year from now, my outlook is less bleak, or even actually positive!

Would I go back?

Would I leave the place I live now and return to where we lived before? Absolutely, without a doubt, 100%, yes. If the opportunity presented itself, in any shape or form that I could ethically justify, I would leave immediately. And some day, that opportunity WILL come. I will not retire nor die where I live now. That would be giving up. The fight is not dead; it is merely on hold.

Hopefully by the time comes to resume the “fight,” it won't be a fight. Hopefully, it will be a life decision that I can make peacefully: not as a reaction against what I've become, but rather because it's a place where I want to go.

The Final Goals

My goal for 2025 isn't to change my mindset. Directly attacking the problem head-on is tantamount to trying to run my head through a brick wall. I spent two years trying that. First by fighting against the situation itself, then by trying to force myself to change my opinion of the situation. It didn't work either time.

My goal is to be learn to be happy in the present, within the constraints that have been forced upon me. My goal is to synthesize a happy medium between my own opinion and the reality I must navigate. By doing this, I think that my mindset will slowly shift over time. I want to settle into a place where I can recognize the sacrifices I made, to be happy in the present, and to be hopeful for the future. I want to be engaged with life, not merely drifting through it.

Hopefully, it works this time.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2025-01-12T14:27:23+01:00

I have undertaken a journey to radically change, and in my opinion, simplify, my self-hosting setup. For the past 5+ years, I have been manually creating and maintaining nginx configs—one for each service.

But now I plan to gradually move everything to Coolify.

The Matrix server, which runs on the same VPS as most services, is deployed through its own Ansible playbook. This makes the current configuration very complicated: the playbook expects to own the webserver. Getting it to play nicely with other services is slightly challenging.

The VPS environment is quite old, and the Matrix Ansible playbook used to use nginx as a proxy. But they have since changed it to use Traefik. That is good, but all my configurations are still stuck on nginx! So right now, I have nginx fronting the Matrix server's traefik instance, along with all other services.

This means that nginx is the source of truth for everything like SSL certs, routing, service configuration, etc. It also means that I lose Coolify's more interesting features like automatic SSL certificate acquisition, automatically binding services to domains, etc.

Benefits of Coolify

Even though I have to solve the proxy problem, Coolify is still giving me benefits:

  • Centralization: all services will live in one place.
  • One-click deployments: no more git pull, push, and manual updates.
  • Automation

Centralization

My self-hosted services are strewn across several servers, both on VPSes and at home. I proxy the services running at my house through frp to the VPS, and expose them via separate nginx server blocks, sometimes with special configs for web sockets and the like. This is very annoying to manage by hand (though after 5 years, I've gotten it down to a science).

Services on the VPS are usually bash scripts. They either start a container, or run a program directly. Services at home are usually Docker Compose deployments that I have to manage directly, with a configuration separate from the docker-compose.yaml distributed from upstream. I maintain private forks of several services for both config and functionality changes.

In order to update a service, I have to do it completely manually. AND I have to remember where it's actually running. AND I have to make sure I don't break any configuration. This does not scale. I'm one person, and pretty much all of these are hobby projects. But my time is valuable, because I have a family to take care of, a job, and other hobbies. The less time I spend messing around with underlying stuff, the more time I have for the interesting parts: using my self-hosted services, building something new, etc.

One-Click Deployments

This is one of the biggest selling points of Coolify. There's a bunch of applications that you can install with one click. Notably, though, it doesn't allow you to override or map ports with these one-click installations. Given my proxy problem, I can't make much use of this feature yet. But even without it, I can still make use of the built-in docker compose deployments. Coolify allows a docker-compose.yaml file to be directly uploaded, and it then handles deployment of this to one or more servers.

Automation

Coolify aims to be an open source Vercel/Netlify replacement, and the integration with Git repositories is excellent. Coolify has direct integration with GitHub, but can pull from anything that it can access over SSH. It also supports webhook deployments from the common git forges, including self-hosted ones like Gitea/Forgejo. This allows me to completely replace the entire Drone pipeline, and I no longer need to rely on privileged directory mounts into the Drone runner.

New Deployment Process

Original deployment process, before Coolify: – A commit is pushed to the capsule's git repo. – Drone CI pipeline runs and builds the static site. – Drone CI pipeline copies the capsule files into a directory mount. – The directory mount is from the host VPS, where the server runs.

This has some obvious disadvantages: it's stuck on one server, it cannot scale, and it's also less secure. While a Gemini server will likely never need to scale, having to mount directories from the host VPS is not so great.

Here is the n ew deployment process, after Coolify: – A commit is pushed to the capsule's git repo. – A webhook call is made to Coolify. – Coolify uses the docker-compose file to build and deploy the site.

The Docker Compose build serves all content directly as a container, which allows the static site to be hosted anywhere (not just the VPS), AND it does not require the VPS directory to be mounted anywhere. This increases isolation and security of the server.

New docker-compose.yaml

The new Docker Compose file is radically small. The Gemini host is defined below, and the only volume mount is an existing mount that holds the TLS certificate for gemini://agnos.is.

docker-compose.yaml for capsule and kineto services: capsule: container_name: agnosis-capsule hostname: capsule build: context: . dockerfile: Dockerfile init: true volumes: - /path/to/.certificates:/app/.certificates environment: - GEMINI_HOST=${GEMINI_HOST} ports: - 1965:1965 http-proxy: container_name: agnosis-http-proxy build: context: . dockerfile: Dockerfile.kineto args: CSS_FILE: /files/agnosis.css environment: - GEMINI_HOST=${GEMINI_HOST} ports: - 9080:8080

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2025-01-02T22:09:05+01:00

A small update on the status of the filters and tools for Open WebUI. The 0.5 version of Open WebUI introduced major changes in the codebase, which has affected some of the extensions I have made:

  • Checkpoint Summarization Filter: will not load.
  • Thinking filters: may or may not work; depends on the inlet request parameter.
  • OSM tool: works.
  • Gemini tool: works.

I will update the broken filters soon, although I am considering redoing the checkpoint summarization filter from scratch, AGAIN. It has proven to be a decent baseline for how to handle stories, but it needs further work, especially around branching and regeneration of responses.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-12-13T22:40:53+01:00

As of this post, the capsule is now serving all content natively via the Gemini protocol. There is no longer a separate HTML copy of the site.

Today, I discovered Kineto, a Gemini –> Web proxy.

Kineto is very simple. You give it a stylesheet and a Gemini domain, and it proxies the entire capsule. In fact, it's so simple that it's composed of one source code file. I kept the CSS generated by gmi-web, so the HTTP version of the capsule looks the same. But instead of receiving the HTML content from static HTML files hosted on my web server, you are receiving HTML dynamically generated from Gemtext on the Gemini protocol!

While this fits in with the ethos of my site being Gemini-first, it has also allowed me to drastically simplify how the site is generated. I was able to nuke the entirety of the HTML build process from the Justfile, which has removed probably around 100 lines of hacky bash scripting.

Additionally, I can store the CSS in the site's git repository now, and tweak it as I feel like. The capsule serves the CSS, and Kineto proxies it too. This will give me many more opportunities to change how the site looks in web browsers, without having to hack gmi-web.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-12-06T09:35:36+01:00

I have been working on reworking Gempost.

Gempost is a static site generator that was created by JustLark.

I forked it quite a long time ago to modify it for my needs, the biggest change of which was adding pages support to the application, instead of just handling Gemlogs. I have now made a pretty major update to this pages functionality by turning pages into fully templatable gemtext Tera layout templates, similar to how Jekyll handles content.

You can find it here. (pagetemplatedir branch)

How does it work?

  • You must specify a page_template_dir directory in config.
  • This directory can have any number of Tera templates.
  • There must at least be a base.tera template file.

New Features

Layout Templates

The base.tera template is a common template that all pages use as a layout, unless overridden by the new layout option in the sidecar YAML file. A layout Tera template has the following available to it:

  • {{ content }} variable. This is the content of the page itself.
  • {{ values }} variable, from the page's sidecar YAML file.
  • {{ entry }} variable, from the actual page entry itself.
  • {{ breadcrumb }} variable, from the page navigation hierarchy.

Page Templates

All pages (NOT posts! yet.) are themselves templatable, similar to how Jekyll handles HTML or Markdown content. They are handled as full Tera templates, which means all Tera features will work with them, including extends and includes.

The following variables are available to pages:

  • {{ values }} variable, from the page's sidecar YAML file.
  • {{ entry }} variable, from the actual page entry itself.
  • {{ breadcrumb }} variable, from the page navigation hierarchy.

There is a new layout option available in the sidecar YAML for pages. It is the layout template to use. By default, if it's not specified, this will be “base”, which means it will read the base.tera file from the pages template directory specified in the gempost config file.

Better Error Reporting

I have also updated the error reporting during templating for pages. The application will now output exactly why a templating operation failed, rather than just the top-level (and usually unhelpful) error.

Where to go from here

It seems like gempost is pretty much abandoned, especially because JustLark's Gemini capsule is now offline. I am thinking about taking Gempost in a new direction, and unifying the features of pages and posts together. This will simplify my own site configuration, and I think make the tool more useful to people who want a more generalized static site generation solution for Gemini capsules.

Things I'm thinking about:

  • Generating dynamic data (e.g. link menus) at site compile time.
  • Global site data, not just values per page.
  • Adding all the pages features to the gemlog post generation.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-12-05T11:24:00+01:00

No, I'm not talking about the Google AI model.

I'm talking about the Gemini protocol.

But chances are, if you're reading this post, you already know that I'm talking about the protocol:

Gemini is a new internet technology supporting an electronic library of interconnected text documents. [...] We are out to build a lightweight online space where documents are just documents.

When I created this site, it was essentially my return to having a personal website on the internet. At first, I only had the Gemini capsule; the HTML version was added later. But why create a Gemini capsule and ignore the normal HTTP Web? The first reason was, simply, because I could.

But there were other reasons:

  • Simplicity in user experience.
  • Simplicity of maintaining the site.
  • A content-first experience.

Simplicity

Gemini, by design, is very simple. Perhaps too simple. The gemtext format is similar to Markdown, but stripped down to its barest essential components:

  • One line does one thing (text, link, quote, etc).
  • Only three heading levels.
  • No stylistic formatting.

There is no styling of text in Gemtext. There is no bold, italics, or underlines. There are no inline code snippets. Only code blocks. This forces the author (me!) to focus on the best possible presentation of the text. What little styling is possible over Gemini protocol is up to the user's browser.

The User Experience

Although Geminispace is populated almost exclusively by tech nerds, I try to design my capsule for people who are NOT tech nerds. This is my personal site, not an obscure git repository.

The forced simplicity of Gemini and its native text format, gemtext, carries over to the Web version of this capsule. The Web version is static HTML, and is designed to appear more or less exactly the same way as the capsule appears in a Gemini browser.

The result is a fast-loading website that renders well on both desktop and mobile form factors. There is no JavaScript, and navigating the site is as good as I am able to make it.

The Development Experience

The original goal with creating the site in Gemini was to make it easy to maintain. It is easy to create content for it. Admittedly, though, creating this website did turn into an exercise of making my own static site generation pipeline. This is not the definition of “simple” for regular people. The site is actually stored in a git repo and built and updated via a CI (continuous integration) pipeline. Any change I make to the site is immediately deployed and visible on both the Gemini capsule and the HTML version.

Most of the heavy lifting is done by gempost.

The main Gemlog and the Astroponic Garden are treated as two separate “capsules” by Gempost. The “main site” contains the Gemlog you are now reading, and the rest of the content as pages. The Astroponic Garden is the tinylog formatted stream of consciousness.

Gemlog Astroponic Garden

Because everything for creating and building the site is in place, creating content “just works.” But it took a while to get there.

Content-First

When I was writing this post, I originally used the term “content-driven.” But I quickly changed it to content-first. In my mind, “content-driven” more refers to a marketing-centered experience. I don't want to “drive” things. Content-first is a better way to explain what I want out of Gemini. The idea is that the CONTENT informs the design (what little of it is possible) and not the other way around.

Gemtext forces you to get creative when it comes to presenting a beautiful experience to the reader. I am very particular about how a page looks in Gemini browsers, and I design this capsule with that in mind.

It's hard to quantify exactly WHAT particulars I have. But it tends to be:

  • Language that is engaging and not overly dense.
  • Natural flow of words and links in the document.
  • Headings that promote ease of navigation and reading.

The biggest challenge for me has been presenting an engaging layout without making the text overly dense or hard to follow.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-11-30T12:43:52+01:00

A quick update: I am now working on a simple tool to allow LLMs to connect to Gemini capsules.

Find the documentation here.

Find the code here: https://openwebui.com/t/projectmoon/gemini_protocol_tool/ https://git.agnos.is/projectmoon/open-webui-filters/src/branch/master/gemini.py

The initial release supports basic direct connection to Gemini pages, and relies on the model's contextual understanding to navigate the capsule. This allows you to interact with Gemini in a conversational way.

To-Do List:

  • Implement handling of non-2x status codes.
  • Convert Gemtext to Markdown for better LLM understanding.
  • Handle file uploads?
  • Handle non-text content.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-11-29T22:49:14+01:00

A major update for the OpenStreetMap tool for OpenWebUI is now available. You can grab it at one of the links below.

https://openwebui.com/t/projectmoon/open_street_map/ https://git.agnos.is/projectmoon/open-webui-filters

The tool is now on the 2.x iteration, and comes with a number of improvements and bug fixes.

New Features

There are several new features that make the tool more useful and reliable.

  • Navigation: LLMs can now provide navigation information from ORS, and answer questions about distance between places.
  • New Citations: Fancy, styled citations per OSM result.
  • New POI category: tourist attractions.
  • POI ranking system: currently used only for tourist attractions, to push more prominent attractions to the top.

Of the officially tested models, the recommended ones for use with the navigation feature are:

  • Qwen2.5
  • Mistral Nemo
  • Mistral Small

These models (and their derivatives) demonstrate contextual awareness and can understand conversations where the user asks about a destination, and then asks how to get there in a later message.

Llama3 will work, but it requires a very explicit prompt to use the navigation function. Something like: “How do I get to X? Use the OSM navigation tool” usually triggers it.

Other Improvements

Other improvements and bug fixes:

  • Information from OpenRouteService is now cached.
  • Various fixes for crashes and misleading information.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-10-15T22:48:20+02:00

Short and simple update: two new filters that make use of Open-WebUI's new feature to render collapsible sections in order to separate the reasoning and thought processes from final output for models that support this kind of workflow.

There are two new filters: one for Reflection 70b and one for Artificium 8b.

These filters act on the final output of the models, and separate the LLM's reasoning and thinking steps from the final output, and put them into collapsible sections. It makes it easier to focus on the LLM's final answer. Additionally, the filters can optionally remove the thinking steps from the input when text is submitted to the LLM, in order to save on token use.

Artificium Thinking Filter Collapsible Thought Filter (Reflection 70b)

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-09-30T19:01:37+02:00

The 1.0.0 release of the OpenStreetMap tool for OpenWebUI has arrived!

https://openwebui.com/t/projectmoon/open_street_map/

The 1.0.0 release has the following changes that make the tool a powerful map searching solution OpenWebUI, allowing users to find points of interest (POIs) near any place: – Caching: all data except the actual POI search is now cached, reducing load on public OSM services. – Nameless entities are now handled. This is important for minor landmarks, playgrounds, and other leisure areas. – The tool now can now report its results as a citation in replies. – Breaking change: the Nominatim URL setting has changed.

Along with calculating travel distance to nearby destinations, and various other bug fixes over the past weeks, I feel like it's time for a 1.0 release.

Breaking Config Change

The biggest announcement is the breaking change of the Nominatim URL valve setting for the tool. This used to point directly to Nominatim's search endpoint. But now the setting must point to the root URL of the Nominatim instance, because it's now using two different Nominatim endpoints.

If you need to change the setting, your LLM will refuse to search OpenStreetMap and warn you about this.

Caching and Nameless Entities

The two most important changes are caching and nameless entity handling. The public OSM services are available for free to everyone, and the data does not change THAT often. By caching address lookup data, extra POI information, and navigation travel distance, a lot queries against the OSM servers can be avoided. This is particularly important for the common scenario of the user searching from their house, school, work: “What's the closest X near me?” Instead of hitting Nominatim every time to resolve the user's location, it is now simply pulled from the cache.

Additionally, many entities in OpenStreetMap do not have names. This is either because of lack of proper tagging, or the place may not actually have a name at all. This is very common with things like playgrounds in neighborhoods, small green spaces in cities, and so on. – The logic for determining what entities are “useful” to the tool has changed. – The tool now resolves an address for these nameless entities and uses it as the name.

Sending the results as a citation is just a nice bonus that gives some insight into what the OSM tool is doing when it searches for the user.

The Future

The tool is rapidly approaching feature completion. Releases in the immediate future are going to focus on: – Cleaning up the code for a maintainable future. – Fixing bugs and edge cases. – Adding more predefined POI search functions.

The code is a bit of a mess at the moment because of OpenWebUI's requirement to have all the Python code in one file. I am considering ways to deal with this, ranging from moving a lot of the code to a PyPI module, or simply just having a simple build file that concats the code together into one Python module.

License: CC-BY-SA-4.0.

Written by: @[email protected]