Can we improve the Fediverse Allow-List Model?

Looks like someone really kicked the hornet’s nest recently on mastodon by announcing (not even deploying) a Mastodon-BlueSky bridge. Just take a look at the github comments here to get an idea of how this was received.

Plenty of people way more experienced than myself have weighted on this issue so I don’t feel the need to leave my two cents. However I wanted to talk about a very common counter-argument made towards those who do not want such bridges to exist. Namely, that Fediverse already provides the tools towards not having such a bridge be an issue: The allow-list model.

The idea being that if your ActivityPub server by default rejects all federation except towards trusted instances, then such bridges pose no problems whatsoever. The bridge (and any potential undercover APub scrappers) would not be able to get to your instance anyway.

Naturally, the counterargument is that this is way too limiting to one’s reach, and they shouldn’t be forced into isolation like this. Unfortunately the alternative here appears to try and scold others into submission, and this is unlikely to be long term solution. Eventually the Eternal September will come to the Fediverse. If you spent the past few years relying on peer pressure to enforce social norms, then the influx of people who do not share your values is going to make that tactic moot.

In fact, we can already see the pushback to the scolding tactics unfolding right now.

The solution then has to be a way to improve the way we handle such scenarios. Improve the tooling and our tactics so that such bridges and scrappers cannot be an issue.

A lot of the frustration I feel also comes down to the limited set of tools provided by Mastodon and other Fediverse services. A lot of the time, the improvement of tooling is stubbornly refused by the privileged core developers who don’t feel the need to support the needs of the marginalized communities. But that doesn’t mean the tooling couldn’t be expanded to be more flexible.

So let’s think about the Allow-List model for a moment. The biggest issue of an Allow-List is not necessarily that the origin server restricts themselves from the discussion. In fact they’re probably perfectly happy with that. The problem is that if this became the norm, it massively restricts the biggest strength of the Fediverse, which is for anyone to create and run their own server.

If I make a new server and most of everyone I want to interact with is in Allow-List mode, how do I even get in? We then have to start creating informal communication channels where one has to apply to join the allow-circle. Such processes have way too many drawbacks to list, such as naturally marginalizing Neurodivergent people with Rejection Sensitivity Dysphoria, balkanizing the Fediverse, empowering whisper networks and so on.

I want to instead suggest an alternative hybrid approach: The Feeler network. (provisional name)

The idea is thus: You have your well protected servers in Allow-List mode. These are the servers which require protection from constant harassment when their posts are spread publicly. These servers have a few “Feeler” instances they trust on their allow-list. Those servers in turn do not have an allow-mode turned on, but rely on blocklist like usual. Their users would be those privileged enough to be able to handle the occasional abuse or troll coming their way before blocking them.

So far so good. Nothing changes here. However what if those Feeler servers could also use the wider reach to see which instances are cool and announce that to their trusted servers? So a new instance appears in your federation. You, as a Feeler server, interact with them for a bit and nothing suspicious happens, and their users seem all to be ideologically aligned enough. You then add them into a public “endorsed list”. Now all the servers in your trust circle who are in allow-mode see this endorsement and automatically add them to their allow-lists. Bam! Problem solved. New servers have a way to be seen and eventually come into reach with Allow-List instances through a sort of organic probation period, and allow-listed servers can keep expanding their reach without private communications, and arduous application processes.

Now you might argue: “Hey Db0, yes my feelers can see my allow-list server posts, but if they boost them, now anyone can see them, and now they will be bridged to bluesky and I’m back in a bad spot!”

Yes this is possible, but also technically solvable. All we need to do is to make the Feeler servers only federate boosted posts from servers in allow-mode, to the servers that the ones in the allow-list already allow. So let’s say Server T1 and T2 are instances in allow-list mode which trust each other. Server F1 is a Feeler server trusted by T1 and T2. Server S1 is an external instance that is not blocked by F1, but not yet endorsed either. User in F1 boosts a post from T1. Normally a user in S1 would see that post by following that user. All we need to do is to change the software so that if F1 boosts a post from T1, the boost would only federate towards T2 and other instances in T1’s allow-list, instead of everyone. Sure this would require a bit more boost complexity, but it’s nothing impossible. Let’s call this “protected boost”.

