Sign in

Zicklag

@zicklag.dev
897 followers 197 following 1.5K posts

I strive to make great things that people can use and enjoy, all to the glory of God. Links & Bio Page: zicklag.dev GitHub: github.com/zicklag Making @roomy.space

PostsRepliesMedia
Zicklag @zicklag.dev · 20/07/2026
This is cool, I just left an @atstore.fyi review on @standard-reader.app right inside of the Standard Reader App. It prompted for auth again so that it could request the scopes needed to write the review, but I didn't have to leave standard reader my review instantly shows up on its store listing.
Screenshot of my 4 star review of standard reader on the atstore.fyi app:

Very nice. The best standard.site reader I've seen so far.
1314
Zicklag @zicklag.dev · 13/07/2026
@leaflet.pub I've got a little UI issue. In a thin window, I'm unable to edit my footnote without the toolbar covering it up.
Screenshot of the footnote edit toolbar covering up the footnote that I'm editing.
280
Zicklag @zicklag.dev · 08/06/2026
It worked! I was able to send a Bluesky post under an "org account" while logged in under my own account, because the org account used our new arbiter server to create a policy allowing me to do so. These policies can be as advanced as you like, restricting based on lexicon, user role, etc.
Picture of the arbiter manager debug interface for creating records.Picture of the arbiter manager policy editor.
6827
Zicklag @zicklag.dev · 05/06/2026
Day 3 of using Comic Shanns for my code and editor. github.com/shannpersand... So far I'm liking it. 😃
Screenshot of Zed using Comic Shanns for the editor and the code.
000
Zicklag @zicklag.dev · 03/06/2026
Almost got the flow finished.
Screenshot of the multi-step arbiter community account setup.

Steps: overview, sign in, app password, email code, admin, done.
020
Zicklag @zicklag.dev · 21/05/2026
Tri Force Heros is the most intense teamwork game I've ever played if you want to step it up a notch. en.wikipedia.org/wiki/The_Leg...
Picture of a portion of the game's back cover.

Has three players stacked on top of each other's shoulders.

The middle one is saying "Go!", the top one is saying "OK!", and the bottom one is saying "!?".

Text says: Totem Time! Stack up with your teammates to overcome challenges and navigate dungeons.
020
Zicklag @zicklag.dev · 20/05/2026
No attempt to hide it huh @trezy.codes? 😁 > HappyView is the best way to build an AppView for the AT Protocol. Found an excuse to try you out @happyview.dev. Will be judging you. 🧐
Screenshot of HappyView's docs highlighting the text: "HappyView is the best way to build an AppView for the AT Protocol."
1171
Zicklag @zicklag.dev · 19/05/2026
Wow, look at @lexicon.garden pointing out my breaking changes. I didn't know you were watching! I wasn't done yet! 😄
Screenshot of lexicon.garden showing a lexicon diff of my town.muni.arbiter.defs lexicon with breaking changes: 2 added constraints.
1180
Zicklag @zicklag.dev · 14/05/2026
I have just finished an interactive arbiter simulator that runs right in the browser! The arbiter is our attempt at an interoperable group management system for the ATProtocol and permissioned spaces. zicklag.github.io/leaf-0.4/arb...
Screenshot of the arbiter simulator web UI.
1306
Zicklag @zicklag.dev · 07/05/2026
Here's another cool one. This tests what happens when two people try to submit requests to add a user at the same exact time. Quint selects a random request that will be handled first and our test makes sure that one succeeds and the other fails under any of the random scenarios.
/// Try to have both alice and bob try to add a member to a space with a remote delegation at the
  /// same time, and show that only one of the requests is accepted.
  ///
  /// TODO: this test makes me realize we aren't telling you when a particular job errors so the
  /// runtime isn't cleaning up the errored jobs.
  run twoOwnersAddAMemberToSpaceWithRemoteDelegationSimultaneouslyArbiterTest =
    initScenario1
      // Alice sends a request to add a new member
      .then(sendMsgFromUser("alice", "b", "subcom", "$admin", XSetMemberAccess({ member: MemberUser("newMember1"), access: AddMembers }), 2))
      // Server B handles it, but will start a job that needs to resolve the member list from server a
      .then(handleMsg("b"))
      // And Bob sends one immediately after for a different user
      .then(sendMsgFromUser("bob", "b", "subcom", "$admin", XSetMemberAccess({ member: MemberUser("newMember2"), access: RemoveMembers }), 2))
      // Server B handles it, but will start another job to handle the member list from server a
      .then(handleMsg("b"))
      // Server A handles both of the resolution requests and will send replies to server B. It's
      // nondeterministic which one it handles first.
      .then(handleMsg("a"))
      .then(handleMsg("a"))
      // Server B will handle one of the resolutions, which should succeed
      .then(handleMsg("b"))
      // At this point the arbiter should have successfully completed the 
      .expect(match(choreo::s.system.get("b").arbiters.get("subcom").result) {
          | ArbiterFinishedJob(job) => job.result == JobOk
          | _ => false
        })
      // Now server B handles the next reply, which will attempt to complete the second job.
      .then(handleMsg("b"))
      // But this will error because the state has been changed since the request was submitted by
      // the earlier request.

