I can't stop building tools.
Ever since I realised that I can use LLM coding agents to build lots of little bits of personal software I've been on a roll creating a tonne of tools just for my own use.
I am finding this moment in the trajectory of the software industry quite joyful. I am not blind to the ethical issues being raised about these tools, and the potential risks to our industry. But I am cautiously optimistic that if we apply them correctly, like another tool in our tool belt, we can actually find real genuine use for them. The caveat being that coding agents are probably the biggest foot gun in the history of foot guns.
Anyway, back to the tools I am building.
URL shorteners, what are they for?
I am 99% sure they were originally built to save characters on Twitter. Back when Twitter had a 160 character limit. Back when Twitter was actually Twitter. However the wiki says they've been around in some form since 2001.
There has always been a vanity aspect to it - popular words or names were often snapped up by accounts (a bit like domains) and sat on, or used as a vanity metric. Presentations in tech would often end with a short URL that is memorable (people didn't always have camera phones back then).
The bit.ly short url cool i.e. https://bit.ly/cool redirects to an article telling you to use...Bitly. Written in 2008. Hah!
So how do they work?
There is no secret sauce - they're just a look up table with an HTTP 301 response to the forwarded URL. A few services tried to monetise themselves by offering things like analytics, customisable paths, domain forwarding, etc. But they didn't really do much at all.
Remember: this was the early Web 2.0 era, back when SaaS was booming and "the moat" was inertia, the effort already put in to build something, and adoption by large online communities.
Why build your own?
I have got to admit: seeing someone share their own custom domain and short link this way was so cool. You knew back in the 00's and 10's if someone had their own custom shortener domain they were real techies.
And so, I always wanted my own. But I didn't want to pay for it 🙈
If we combine this desire with the realisation I had earlier about LLMs being able to build a lot of the scaffolding for stuff like this now, then you can start to see how this idea came around.
I also had another idea I wanted to try: could I make this configurable with a single markdown file and have it be a static website? That would be ideal for me as it would fit my Hyper Personal Software manifesto.
URL redirection is easy with static pages, they look like this:
index.html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Redirecting…</title>
<meta http-equiv="refresh" content="0;url=https://github.com/phalt">
<meta name="robots" content="noindex">
<link rel="canonical" href="https://github.com/phalt">
<script>location.replace("https://github.com/phalt")</script>
</head>
<body><a href="https://github.com/phalt">Redirecting to https://github.com/phalt</a></body>
</html>
The key part is the <script> which triggers a location.replace. The anchor tag is there to support people who do not have JavaScript enabled. We've also got the canonical link here to help search engines understand what these pages are.
No actually, from what I gather from trying to use curl against a few bit.ly links they return a 301 MOVE PERMANENTLY response directly from the server. The static solution I am using above is just as adequate.
The static site portion of my goal is done, now how is the "configured from a single markdown file" goal going to be achieved?
Frontmatter, basically:
paulias.md---
repo: phalt/paulias
cname: paulias.dev
branch: main
title: Paul's shortlinks
about: "Hello. I am [Paul Hallett](https://paulwrites.software) and these are my shortlinks:"
footer: "Shortlinks built using [paulias](https://github.com/phalt/paulias)."
---
[gh]: https://github.com/phalt
[me]: https://paulwrites.software
[hyps]: https://paulwrites.software/articles/hyps
[bsky]: https://bsky.app/profile/paulwrites.software
[pauldot]: https://paulwrites.software/articles/pauldot
All the configuration I need for my URL shortener is frontmatter properties. Most of them are just content for the landing page (because if you're like me and you see a web address, you always wonder what is on the / path).
The three most important ones are:
repo: my tool tracks a git repository as the source of the config file and also the generated static pages.branch: my tool wraps a bunch of simple git commands with a nice CLI (see below).cname: Github Pages needs aCNAMEfile in the root to handle custom domain configuration. This is generated from the value set here.
The very last thing I needed was a way to track the look up between the short link -> redirect link.
I settled on this format:
md[short] -> https://destination.com
This would translate to the /short path on my website, and redirect to destination.com.
This format is already an established part of markdown syntax so not some silly made up format that I invented.
Okay, what's the tool and how does it work?
Now the fun part, introducing the new tool.
Given these tools are intended primarily for me (but I don't mind if you want to use it yourself) I have leaned heavily into pun names that still give off some hint as to what they do.
So this one is called... Paulias. Paul (me). Alias. Geddit? 😆
Paulias works a bit like other static site generators - you install the CLI tool, then use it within a git repository to generate the html pages.
Installation
Paulias is available as a pypi package and I recommend installing it with uv:
shelluv tool install paulias
Confirm it works:
shell> paulias
Usage: paulias [OPTIONS] COMMAND [ARGS]...
______ _ _
| ___ \ | (_)
| |_/ /_ _ _ _| |_ __ _ ___
| __/ _` | | | | | |/ _` / __|
| | | (_| | |_| | | | (_| \__ \
\_| \__,_|\__,_|_|_|\__,_|___/
Paulias. Version: 0.1.0
Set up and adding links
Within your git repo, start by running paulias init to create a new paulias.md file:
shpaulias init
Paulias will tell you what to do next when you run this:
shell> paulias init
✓ Wrote paulias.md.
Next steps:
1. Edit paulias.md and fill in your details.
2. Run paulias add <path> <url> to add shortlinks.
3. Run paulias deploy to build and publish.
Once you've modified the file you don't need to modify the file directly, you can use CLI commands to do everything:
sh> paulias add gh https://github.com/phalt
✓ Added : https://github.com/phalt
Run paulias deploy to publish.
Links are validated to make sure you don't overwrite an existing link, and that the redirect path is a proper URL.
To delete a link just run paulias delete PATH.
At any time you can run paulias list to see what short links you have:
shell> paulias list
My shortlinks (2 entries, deploying to paulias.dev)
short target
gh https://github.com/phalt
me https://paulwrites.software
You don't have to deploy a static site. Paulias can act as a CLI bookmark tool for you. Just run paulias open PATH to open the target URL in your default browser. You can use paulias to keep track of common links for a project (such as the Jira or Bugzilla board) by shipping a paulias.md file along with your project.
Deploying
Paulias has a deploy command that will build the static files and then push to your git remote branch. It is built to work directly with Github Pages but should work for other simple static hosting sites too.
You will need to do a bit of configuration to the Github repository to get this last bit to work:
- In repo Settings → Pages, set source to the
mainbranch, folder/docs. - Configure your CNAME properly so it matches (if you're using a CNAME).
Once that is done, paulias deploy will build and then push the changes for you.
shell> paulias deploy
✓ Deployed 5 shortlinks → paulias.dev
There is also a paulias serve command if you want to run the site locally to test it out.
Wrapping up
That's it! You now have a statically hosted URL shortener!
You can see mine here: paulias.dev
The links work like short URLs for example paulias.dev/gh redirects you to my GitHub page.
The "shortness" of it is down to what cool domain you can snag, but you get the idea.
What's next? I considered adding a plugin for analytics, but personally I don't care about that, and it is my tool after all.
The fact you can use it in any repo means you can use it as a bookmarking tool - you just ignore the last deploy step. That's a pretty cool feature. Maybe it needs to use a global paulias.md file somwhere...
Anyways, If you want to fork the project and modify it to suit your own needs then fork away.