Of course, this would require all Apub software to expose an “Endorsement” list for this to work. This is where the big difficulty comes from, as you now have to herd the cats that are the multitude of APub developers to add new functionality. Fortunately, this is where tools like the Fediseer can cover for the lack of development, or outright rejection by your software developer. The Fediseer already provides endorsement functionality along with a full REST API, so you can already implement this Feeler functionality by a few simple scripts!

The “protected boost” mode would require mastodon developers to do some work of course, as that relies in the software internals which cannot be easily hacked by server admins. But this too can potentially just be a patch to the software that only Feeler-admins would need to run.

The best part of this approach is that it doesn’t require any communication whatsoever. All it needs is for the “Feeler” admins to be actively curating their endorsements (either on the Fediseer, or locally if it’s ever added to the SW). Then all allow-list server has to do is choose which Feelers they trust and “subscribe” to their endorsement list for their own allow-list. And of course, they can synchronize or expand their allow-list further as they wish. This approach naturally makes the distributed nature of the Fediverse into a strength, instead of a weakness!

Now personally, I’m a big proponent of the “human touch” in social networks, so I feel that endorsement lists should be a manual mechanism. But if you want to take this to the next level, you could also easily set up a mechanism where newly discovered instances would automatically pass into your endorsement list after X weeks/months of interaction with your user without reports and X-amount of likes or whatever. Assuming admins on-point, this could make widely Feeler servers as a trusted gateway into a well protected space on the fedi, where bad actors would find it extraordinarily difficult to infiltrate, regardless of how many instances they spawn. And it this network would still keep increasing each reach constantly, without adding an extraordinary amount of load to its admins.

Barring the “protected boost” mode, this concept is already possible through the Fediseer. The scripts to do this work already exist as well. All it requires is for people to attempt to use it and see how it functions!

Do point out pitfalls you foresee in this approach and we can discuss how to potentially address them.

Error Codes and Styling

Does the above image look scary? If so, you might just just be a software developer!

The above is the result of a long-time coming, but massive pull request to standardize the formatting of the AI Horde code. I’ve been meaning to do this ever since I discovered the black and ruff tools, but I’ve been procrastinating for almost as long. Well, I finally somehow got my ass in motion to do it. Including writing tests, and doing some careful regression testing, It took me like a week in total. And I still didn’t apply all of the ruff checks either.

What this means is that from now on, anyone sending a change, can simply run ruff . --fix && black . and it will automatically format all changes to match our standards. Making the code predictable to read and reducing some bad programming practices and potential tech debt.

Also, as a software dev, finally doing this kind of operation is so satisfying. Not much fun to do, but you’re very happy to have this done. What’s a good analogy for this? a peeling session (post your best analogies in the comments)?

Soon after, I also deployed another change that might be useful for AI Horde integrators out there. I have now added unique error return codes to each error message from the horde. This should make it easier to parse the various errors the horde might spit out with code, instead of having to parse an error message which might potentially change in the future. It also allows you to do things like error code translations (although I think it might be useful to allow people to send translations for the various RCs to the horde as PRs, so that we don’t force every frontend to reinvent them)

I also wrote a README page detailing all the existing RCs.

There’s also been the various bugfixes and improvements on the worker, sdk and hordelib code. Remember to update your reGen worker regularly!

Once again, many thanks to NLNet for providing the funding for such “necessary chore” tasks like these. These kind of things are not a ton of fun to do, as they don’t add any new functionality to the project, but they massively help future development by reducing tech debt.

Webhooks on the AI Horde

Today I am excited to announce that I have deployed a new feature which allows you to specify a webhook when requesting a generation on the AI Horde. If you do that, once each generation is completed on the AI Horde, it will send POST request to the specified url, with a payload matching the request type.