// out of space in alt text...
120
Zicklag @zicklag.dev · 06/05/2026
I'm doing it! Running a multi-server simulation of the arbiter specification using @quint-lang.org! This test will send a message to one arbiter, which will resolve a remote member list on another arbiter, and use the space hierarchy to calculate the final member list and access levels.
  /// Resolve a space with several layers of delegation including remote delegation
  run resolveAcmeDevChannelArbiterTest =
    // Setup scenario 1
    initScenario1
      // Send message from user to resolve member list of #dev channel
      .then(sendMsgFromUser("alice", "a", "acme", "#dev", XFetchMembers, 2))
      // Have server A handle the message
      .then(handleMsg("a"))
      // That will trigger a message to resolve a member list from server B, which handles
      // its message
      .then(handleMsg("b"))
      // Which will send a reply to server A, which handles that message
      .then(handleMsg("a"))
      // And finally alice will have a response in her messages with the member list
      .expect(
        choreo::s.messages.get("alice").exists(msg =>
          match (msg.kind) {
            | ReplyResolvedMembers(result) =>
              result.members.memberList == Map(
                // Admins of acme server
                "alice" -> Owner,
                "bob" -> Owner,
                // Moderators of acme server
                "charlie" -> RemoveMembers,
                "dave" -> AddMembers,
                // Admin of remote #gaming space
                "georgia" -> IsMember,
                // Members of remote #lobby space
                "henry" -> IsMember,
                "grace" -> IsMember,
                // Member of remote #gaming space
                "ivan" -> IsMember,
              )
            | _ => false
          }
        )
      )
2111
Zicklag @zicklag.dev · 26/04/2026
@orhun.dev Using @ratatui.rs indirectly through the @quint-lang.org trace explorer, which rocks! 🚀 github.com/informalsyst... Helped me trace the root cause of a crash in the arbiter I'm implementing. This was super easy to use.
Screenshot showing a state diff in the TUI with overlay text:

The Culprit: Why do we still have job 19 in the queue when we just said that it finished OK with a resolved member list?
081
Zicklag @zicklag.dev · 25/04/2026
This is actually really cool. Seriously, having threads and profiles open in new windows might just be a way better interface. I got used to it but microblogging interfaces are just so suffocating. Maybe… it might feel better to get lost in too many windows than to be forced into one big line.
Screenshot of my AtmoXP window right now.
4294
Zicklag @zicklag.dev · 18/04/2026
Sweet, it worked!
Screenshot of my latest Leaflet on the @atmosphere community site in the community content section.
140
Zicklag @zicklag.dev · 04/04/2026
Discord was almost called Bonfire to indicate a nice and cozy place Instead we get Discord. Definition: - lack of concord or harmony between persons or things - disagreement; difference of opinion - strife; dispute; war - any confused or harsh noise; dissonance. I wonder why they changed it. 😆
Screenshot of Discord "Did you Know" loading screen saying:

Discord was almost called Bonfire before we picked our name. It was meant to be nice and cozy.
1160
Zicklag @zicklag.dev · 28/03/2026
Another slide. > The [TLA+] abstraction helped a lot in coming to a much cleaner architecture ( we witnessed first-hand the brainwashing done by years of C programming). One of the results was that the code size was about 10x less than in [the previous version].
Talk slide:

The next version of Virtuoso.

It's high-level design is described in TLA+.

Here's an email from Eric Verhulst, the head of the development team.

