Epiktistes

Epiktistes is my home in the Fediverse. It is an instance of Ktistec, a single-user ActivityPub server like Mastodon, but with fewer users and fewer commits. Here's my introduction (last updated early-2025).

I wrote a series of posts about optimizing the performance of the Ktistec server, its build time, and its executable size: part 1, part 2, part 3, part 4, and part 5.

Some things I regularly write about, organized by hashtag:

I also wrote some #pointfreeverse.

My post on using emoji in Crystal Language identifiers got some πŸŽ‰ attention. The obvious question was, how much further could I take a Crystal based solution? I played around with macros for a while to see how much syntax I could replace, but that path didn't go very far. Too much of the language, like block delimiters, showed through.

It turns out there is at least one programming language designed almost entirely around emojiβ€”Emojicode. Emojicode is pretty cool and impressively complete, but because Emojicode is, at its core, a fairly traditional imperative language, it is difficult to keep the ASCII out. πŸ€”

I thought I could do better by modeling an emoji-based programming language on a stack-based language like Forth. πŸ’‘ Heavy use of recursion and the stack makes it easy to avoid naming things, which means ✨ less ASCII and more emoji ✨.

This ugly duckling defines a word (a function) that computes a factorial. The factorial word is the character ❗ (the syntax πŸ“–β— ... πŸ“• defines it as a new word). You can see that ❗ calls itself recursively, right?

πŸ’­ Factorial

πŸ“–β—πŸ“š2οΈβƒ£β¬‡οΈβ“πŸ‘πŸ—‘οΈ1οΈβƒ£πŸ‘ŽπŸ“š1οΈβƒ£βž–β—βœ–οΈπŸ”šπŸ“•

πŸ”’5β—πŸ˜€   πŸ’­ 120
πŸ”’10β—πŸ˜€  πŸ’­ 3628800

You can use spaces and line breaks to make things more readable, but a lot of Forth code kind of looks like this to me so 🀷.

There's already a small number of primitive words and a standard library of additional words. I'll probably play around with the core a bit more and then publish it.

Tower of Hanoi 🏯 works, too!

#emoji #forth #esolang

Release v3.2.0 of Ktistec

The major feature in v3.2.0 of Ktistec is thread analysis. The previous release, v3.1.2, added support for viewing threads from Lemmy communities. I follow the Open Source community, which leads to many large threads. The thread on FFMpeg and Google has 112 posts and is still growing.

Thread analysis helps me navigate these extensive conversations. It includes: top contributors, a timeline histogram, and notable branches.

The analysis applies several heuristics to identify interesting branches of the main thread. β€œInteresting” is subjective, but the algorithm currently looks for sudden bursts of activity and highlights those areas. Ktistec uses this to create a table of contents that links directly to those branches. Clicking on one of these links takes you to a branch-only view that focuses on the selected part of the thread.

It's fastβ€”I anticipated needing to cache analyses, but analyzing a thread with over 400 posts takes only about 50 milliseconds on my production server.

Figure 1: Screenshot of the final design. Notable branches link to subsets of the thread.

This release also addresses an object visibility regression that was introduced in a previous version.

Full Changelog

Added

  • Thread analysis that displays key participants, a timeline histogram, and notable branches
  • New MCP tools: analyze_thread and get_thread
  • Focal point rendering support for image attachments

Fixed

  • Regression in object visibility affecting replies to threads

Changed

  • Enhanced MCP tool details for likes, dislikes, and announces
  • Improved cookie security.

#ktistec #fediverse #activitypub #crystallang

TIL

The … (the Unicode ellipsis character) works as both a Crystal Language macro and method name, as in:

macro …(str, n)
  Ktistec::Util.render_as_text_and_truncate({{str}}, {{n}})
end

Which can be used in a view template as:

= … preview, 120

I'm not saying you should. I'm saying you can.

#crystallang #til

the kingdom was lost for want of a path attribute in a cookie... 😑

I love a good discussion, but navigating large threads is difficult, and filtering the dross to find the silver and gold is tedious. I am working on thread analytics and an improved thread header to make it easier to identify the interesting bits and to quickly navigate to them.

Here's a peek:

screenshot showing the new thread header with detailed analysis of a large thread

In addition to top contributors, the thread header now includes a timeline histogram showing periods of engagement, and a table of contents with notable branches and direct links to those branches.

This feature is still under development, so expect changes and refinements before the next release.

#ktistec

Okay, my analysis is complete! Here are the core changes to Ktistec required for Mastodon API compatibility:

  • PKCE (Proof Key for Code Exchange) must be optional: Because Mastodon makes PKCE optional, clients don't support it, which means other servers can't require it. PKCE (and the code_challenge parameter) ensures that an authorization code can only be exchanged by the client that initiated the OAuth request.
  • Support for the client_credentials grant type: The client_credentials grant type is used to grant a client app-level access without requiring user authentication. Mastodon requires this for some of its "public" API endpoints. This necessitates a change to the database schema to allow a null account id in the client secrets table.
  • Addition of a created_at timestamp property: Mastodon requires a non-standard created_at property in the body of the /oauth/token endpoint response instead of (in addition to) the standard expires_in property.
  • Support for both form-encoded and JSON request bodies: This isn't a Mastodon requirement per se but popular clients clearly demand some latitude in what they send.
  • WebFinger must accept requests with no resource parameter: This is honestly a bug on my part.
  • Mastodon-compatible endpoints: A boatload of them. Clients expect many endpoints and don't gracefully degrade if they're not present. Really I should just implement features like pinned posts and bookmarks...

The only thing here that gives me heartburn is that PKCE is not required.

#ktistec #mastodonapi #oauth

Physics is really bizarre and wonderful. Here I start explaining why the Standard Model has U(1) Γ— SU(2) Γ— SU(3) as its symmetry group. But I don't assume you know anything about groups or quantum mechanics! So I have to start at the beginning: how the electromagnetic, weak, and strong force are connected to the numbers 1, 2, and 3. It's all about quunits, qubits and qutrits.

You've heard of bits, which describe a binary alternative, like 0 and 1. You've probably heard about qubits, which are the quantum version of bits. The weak force is connected to qubits where the 2 alternatives are called "isospin up" and "isospin down". The most familiar example is the choice between a proton and a neutron. A better example is the choice between an up quark and a down quark.

The strong force is connected to qutrits - the quantum version of a choice between 3 alternatives. In physics these are whimsically called "red", "green" and "blue". Quarks come in 3 colors like this.

The electromagnetic force is connected to "quunits" - the quantum version of a choice between just one alternative. It may seem like that's no choice at all! But quantum mechanics is weird: there's just one choice, but you can still rotate that choice.

Yes, I know this stuff sounds crazy. But this is how the world actually works. I start explaining it here, and I'll keep on until it's all laid out quite precisely.

youtube.com/watch?v=7Umq7yXoVAc

mastodon's creative extensions to oauth are gonna make me cry...

Ktistec is going to require that clients support PKCE

both 1000xRESIST and Clair Obscur: Expedition 33 are listed a "playable" on the Steam Deck but not "verified". it sounds like some of the problem might be frame rate. i'm unsure whether or not to take the risk. sadly neither run on a mac.