Apropos, it’s a good time to announce I have started writing some integration information for the AI Horde, which contains information about the available API, and SDKs, and of course, the new webhooks. Feel free to send PRs to improve it!

This new functionality can allow a few more efficient ways of using the AI Horde. For example you could avoid polling the AI Horde every second or so, and rely on webhooks, and only do a manual poll every 30 seconds or so, if the requests have not webhooked over to you yet. The AI Horde will retry a webhook 3 times before giving up, so in case of network issues etc, you can always check the status manually as usual. This approach would reduce the load on the AI horde, while at the same time giving you faster results. It’s what I call a win-win!

Of course, not all clients can support webhooks, so for those who can’t, the existing functionality will continue working as usual.

Ludicrous Speed!

One very useful feature I’ve been meaning to support for the AI Horde for a while has been request batching. Request batching is the function to generate multiple Stable Diffusion images in parallel, by using internal mechanism to the ML libraries, instead of splitting them into multiple processes. Due to the re-using common parts of the request, it allows the GPU to generate each extra image with just 20% slowdown, instead of 100%, so long as you stay within your GPU’s power.

Soon after we finished adding LCM support, I turned my view to making this a possibility, as between these two features, it could massively increase the overall speed at which the AI Horde completes requests. The only problem is the overall complexity to handling this in the Inference.

Today I’m proud to announce that the AI Horde natively supports smartly batching multiple images in the same request when possible which can result in massive improvements in overall speed! Read on for more details of how we achieved it.

By relying on ComfyUI, the most difficult part was done, and earlier work done by Tazlin and Jug had already prepared the ground to use our hordelib library to handle sending such batched requests to the comfy engine, but I still had a lot of work to do to not only allow the AI Horde accept and queue such loads properly, but also for the worker to be able to understand payloads for multiple images.

Fortunately due to the new setup of the reGen worker, being able to adjust it to accept one job for multiple images and then submit multiple image results at the end was easier than I expected. Of course doing multiple image submissions was the hardest part and I had to basically refactor that whole area of the code.

The AI Horde queuing part was not as code intensive. Making a worker pick up multiple requests when possible was not particularly hard, but not giving the worker more than it can “chew through” was. You see your worker might be able to do 1 image at 2048×2048, and it might be able to do 20 images at 512×512. However give it 20x2048x2048 and it will fall down and die! So this required a bit of fancy footwork. The way I solved this is that the worker declares how many batched images they can do along with its max resolution. The horde then assumes that the worker can safely achieve their max batching at 1/3rd of their max resolution. After this part, as the requested resolution of a job increases, the horde will smartly reduce the amount of batches from a job it will give that worker.

Practically this means that when I declare I can do 20 batches and my max resolution for one image is 2048×2048, then I will pick my full 20 images at 512×512 but will only pick 7 images at my full resolution.

Therefore the AI Horde will continue smartly slicing a request for multiple images into a number of jobs. Only this time instead of each job being 1 image, it can be multiple. Effectively this means that the horde is able to way more efficiently utilize the maximum processing power of each worker and therefore the overall performance improves!

There were a few hiccups along this development as well. For one I realized that the hordelib code did not handle batching for img2img requests at all, so I had to pull up my sleeves and jump into the way hordelib translates requests to comfyUI nodes and figure it all out. It took me a while but now that I understand this better, it will make it easier for me to add even more fancy additions to our comfy workflows!

Another somewhat important problem is that the seed returned by batched requests in comfy is not accurate. The explanation of this is a bit too technical, but at the end of the day, there is extra variable when trying to replicate an image generated via a batch, on top of the generation seed. Currently the horde will return the relevant “batch_id” in the generation metadata, which I hope in the future to use so I can add a way to replicate images from batched requests as well.

For now, if you need to ensure you can always replicate your images via a seed, the best way to do it is to request them using the new disable_batching keyword on your request. Setting this to true will make your request always split to 1 image per job, which is the way the horde used to work until now. However since disable_batching is significantly less optimal than batching, it is only available to trusted users (i.e. those who’ve been running workers for a while) and patreon supporters.