The [TLA+] abstraction helped a lot in coming to a much cleaner architecture ( we witnessed first-hand the brainwashing done by years of C programming). One of the results was that the code size was about 10x less than in [the previous version].
010
Zicklag @zicklag.dev · 28/03/2026
Leslie Lamport: > Coding should be the easiest, lest important part of programming. > If you're having trouble writing a piece of code, you're doing something wrong. Some great points for these couple minutes of the talk: youtu.be/8-Bc5Lqgx_c?...
Screenshot of Leslie Lamport giving a presentation with his slides.
160
Zicklag @zicklag.dev · 26/03/2026
Lucky @roomy.space server build? 256 seconds has to be lucky, right?
Mar 26 2026 11:12:39    Build time: 256.23 seconds
170
Zicklag @zicklag.dev · 25/03/2026
I *love* this radio analogy! I think that it instantly breaks down some difficult barriers to understanding the nature of what is happening with the "AT" protocol.
Take radios for example. You can buy any regular radio and listen to the same airwaves as anyone else because of the standardized AM/FM frequencies. I don't know what those letters mean, but I do know those letters represent a network of antennas and radios that have brought my family a lot of joy on car rides and cabin trips.

Every radio "speaks" AM/FM because it has been built in accordance with a standardized protocol for how to engineer a radio that can receive the AM/FM signal.

The AT protocol is another such standard, but for social media signalling. Messages, discussion threads, links, images, events and profiles, these are all common social media signals. Once a website speaks AT it can communicate with all other websites in the AT network, which we protocol nerds affectionately like to call The Atmosphere.
0140
Zicklag @zicklag.dev · 25/03/2026
Hey! They're still weird bespoke event tools. /jk But seriously, ATProto does almost "convert" the kind of bespoke tools you might write into widely useful things because it benefits from the existing network of people, lexicons, tech, etc.
Classy pooh bear meme:

Weird bespoke event tools / ATProto-powered weird bespoke event tools.
151
Zicklag @zicklag.dev · 24/03/2026
This touches on something that FizzBee helps a lot with compared to pure TLA+. It makes it very easy to write the spec similarly to pseudo-code while experiencing the failures associated with real async code. muratbuffalo.blogspot.com/2026/03/mode...
This brings us to an important lesson about formal verification and system design: the paradigm gap. Pure TLA+ is a beautiful event-driven way to describe the mathematically correct state of your system. However, the environments where these systems actually live (Java, Go, C++, or Rust) are fundamentally built around sequential threads, loops, and queues, just like our PlusCal model. The impedance mismatch between an event-driven specification and a sequential implementation introduces the risk of HOL blocking. Because modern programming languages make it so effortless to pause a thread and wait for a resource, it is incredibly easy for a system to fall into the blocking trap. We should be cognizant of this pitfall when implementing our designs.
012
Zicklag @zicklag.dev · 21/03/2026
BTW, noticed a small UI glitch:
Screenshot of an event with the text running off the dialog box to due to a long URI in the description.
030
Zicklag @zicklag.dev · 20/03/2026
I just got my first messages over the firehose / jetstream! Thanks to @mary.my.id for the nice atcute libs! I've been here for over a year now, so I suppose it's about time I tried this out myself! 😄 I'm pulling @stream.place messages that _might_ end up in @roomy.space somehow. 👀
Screenshot of stream.place chats showing up in my terminal since I subscribed to them with a firehose script.
1364
Zicklag @zicklag.dev · 16/03/2026
Today, several days after creating my first draft in Bluesky, I finally found out where it went.
Picture of the Bluesky new post dialog with an arrow pointing at the drafts button that is next to the post button.
040
Zicklag @zicklag.dev · 13/03/2026
I guess it's official, I'm THE Zicklag, now. /jk I wonder how close I come close to the record of "fewest followers when verified by Bluesky". It looks like I had 608 followers at the time they verified me. Anyone else get verified with less followers? 😁
Screenshot of the "Bluesky verified you" notification in the Bluesky app.
1251
Zicklag @zicklag.dev · 09/03/2026
First off this builds on @standard.site, which is a standard schema for sharing publications, documents, and subscriptions in a way that can be indexed by any ATProto app. For example, I can make a publication using leaflet.pub and have it be automatically discovert in the pckt.blog
Screenshot of pckt.blog showing a couple of Zicklags posts from leaflet.pub.
192
Zicklag @zicklag.dev · 02/03/2026
@flo-bit.dev seriously. 😏
Time lock titled: my bank details and all my passwords.

