My thoughts on Slackware, life and everything

Month: June 2026

I had to fix the Slackware 15.0 git repository

Recently, and unexpectedly, I noticed a lot of errors in the output of the script which populates the git repository for Slackware. Specifically, when it updated the “15.0” branch which tracks the updates in Slackware 15.0.

I did an evening of troubleshooting and fixing. Somehow, the root user had dumped a copy of Slackware-current in the checked-out directory containing the Slackware 15.0 branch of the git repository. The script errors were caused by the inability of the non-root user running the script, to delete all the root-owned files that were suddenly there.

I was out traveling (to the ISC’26) with my team and did not have the time to fix this earlier.

Now I have fixed https://git.slackware.nl/current/log/?h=15.0 which I mirror as https://forge.slackware.nl/slackware/distrodevelopment/src/branch/15.0 by deleting the faulty commit (which contained all of Slackware-current), replaying the three good commits that came after and then salvaging the actual update from the faulty commit.
It means that the 4 new commits (actually the same commits but with a new hash) look a bit weird compared with all the others. They were manually fixed.

What this also means is: I have re-written the git history. If you cloned this repository from either of the above repository URLs (pure ‘clone’, not ‘clone –mirror’) you need to do a hard reset:

$ git fetch origin
$ git reset --hard origin/15.0
$ git fetch --prune --prune-tags origin

If you cloned this repository in the Slackware Forge, it’s considered an independent copy. It will not update of its own. You will have to sync or reset manually.

If you actually are mirroring the repository https://forge.slackware.nl/slackware/distrodevelopment then your next “git remote update” will most likely just bring your mirror back in sync without a need for further interaction.

I have also double-checked that any script that touches this git repository when doing updates is not clashing with another instance.
Sorry for any inconvenience.

Fixing the cgit configuration of git.slackware.nl

In an earlier article here on the blog, I documented how I have setup cgit to create a browseable web interface to my git repositories, most notably git.liveslak.org and git.slackware.nl.

That configuration has worked just fine for years, and you could clone a branch of a repository using the “https://” git URI and that works.

However…
Cgit is a nice graphical shell around git repositories, but it does not serve the actual git protocol.
I found out when I tried to setup a mirror of the “current” repository on the Slackware Forge. For that, I needed to perform a full clone including all branches and tags. That failed mysteriously with the error:

$ git clone https://git.slackware.nl/current
Cloning into 'current'...
error: Unable to find d8220d28e5d53cd896b28d9dea13e2258923f35a under https://git.slackware.nl/current
Cannot obtain needed object d8220d28e5d53cd896b28d9dea13e2258923f35a
while processing commit 897670f2f2e1795652dfa3da21f9879d04a9b8dc.
error: fetch failed.

At first I thought that the remote repository was damaged or corrupted,but that was ruled out by searching for the hash to see if it would actually return something else than an error. From within the bare git repositorty on the server:

# git cat-file -t d8220d28e5d53cd896b28d9dea13e2258923f35a
commit

The hash does exist and it is a commit. That rules out the corruption.
Examining those errors “unable to find under ” and “cannot obtain needed object … while processing commit …” the conclusion is that the webserver only serves the bare repository as static files over plain HTTP, with no git-http-backend smart protocol behind it.
A working “git clone” over https needs the git-http-backend configured alongside the cgit configuration in Apache. Since that backend runs as the webserver user “apache”, and the git repositories are owned by user “git”,  we need to deal with file permissions/ownership and what git considers “safe directories”. Modern git (2.35.2 and later) refuses to operate on a repository owned by a different user than the one running git, and aborts with:
fatal: detected dubious ownership in repository at '/the/path/to/current'

The final configuration that adds the “git-http-backend” protocol to the Apache webserver and also resolves the “dubious ownership” error comes in two parts.

First:
A global git configuration directive which will only be used by the Apache user so that it won’t trip over the “git” user-owned repository files.
Create the file “/etc/httpd/http-git-config” and add these lines to it:

# ---
[safe]
        directory = *
# ---

Second:
Adding a code block to the VHost definition of the git server. In my previous article I described the git.liveslak.org configuration but actually this is identical to that for git.slackware.nl.
Therefore, to the file “/etc/httpd/extra/git.slackware.nl_content.conf” we add the following right before the “SetEnv CGIT_CONFIG” line:

# ---- smart HTTP for git clients (git-http-backend) ----
# Root directory that contains the bare repositories (current.git, etc.).
SetEnv GIT_PROJECT_ROOT /local/path/to/git/repositories

# Apache trips over the git:git ownership of the repositories, so we
# need to tell git that for Apache, all repositories should be considered
# as having safe ownership:
SetEnv GIT_CONFIG_GLOBAL /etc/httpd/http-git-config

# Route ONLY the git protocol paths to git-http-backend. Everything else
# (the cgit pretty URLs) is left untouched and handled by cgit below.
# The character classes accept both SHA-1 (40 hex) and SHA-256 (64 hex)
# object names, so this keeps working When we ever migrate hash formats.
# This MUST appear before the cgit ScriptAlias in the vhost.
ScriptAliasMatch \
  "(?x)^/(.*/(HEAD | \
    info/refs | \
    objects/(info/[^/]+ | \
      [0-9a-f]{2}/[0-9a-f]{38,62} | \
      pack/pack-[0-9a-f]{40,64}\.(pack|idx)) | \
    git-(upload|receive)-pack))$" \
  /usr/libexec/git-core/git-http-backend/$1

<Directory "/usr/libexec/git-core">
    Options +ExecCGI
    Require all granted
</Directory>
# -------------------------------------------------------

Test the Apache configuration for errors after saving your changes:

# apachectl configtest

And reload the webserver gracefully (not aborting current connections):

# apachectl -k graceful

Now, let’s test the server response when we send it a request:

$ curl -sI "https://git.slackware.nl/info/refs?service=git-upload-pack" | grep -Ei 'HTTP/|Content-Type'
HTTP/1.1 200 OK
Content-Type: application/x-git-upload-pack-advertisement

The content-type of “application/x-git-upload-pack-advertisement” instead of something like “text/plain” or “octet-stream” means that we have a properly working HTTP backend for git now. Cloning the repository no longer returns an error:

$ git clone https://git.slackware.nl/current
Cloning into 'current'...
remote: Enumerating objects: 103427, done.
remote: Counting objects: 100% (103427/103427), done.
remote: Compressing objects: 100% (31583/31583), done.
remote: Total 103427 (delta 69643), reused 103103 (delta 69319), pack-reused 0 (from 0)
Receiving objects: 100% (103427/103427), 759.01 MiB | 69.60 MiB/s, done.
Resolving deltas: 100% (69643/69643), done.

This fix allowed me to mirror https://git.slackware.nl/current/ to https://forge.slackware.nl/slackware/distrodevelopment with a sync frequency of 1 hour.

Using Claude to create a work of art

© 2026 Eric Hameleers. All Rights Reserved.

Take the “work of art” with a grain of salt please 🙂 This is an article about computer-generated art but with my own photographs as the source material.

In May, the last of our four cats died. They were two pairs of Holy Birmans, first two little sisters who we took in when they were only 7 weeks old; and later two big brothers whom we adopted when they were over 8 years old.
For the first time in 30 years we do not have any cat in the house. It is silent and sometimes desolate, and I miss the little fluff-balls. But we need to be realistic – we also want to see more of the world and having cats means you need to take care of their well-being. These four are it. There will not be future cats.

Me and my wife decided we wanted to commemorate them by creating some kind of artwork and put that up on the living room wall. We wanted their pictures, and since they were four very different cats, we looked for defining features and old photos that showed their uniqueness. We succeeded in that part, but then came the question, what form and shape should this take? The pictures had different backgrounds, the lighting created different colors, the cats in the pictures had different sizes.

I came up with the idea to create solarized versions of these pictures, give them a kind of Warhol effect with primary colors and bold planes. I looked into ImageMagick, and could not find a good way forward. I looked at online AI image generators and manglers, and none of that was any good either, no consistency in the results.

So I turned to Anthropic’s Claude chat bot. I started with a simple question:

I have four pictures of my cats. I need the cats without the background and primarily the cat heads and/or bodies in a composite picture, which has the solarized style of an Andy Warhol painting

To which the bot responded (it knows I work on Slackware):