Of course you can continue manually splitting your requests to 1 image per request, but that already has increased kudos costs, and in the future this might get disincentivized further for the health of the AI Horde.

Between batching and LCM proliferation, we’re already starting to see significantly improved generation times on the AI Horde. To the point that with enough priority, you can receive 20x1024x1024 images in less than a minute! A small problem is that currently one of our most popular frontends, Artbot, defaults to manually splitting each request to 1 per image. Nevertheless, Its developer Rockbandit is already hard at work making their requests batching-compatible and once that happens, I expect the overall speed with massively improve!

Rebuttals on the Fediseer

I noticed recently that a few instances are just issuing counter-censures on the Fediseer just to be able to reply to the censures they received from others. While I get the need to say your piece, I didn’t like this utilization. So I wanted to provide an official way for instances to reply to censures and hesitations they received.

So now we’ve deployed Rebuttals. A Rebuttal is a “reply” to a censure or hesitation from another instance. If you have received both, the same rebuttal applies. This is set up this way so that rebuttals are not tied to any specific censure/hesitation and therefore being deleted when those are. If someone deletes and re-adds their censure against your instance, the same rebuttal will re-appear.

As always, remember there’s no hate speech allowed on the Fediseer, so make sure your rebuttals stay cool.

Also keep in mind the Fediseer is not a forum. There won’t be multi-threaded discussions going on. The expectation is that you can use the Rebuttals to explain why a censure is bogus and whatnot. Not to maintain flamewars.

I know there’s plenty of beefs on the Fediverse. I’m hoping with this feature won’t become fuel for them, but rather a way for everyone to feel they have a say in a neutral ground. I hope this can serve as a de-escalation as well. Sometimes an instance might receive a hesitation or censure from someone they don’t dislike, due to a misunderstanding. This will allow them to try and counter that, without having to counter-censure.

Let me know what you think in the comments below, by replying to this post on mastodon, or in the lemmy community.

Btw, since I have you here, did you know that you can support the hosting and development of the Fediseer? Currently I’m paying the hosting costs out of pocket. It’s not a lot but it would be nice if the infrastructure costs were self-sustaining. So if you find value in this service, feel free to throw some money at the development team.

LCM and multiple versions of LoRas on the AI Horde

Finally 2024 is here and this allowed me a bit of free time to work on some of my NLNet tasks. The first thing on my list to tackle was adding LCM support on the AI Horde as it provides massively reduced steps, which for a crowdsourced service like ours, it makes all the difference in how much we can deliver.

For those who don’t know, LCM is a new breakthrough in Stable Diffusion that allows to “finetune” the model in such a way where an image can be generated using 10% of the steps previously required. So an image which would require 30 steps to converge, now needs just 3! That is a massive boost for lower-range GPUs. For high range GPUs, it starts avenues such as video generation as an image can happen at millisecond speeds!

Given the benefits, I wanted to work on this as soon as possible, and given the flexibility of the FOSS GenAI technology enthusiasts, we already had a great way to use LCMs, by using LoRas to turn any SD model into an LCM version.

However there was a snag. You see while the AI Horde already supports all LoRas on CivitAI, we never supported different versions of each, as we never expected anyone would want to use more than the latest. Unfortunately people on CivitAI started using the versioning system as “alternative” versions. And the LCM LoRa was using the same approach, where there was a version for each different sampler.

So the first order of business had to be to allow the AI horde to understand and support all LoRa versions of each LoRa! This took the better part of a full work-week of development and debugging, and then another week of troubleshooting and fixing in beta.

The good news is that this lead to us also identifying and squashing a very frustrating long-running bug where workers would rarely return previous images they’d generated instead of the ones requested. Getting someone else’s image is something we definitely don’t want to ever happen so we’re very happy we figured it out.