Opens in 974 years 7 months 25 days 23 hours 50 minutes and 20 seconds.
270
Zicklag @zicklag.dev · 02/03/2026
The definition of Legacy Code: Code that I wrote more than a week ago. The AI summary agrees with me:
Legacy code refers to software that is still in use but was developed with outdated technologies, lacks adequate documentation, and is difficult to maintain or modify.
000
Zicklag @zicklag.dev · 19/02/2026
I haven't read them, but the list of headlines beneath this post is crazy. 😵‍💫
List of blog posts:

AI Completely Failing to Boost Productivity, Says Top Analyst

It Turns Out That Constantly Telling Workers They’re About to Be Replaced by AI Has Grim Psychological Effects

The Number of People Using AI at Work Is Suddenly Falling

Workers Say AI Is Useless, While Oblivious Bosses Insist It’s a Productivity Miracle

Researchers Studied What Happens When Workplaces Seriously Embrace AI, and the Results May Make You Nervous

Microsoft AI CEO: Virtually All White Collar Tasks Will Be Automated Within a Year and a Half

Majority of CEOs Alarmed as AI Delivers No Financial Returns

Economist Warns That the Poor Will Bear the Brunt of AI’s Effects on the Job Market
000
Zicklag @zicklag.dev · 19/02/2026
dialed.gg First try:
The score for the game:

You ranked 30,900 out of 323,247

46.00/50

Tetrachromat or obsessive? Either way, maybe go outside.

Challenge a friend to beat 46.0.

Play again
020
Zicklag @zicklag.dev · 02/01/2026
@standard.site this is awesome! This is awesome! I had a thought reading this Q&A: if multiple apps extend the lexicon with the same key, but a different schema, then that can overlap in unintended ways like pinnedPosts did once: docs.bsky.app/blog/pinned-...
Screenshot of Q&A question: Can I extend the lexicons?

Yes. Additional properties pass through validation. Platform-specific features can live alongside the standard fields. The schema defines a shared baseline, not a constraint.
1121
Zicklag @zicklag.dev · 19/12/2025
We already have an explorer app for Leaf that can be used to query from streams! You can use it to send events too. It's kind of like the excellent @pdsls.dev but for Leaf. Here is the first event sent in a Roomy "personal stream". You might notice it looks kind of like an XRPC call.
Screenshot of the Leaf explorer app, showing the admin add event of a roomy space.
191
Zicklag @zicklag.dev · 18/12/2025
Nerds behold, the very first Leaf stream DID: did:plc:tqd32oyrvfdkzh62zmk3tftv Soon every space in @roomy.space shall have it's own Leaf stream with it's own DID.
Code screenshot:

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/multikey/v1",
    "https://w3id.org/security/suites/secp256k1-2019/v1"
  ],
  "id": "did:plc:tqd32oyrvfdkzh62zmk3tftv",
  "alsoKnownAs": [],
  "verificationMethod": [
    {
      "id": "did:plc:tqd32oyrvfdkzh62zmk3tftv#leaf_server",
      "type": "Multikey",
      "controller": "did:plc:tqd32oyrvfdkzh62zmk3tftv",
      "publicKeyMultibase": "zQ3shmenhzahSPKF4NRzTAnHnG8roQ8YqhBAetLpYpY4uL47G"
    }
  ],
  "service": [
    {
      "id": "#leaf_server",
      "type": "LeafServer",
      "serviceEndpoint": "https://leaf-dev.muni.town"
    }
  ]
}
2204
Zicklag @zicklag.dev · 23/10/2025
I love the point made here. We actually _need_ to do the work, and feel the pain, of our existing situation to be motivated to understand and fix it. I think often times we don't understand how important our suffering is to a victory that actually matters. "Beware of unearned wisdom" - Carl Jung
Can clear insights distill without dust, tear, and sweat?
One may argue that with machines handling the grunt work, the researchers would finally get more time for thinking. Our brains are --what?-- yes, lazy. Left idle, they will scroll Reddit/Twitter rather than solve concurrency bugs.

I suspect we need some friction/irritation to nudge us to think in the background. And I suspect this is what happens when we are doing the boring work and working in the trenches. While writing a similar code snippet for the fifth time in our codebase, an optimization opportunity or an abstraction would occur to us. Very hard problems are impossible to tackle head on. Doing the legwork, I suspect we approach the problem sideways, and have a chance to make some leeway.