Good news: this is very achievable with a Python script using a couple of well-suited libraries, and you can run it entirely on your Slackware machine. Here’s the plan:
Tool stack:

rembg – AI-powered background removal (uses a U2Net model), works excellently on pets/animals. This is the part where ImageMagick would genuinely struggle.
Pillow (PIL) – for cropping, compositing, posterizing, colorizing, and assembling the grid.
Both installable via pip.

The pipeline per cat photo:

Remove background with rembg (outputs a clean RGBA PNG)
Auto-crop to the cat’s bounding box (head/body)
Posterize (reduce to ~4 color levels) to get that flat, graphic look
Apply a flat color tint per panel (Warhol used vivid, clashing hues)
Arrange all four panels in a 2×2 grid

What I need from you to write the script:

Confirm you can install Python packages via pip on your Slackware machine (or in a venv)
Any preference on output size (e.g. 2000x2000px total, so 1000×1000 per panel)?
Do you want each cat in a different color scheme, or the same cat repeated Warhol-style (like the Marilyn print where it’s one subject, four colorways)?
Should the background of each panel be a solid flat color, or transparent/black?

Once you confirm, I’ll write you a clean, self-contained Python script that takes your four JPEGs as input and produces a single composite PNG.

I checked that I could indeed install the dependencies without any issue. I gave it some additional information:

I can install any package using pip, no problem. The image dimensions of 2000×2000 sounds fine.
Each cat should have a different primary color and I would like to associate the four input pictures with specific colors myself. The background is a good question, since I do not yet know what will give the best result. For now I would go with a gradient background that contrasts with the primary colors I will select for the cats and potentially add some smudging to that background.

That produced a script in a few seconds that actually did everything I had imagined for the resulting bitmap wich consisted of 4 panels in a 2×2 grid, one solarized cat image per panel.

Of course, then the creative mind wanted more. It is interesting how this works. I have ideas, I conceptualize them into a prompt, the AI returns Python code that evolves with every new question I have, and actually every iteration of the script does everything I wanted from it.
Eventually, the script was capable of a lot more, tweaks that created better and visually more pleasing versions of the WarholCats.

What was added during this “discussion”:

  • Per-panel configuration:
    • Define the primary color (required) and optionally specify a different background color than the default color complement of the foreground.
    • An optional (x,y) offset to place each cat squarely in the panel’s center.
    • Background styles, several gradients are possible: diagonal, vertical, horizontal, radial; as well as a simple monochrome background.
  • The bot documented all of these configurable parameters in a PANELS block. All parameters were given sensible fallback values in case they are not provided.
  • Optionally a black outline drawn around the cats to make them stand out more – looks better against a monochrome background.
  • Three layouts: a 2×2, 4×1, or 1×4 canvas.
  • The script has defaults set for my wallmount project (I intend to have the result directly printed on dibond aluminium): my LAYOUT = “4×1” and PANEL_SIZE = 2000, allowing for roughly 127 dpi when the image is applied to a 160×40 cm dibond.

Variables like FILL_FRACTION (defaulting to 0.90) and PADDING_FRACTION (defaulting to 0.06), allow for a middle ground for the framing of the cat images. Eventually I also needed an OFFSET variable to move individual cat images into the center of their panel.
The result is the picture at the top of this article. The Python script can be found in the Slackware Forge: https://forge.slackware.nl/alienbob/randomstuff/src/branch/main/WarholCats/warhol_cats.py
The four original cat photos are attached to this blog:

© 2026 Eric Hameleers. All Rights Reserved.

© 2026 Eric Hameleers. All Rights Reserved.

© 2026 Eric Hameleers. All Rights Reserved.

© 2026 Eric Hameleers. All Rights Reserved.

That’s it for today. I wanted to share how a Large Language Model like Anthropic’s Claude is able to boost your creativity with respect for your precious free time. No… this is not vibe coding. The Python code is simple and clean, and is easy to follow. No weird functionality, and proper inlined comments all over.
Feel free to use the script as you see fit. I would however appreciate that you do not share the pictures of my cats or the resulting solarized bitmap any further. The images are copyrighted.
Cheers, Eric

© 2026 Alien Pastures

Theme by Anders NorenUp ↑