With that out of the way, I simply had to update the AI Horde itself to be able to handle the payload for specific LoRa versions, and then add support for the LCM sampler and then some ways to urge users to switch to it.

If you’re an AI Horde integrator, we strongly suggest you change your default settings to utilize LCM LoRas in your generations. You can get them from the same API you receive the model details, under the modelVersions key. To use them, you need to send the exact version ID as a string (found in modelVersions[#]['id]) this won’t accept a version name. You will also need to set is_version: true for the LoRa payload. This will tell the worker to look for a version instead of a LoRa ID.

Sending the LoRa name or ID will continue working as usual, grabbing the latest version (modelVersions[0]) from that list, so you existing implementations should continue working as usual.

Also we recently added AlbedoXL in our model list, to provide a better baseline for SDXL generations than basic SDXL 1.0 which requires a refiner to work. Using Albedo you can get generations that do not require a refiner in your workflow at all and get much less “fuzzy” generations in the process!

AI Horde to receive NLNet grant!

Back in July I first discovered NLNet and decided to apply for their NGI Zero Core grant to help me help me continue developing the AI Horde. Today I’m excited to announce that the AI Horde has officially been greenlit as one of the projects which will receive the August 2023 grant!

You can see the entry for AI Horde on NLNet here:

AI Horde has been a passion project from the start but it’s difficult to maintain the level of intensity I had for such a length of time. With my patreon funding significantly dwindling month-to-month, multiple of our backend developers dropping, and the need for me to also keep up with some of my real life duties as well as my other FOSS projects, development of the AI Horde has sadly slowed in recent months. While It rmains extraordinarily stable, it has had little to announce, and some new features are slower to “cook” and reliant in the work of valuable backend volunteers like Tazlin.

I am hoping that the addition of NLnet funding should help reintroduce some of that momentum as the release of the grant is contingent on specific milestones being reached.

I have plans for 5 roughly grouped areas of development, for which I have thought of various tasks to receive “bounties” for in the scope of this grant: AI Horde, Dreamer, Scribe, Alchemist and Godot Engine

The AI Horde tasks will focus on improving the middleware itself. Such as extending the shared key functionalities, improving the API documentation etc.

The Dreamer, Scribes and Alchemists tasks will focus on adding new functionalities to the the official workers, such as more generation workflows, batch processing etc.

Finally the Godot Engine tasks will improve the existing toolset of the AI Horde to support game development, such as improving my AI Horde Client, migrating it and Lucid Creations it to Godot Engine 4, etc.

The good news is that due to the way NLNet works, I had to submit stuff to work on, but I couldn’t work on them before the AI Horde was officially accepted (or rather, I could, but I couldn’t receive a “bounty” for them). Now that this is locked-in, I can start working on some of these with the added incentive of getting a reward at the end which can alleviate some of my ADHD executive disfunction. So if all goes well, you should start seeing more activity from me soon.

As always, if you want to support the AI Horde and my work in FOSS and the open commons, please do consider funding me at:

These funds go towards paying for the existing infrastructure first, and motivation continuous development second.

PS: Interestingly enough, it’s my birthday today too 😀

Magnagothica and my first LoRa!

A week ago or so, a new game came out from the creator of Kill Six Billion Demons (one of my most favourite webcomics that you should all go to read right now): Magnagothica: Maleghast

It’s a great world-building and incidentally it’s an idea for a type of setting that I have been thinking to make myself for years, and now someone plucked it straight out of my mind and made a really great version of it which just oozes style!

I have been enamored with this game since I first saw it. It hits ALL my buttons! Heavy Metal, Fantasy, Aesthetics, Boardgames. Only thing it could have done more is include even more metal genres as I’m not too keen on the extreme stuff and I’d love to see styles on Power or Prog Metal etc. But nothing we can’t extend ourselves!

But ye, as I mentioned, I’ve been hyperfocusing on it a bit too much. First I created a lemmy community for it. Then I started extending the music playlists for each house. And lastly I wanted to find a way to be able to not only create my own warband, but also to give individual art to each of my units. And for this, I finally had some necessary skills and hardware. It was time to train my first LoRa!

It took me a good 3 days to figure out how things work, create the necessary datasets, experiment with creation and retry until I got the hang of it. It didn’t help that the original artwork was, let’s say, challenging to work with. But I think in the end I am very proud to have managed to make something which seems to be capable of following the style well enough to create leaders and units.

I’ve found the best use of this lora is for Leader illustrations. To create a leader simply use the “necromancer, leader” tokens in your prompt. For leaders I suggest you set your Lora strength between 0.5 and 0.8. Remember to mention which house you want the leader to be in. The LoRa is pretty decent at copying the style of each house.

magnagothica maleghast, gargamox, drawing, necromancer, male, skinny leader, plain background, toxic green highlights, by tom bloom, sidecut haircut, chains, dripping, white coat###halftone

To generate units, you can choose to either generate unit portraits styles, or full unit illustrations. You can try to replicate the maleghast style with the halftone, or put “halftone” in the negative prompt to get a more sharp result. Personally I prefer to avoid the halftone look and try to make them look more full. You can also use the name of the unit to try to lead the lora to draw something like that unit. You can also use “ghoul” for humanoid undead and “abomination” for more monstrous looking units. For units I suggest you use model strength between 0.3 and 0.6

magnagothica maleghast, abhorrers drawing, full unit illustration, penitent, ghoul, scarred, spiky flail, plain white background, ochre highlights, by tom bloom###halftone
magnagothica maleghast, C.A.R.C.A.S.S., drawing, unit portrait, enforcer, ghoul, plain black background, fuchsia highlights, by tom bloom###halftone

You can check out the new LoRa on CivitAI, and as you’d expect you can also just try it out directly on the AI Horde!

Try it out and let me know what other uses you can find using this style. I think it has plenty of potential.

One expensive pencil

Watching through Thought Slime’s latest video it occurred to me that people who dislike generative AI art, don’t even understand those who do enjoy it and find nothing wrong with it. In this video, Thought Slime came up with a pithy comeback to the strawman they erected: “No longer are you gate-kept by the extremely costly fee of…a pencil.” (2:10) they say mockingly.

The truth is that that as the rest of that video explained, there is, in fact, a very high cost associated with doing manual art well: Time.

Doing decent art, even if mediocre from the perspectives of experienced artists, can easily take years of one’s life and there’s a lot of people who just don’t have this amount of time. Like it or not, the capitalist system we live in is exploiting all of us, and most people will never have the time to follow this passion.

So this mocking strikes me as not only misguided but also extremely privileged. Thought Slime has been fortunate enough to land onto the crossroads of skill, talent, time, race and upbringing that let them make a successful career out of making Youtube videos and Twitch streams. They are now turning towards all the wage slaves of the world using Generative AI and declare “you know that fun thing you like to do for yourself? Stop doing it unless you’re willing to sacrifice as much as I did”.

“Stop having fun unless you have money, or time”

Sure, people will argue, “but if you like art, then making art should be fun for you!”.

This is nonsense!

Not everyone likes doing art. Some people just like consuming art. Some people don’t have time to do learn to do manual art at all. Some people are neurodivergent or disabled in certain ways which forbid them from doing it altogether.

People like seeing pretty things. Do you know what they like most of all? Seeing pretty things that came from their own brain. Imperfection of the final result is besides the point. Generative AI allows people to do this quickly and painlessly, with almost every kind of PC one has available.

So some people just like to put something close to what they have in the thoughts onto (digital) paper and show others and say “this is what I thought of, what do you think”? There’s nothing wrong with that. There’s no need to go to these people and tell them that they’re bad people unless they have a couple thousand hours or more to spend.

I saw, If you just like putting your own thoughts onto drawings with minimum fuss, go nuts. There’s literally no harm in it. And if you like making art, then do that. If you like both making art but want to do it faster, then combine your skills with Generative AI get the best of both!