Yes, doing evaluation work sucks. But it is often necessary to generate the friction and space to get you think about the performance, and more importantly the logic/point of your system.  Through that suffering, you gradually get transformed and enlightened. Working in the trenches, you may even realize your entire setup is flawed, and your measurements are garbage due to using closed loop clients instead of open loop ones.

What happens when we stop getting our hands dirty? We risk distilling nothing at all. Insights don't bubble up while we are sitting in comfort and scrolling cat videos. In an earlier post, Looming Liability Machines (LLMs), I argued that offloading root-cause analysis to AI misses the point. RCA isn't about assigning blame to a component. It is an opportunity to think about the system holistically, and understand it better, and improve. Outsourcing this to LLMs strike me as a very stupid thing to do. We need to keep exercising those muscles, otherwise they would atrophy alongside our understanding of the system.
063
Zicklag @zicklag.dev · 22/10/2025
The latest experimental release of Roomy has pages! Pages are markdown under-the-hood, and have a simple WYSIWYG. They also track the edit history like a wiki!
Screenshot of Roomy showing a rich text page with an edit button on it.
1346
Zicklag @zicklag.dev · 25/09/2025
We've been hard at work for the last month on a new @roomy.chat architecture that we hope will get us into production: A Brief History of Roomy's Architectures blog.muni.town/brief-histor... I'm very excited about the new design and the performance that we're showing on our initial tests!
23712
Zicklag @zicklag.dev · 20/09/2025
My live query for Roomy's space list.
Code sample:

const spaces = new LiveQuery<{
  id: string;
  name?: string;
  avatar?: string;
  description?: string;
  admins: string[];
}>(
  `select json_object(
    'id', format_hash(id),
    'name', name,
    'avatar', avatar,
    'description', description,
    'admins', (select json_group_array(admin_id) from space_admins where space_id = id)
  ) as json
  from spaces
  where stream = ? and hidden = 0`,
  () => [
      Hash.enc(backendStatus.personalStreamId),
  ],
  (row) => JSON.parse(row.json),
);
120
Zicklag @zicklag.dev · 18/09/2025
No, way... Turso, a Rust rewrite of SQLite that is approaching public beta, is actually experimenting with incremental view maintenance and query subscriptions. I thought it was beyond hoping to get that kind of feature in SQLite, but we might be a lot closer than I thought. @tur.so is insane! 🤩
Screenshot:

The database has the following experimental features:

BEGIN CONCURRENT for improved write throughput using multi-version concurrency control (MVCC).
Incremental computation using DBSP for incremental view mainatenance and query subscriptions.
0174
Zicklag @zicklag.dev · 13/09/2025
I just setup reactive SQLite queries for Svelte. You can set reactive SQL bindings, and you can even make the SQL query itself reactive so that you can use a query builder that depends on reactive UI variables! This is going to be fun to see how nice it ends up to use in an actual UI.
Code snippet:

<script lang="ts">
let surname = $state('smith');

let users = new LiveQuery<{ name: string; surname: string }>(
    'select name, surname from users where surname like ?',
    () => [surname || '%']
);
</script>

<input bind:value={surname} />
<ul>
	{#each users.result?.rows || [] as user}
    	<li>{user.name} {user.surname}</li>
	{/each}
</ul>
1172
Zicklag @zicklag.dev · 09/09/2025
I just made a little script that makes it way nicer to communicate with worker scripts in the browser over typed, async function calls. It's a simple 62 line script that can be dropped in and used to wrap around any browser MessagePort. gist.github.com/zicklag/2d7e...
Code sample:

// Use Vite shared worker import
import MySharedWorker from './mySharedWorker.ts?sharedworker';
// Import my message port interface wrapper function
import { messagePortInterface } from './messagePortInterface';

// Define the interface for the main UI thread.
// The workers will be able to call these functions on the UI thread.
export type MainThreadInterface = {
	getLoggedInUser: () => Promise<string>;
};
// Define the interface for the shared worker.
// The UI will be able to call these functions on the worker.
export type SharedWorkerInterface = {
	doBackgroundWork: (arg1: string, arg2: number) => Promise<string>;
};

// Initialize shared worker
const worker = new MySharedWorker();

// Create the interface over the message port
export const workerInterface = messagePortInterface<MainThreadInterface,SharedWorkerInterface>(
  worker.port,
  {
    // Implement the main thread interface
    getLoggedInUser() {
      return 'username'
    }
  }
);

// We can now call the worker interface
const response = await workerInterface.doBackgroundWork("John", 77);
041
Zicklag @zicklag.dev · 07/09/2025
Side note: authenticating to ATProto and then connecting to our experimental Leaf server using our new API client is very easy.
Screenshot of code block:

import { LeafClient } from "@muni-town/leaf-client"

import { AtpAgent } from '@atproto/api'

const agent = new AtpAgent({
  service: 'https://bsky.social',
})

const password = Deno.env.get('APP_PASSWORD');
if (!password) throw "Need APP_PASSWORD env var";

await agent.login({
  identifier: 'zicklag.dev',
  password,
})

const leaf = new LeafClient("http://localhost:5530", async () => {
  const data = await agent.com.atproto.server.getServiceAuth({
    aud: "did:web:localhost:5530",
  });
  return data.data.token;
});

await new Promise(resolve => leaf.on("connect", () => resolve(undefined)));
console.log("Connected to leaf")
050
Zicklag @zicklag.dev · 28/08/2025
And now I have ATProto authentication on a socket.io connection. 📡
Screenshot of a Socket.io debugging client with the response showing the authenticated DID of the user.
030
Zicklag @zicklag.dev · 23/08/2025
Roomy is under heavy development right now and isn't ready for general use just yet, but we're making lots of progress and the UI is coming along quite nicely.
Screenshot of the threads view in the Roomy app.
040
Zicklag @zicklag.dev · 12/05/2025
I started playing around with making an NES game. It's so crazy to learn about the limitations you have to work with on real NES hardware. Every time you think you know how limited you are, you discover another limit! It's like interacting with history.
130
Zicklag @zicklag.dev · 06/05/2025
I love the focus on just making a good game with a good story.
Green Ember: Helmer in the Dragon Tomb

Has:
- A Hospitable Heart
- An Immersive World
- A Moving Story
- A Moral Universe
- Genuinely Fun Adventure
- Cool Fighting Gameplay

Doesn't Have:
- Predatory Ads
- Creepy Chat Features
- In-game Level-up Purchases
- Endless Addiction Cycles
- Glamorized Immortality
120
Zicklag @zicklag.dev · 26/04/2025
There's a little bit of advantage to paying for it I guess.
Surge Professional
For unlimited production-ready projects
Only $30 / Month

Unlimited projects
Unlimited publishing
Custom domain
Custom SSL
Force http to https
Cross-Origin Resource Sharing
Custom redirects
Password Protection

Upgrade to Surge Professional
020
Zicklag @zicklag.dev · 20/04/2025
@roomy.chat now has editing! ✏️ 🎉 Thanks to @nandi.weird.one for the pull request and to @michaelschultz.com for reviewing and merging!
Chat message in Roomy by Zickag: "I just saw that edits were merged!! 😲"

Has a "✏️ Edited" marker underneath of it.
0245
Zicklag @zicklag.dev · 06/04/2025
Modern game development at it's finest.
Single frame comic with stick figures in a business meeting at game studio:

Presentation guy: "You see, we're thinking about it all wrong. We're not making _games_. We're making *ads* that people can play!

Other business members have light bulbs with dollar signs in them above their heads.

Art inspired by XKCD #2277
181
Zicklag @zicklag.dev · 01/04/2025
@roomy.chat now has minimal wiki pages thanks to help from @ kimlimjustin.com! Now you can have conversations in chat and trivially go and save those important thoughts for later, and for future members, in a wiki doc without losing context!
Screenshot of Mushroom Recommendations wiki page in the Roomy app.Screenshot of chat discussion:

Zicklag: Hey there! I've never eaten a mushroom before.

business goose🪿: nary a single mushroom? you should try some they're pretty good

Zicklag: No not yet! Any recommendations? 🙂

♆ • vantage point independence: if you search for mushroom marinade on bluesky, both top and latest tabs have good reccos :)

Zicklag: Neat! I made a wiki page and added your recommendation to the list.
2204
Zicklag @zicklag.dev · 31/03/2025
You can create your own if you want to test out wikis. ( Shown in the screenshot. ) Or you can join roomy.chat/-/roomy.chat. It will show a "Join space to chat" button at the bottom to add it to your server list.
010