2048

A social puzzle of tiles, people, and momentum

Game
2048 — A social puzzle of tiles, people, and momentum

About

2048, but the tiles are the people and communities you follow on the open social web. Stack, merge, and chase the biggest board possible.

AT Protocol records

Data this game reads from or writes to your account.

Uses

  • blue.2048.gamestats
    Game states automatically synchronize across compatible 2048 gamesHow to get this
  • blue.2048.player.statsstats
    Persistent stat tracking across compatible 2048 gamesHow to get this

Listed from atmosphere.games. The developer manages this listing there.

Reviews

No one has reviewed 2048 yet. Yours could be the first.Write the first review
Your identity isn't your usernameWhen I first registered at Bluesky, my username was "@gxjansen.bsky.social". Some months later I changed it to my current one: @gui.do. My followers didn't notice. My posts didn't break. My data didn't move. Instagram, LinkedIn and other legacy social media providers will (mostly) let you rename yourself too. What's different on atproto is what sits underneath the name. On a closed platform your identity is theirs: your account, your followers and your posts all live in one company's database and it only works inside their app. You are just renting your little space in it. On atproto it's yours. Your identity becomes a key you own, and everything hangs off it, so you can change your name, move your data to a different host, open a different app, or publish in a different format, and it's still you, still yours and your followers can still access your content. On the platforms you're used to, you can change your name but you can't own it. On atproto, you can do both. The problem: Identity as a row in their database Think about what your identity actually is on a closed platform. You don't own your username: it's a name they let you use, one row in their database with your posts and connections hanging off it. Useful for them, fragile for you. Delete that row and you stop existing there. Get suspended, and your name can be handed to someone else. You can't take it with you, and you can't run it anywhere they don't allow. Because your name, your identity and your followers are all fused into that one row, the name carries all the weight: lose it and you've lost the person, the username gets reassigned, old links break, and there's nothing underneath to fall back on. atproto doesn't tie your identity to... ...your name Dan Abramov puts it well in his "Open Social": "Your internet handle being something you actually own is the most user-visible aspect of open social apps." Start with the name, since it's the part everyone sees. On a closed platform your @name is a slug you rent in the company's namespace: they can reclaim it or reassign it, because it's theirs, not yours. On AT Protocol your username can be a name you genuinely own, a domain like gui.do. Either way it's just a label pointing at your real identity underneath, so you can change it whenever you like and nothing attached to you moves. The display cabinet from Episode 1 fits this exactly. Your cabinet has a serial number etched into the wood: permanent, yours, not a row in someone's ledger. Your username is a label on the door. Peel it off, swap it for a new one, and nothing inside changes. Swapping the label is the easy part. Owning the name, and the cabinet it's stuck to, is the point. ...your host If you own your own domain name, you already had this flexibility since the beginning. Switching to another e-mail provider is easy: your own address @ your own domain stays the same whether Google, Fastmail, Proton or your own server is delivering it, because it belongs to your domain, not the provider. Same with your phone number: switch carriers, keep the number, nothing breaks. The thing you hold stays put: the company behind it is swappable. atproto brings that same portability to where your identity is hosted. Dan Abramov did exactly this recently: he moved his hosting from Bluesky to Eurosky (the European non-profit from Episode 1) and his username, his followers and his posts didn't budge, same as repointing your domain at a new e-mail host. As he puts it, where your data is hosted and who you are were never the same thing: "hosting and aggregation are two separate things." ...a single app If you make things for an audience, your name is your reputation, and on a closed platform that reputation lives inside one app. Illustrator and author Debbie Ridpath Ohi wrote a clear non-technical explainer of why this matters to creators: "Readers will recognize you, not which app you're using." On closed platforms your audience is recognising an account inside an app, and that account only exists there. The same person is a fresh, unconnected account on every other network. When your identity is a key you own, recognition attaches to you instead, and the app becomes just today's viewer. You can see this already. Flashes shows your photos to the same Bluesky followers you already have. Leaflet lets you publish long-form under that same identity. One name, recognisably the same person in each, because it's one identity underneath, not separate accounts that happen to share a name. ...one content format Each platform centres one format and rewards it above the rest. Instagram leans on photos and short video, YouTube on video, blogs on long text, podcasts on audio, microblogging on short text. They've all bolted on the others (Instagram has text Notes and Threads, YouTube has Shorts and podcasts), but the audience you build still lives inside that one app, so you're pushed toward the shape it favours, whether it suits the work or not. If you publish in more than one format, the old platforms make you choose: stop doing it, force everything into a single app's shape, or run multiple accounts and grow a separate audience on each. Of course there are (strained) workarounds: people post Instagram "stories" that are really just text on a coloured background, because that's the only way to say something wordy to an Instagram crowd. Musicians upload a track to YouTube as a still image over audio, because that's where the listeners are. The format is wrong for the medium: the reach is the only thing keeping them there. atproto doesn't fully fix this: an app still shows what it's built to show. But the app can actually show multiple formats (e.g. both Sifa ID's activity stream and sill.social already do this). And because your identity, your followers and your posts are yours, not locked inside one app, a new medium doesn't mean a new identity or starting from zero. You publish in whatever format fits, under the same you, and the people who know you can pick it up wherever it lives. (Episode 4 gets into how apps share posts and audiences across formats.) Verifying who's behind the key And there's a flip side to the old world where anyone can spin up a username: squatters grab names, and impersonators try to pass themselves off as you to hoover up your followers. So once your identity is just a key, how does anyone know the key belongs to who it claims? The domain-based username from earlier answers that too: a name you own doubles as proof it's really you. Take a New York Times journalist with the username @jane.nytimes.com: provably someone the Times put on its own domain, because only the Times controls nytimes.com. No blue-check approval queue, no central authority deciding who's real. If you own the domain, you own the proof. I use gui.do as my username for exactly this reason: the username is the credential. This is also what takes the wind out of squatters. Because your username is your domain, it's yours on every atproto app at once, including ones that don't exist yet. There's no separate name to claim on each new app, no landgrab, no racing to register @yourname before someone else grabs it. Sign into a brand-new app and you're already @gui.do there, because you're the only one who can be. That whole "quick, claim your name before it's gone" reflex just stops being a thing. Domain verification like this is the floor, not the ceiling. The harder question, "is this really who they say they are, beyond owning a domain?", still stands, because someone can always register a domain that looks like yours. It's a challenge I've been working on with a couple of others: a draft proposal for verifying specific claims (that you finished a course, that you work where you say you do) as scoped, public attestations by someone in a position to vouch, instead of a government-ID upload or a checkmark handed down from above. Whether that beats today's blue checks, I don't know yet. Not solved, but definitely being worked on! Where we still need improvement Two worries you might have (that are actually up to you, not atproto): 1. your username being a domain: domains expire, get sold, or have their DNS hijacked, the same risk you'd run using your own domain for e-mail (Rescorla wrote up the weak points early). The saving grace is that losing the domain costs you the label, not the identity underneath, so you point a new username at the same key and carry on. Just make sure you enable auto-renew for your critical domains and pay the invoices on time, and you should be good. And of course properly protect your domain registrar login, which brings us to the next point... 2. the plain old stolen password, which no one has really solved for big audiences. It's your job to take care of a unique password in a password manager, and two-factor or a passkey wherever your app supports it. Both for your atproto account and for your domain registrar. One issue that's still atproto's to fix (or rather: its ecosystem) is the directory that turns your key into something apps can look up: it's still mostly run by one company (Bluesky). The overall protocol is decentralised, but that lookup layer, in practice, isn't yet. Moving it to an independent non-profit is in progress, and it's not the only group working on it: Eurosky, the non-profit from earlier, already runs its own copy of that directory and most of the rest of the plumbing. Until it's genuinely spread across many hands, "your identity is yours" is true by design and still partly on loan in operation. But the network is still young and a lot of initiatives to address these issues are quickly being rolled out. So how about the actual place where you store your data? Ok so your identity is a unique key you hold, and your username is a label you can change at will without losing a single follower. That fixes who you are. And you already got a glimpse of the rest moving with it: people are already switching from Bluesky to Eurosky, to Blacksky, or even self-hosting their content, and when they do, it all comes along. So if your content doesn't live in the app... where DO your posts, your articles, your photos, five years of history actually sit? And what happens to all of it when it's not you leaving, but the app you used shuts down for good? See you in Episode 3. --- Episode 2 of 7. Full series at /series/atproto/. I'm building two products on atproto (details on the series page).Jul 1, 2026Who actually owns your network?If your LinkedIn account vanished tomorrow, your contacts wouldn't survive the move. Yet it doesn't have to be this way. I've moved communities and networks between platforms more times than I'd like: Slack, Facebook Groups, LinkedIn, Meetup, forums, Twitter, sometimes as the main channel, sometimes a side tool. Every move charged a huge tax on the way out: the people who didn't follow to the new place, the years of conversations stranded in a database neither I nor the members controlled. Realistically, half the audience never makes the jump. It's built that way on purpose. Platforms like LinkedIn don't want you to leave: they want everyone to stay put and become dependent on them. But making it impossible to leave with your own contacts and your content is less of a happy relationship and more akin to a hostage situation. Platforms come and go. However big one looks today, there's a new hype around the corner. What keeps costing you, and your contacts, is the lock-in architecture underneath them all. The tax is built in Take Slack's free plan: After 90 days your message history vanishes. Not deleted though, just hidden: they keep your data on their servers (and may well keep training on it), then charge you to see your own conversations again. You wrote it, they store it, you rent access to it. SaaS platforms change their pricing simply because they can and the math stops working for you. Twitter didn't just rename to X, the whole environment changed. Discord decided my community suddenly needed ID verification. None of these were about us, they were business decisions at companies I didn't own, and every time my contacts or community members paid part of the bill. And you can't take your LinkedIn, Instagram or Twitter contacts to a different platform. Not because it's technically impossible, but because whoever built it made sure the door only opens one way. That's purposeful architecture, not just the way it HAS to be. It should be about the people, not the platform (nicely put by Anuj Ahooja). You already accept the opposite, every day Think about your phone number. You switch carriers and keep it. You call anyone, on any network, and it just works. Same with e-mail. Now picture a phone that only let you call people on your exact carrier, and the day you switched, you lost every contact and every past conversation. Absurd, right? Nobody would sign up for that. But that's how social platforms of the past 20 years work. Your contacts only exist inside one app, and you can't bring them with you. You know what the (yes, boring but important) difference is between social networks and things like e-mail and phone networks? Protocols. Apps as views, not vaults Open Protocols work for e-mail and phone numbers. They can work for social media too. Picture a protocol where the things you make, your posts, your photos, your follows, your reviews, are all yours, stored and shown off in something like a display cabinet that others can view, but you own and control. Apps are just the viewers that look into it. You can swap the app, and just give them access to your cabinet. Dan Abramov wrote a great technical explainer of this in his "A Social Filesystem". If you ever want the mechanics: read this. The series you are reading now comes at it from the other side: what living through the alternative actually costs you and me, and why that should change how you pick the tools you depend on. The specific protocol we are talking about is called AT Protocol (atproto for short). The wider ecosystem of apps and servers built on top has its own name: the Atmosphere, and the single account you have (that gives you access to all apps and the whole cabinet) is thus called your Atmosphere account. Bluesky, the app most people have heard of, is just one app in the Atmosphere. Not the protocol itself. Just one view among many. (Also see Roel van Hooydonck's "the Atmosphere is already here") When someone wants a feature Bluesky doesn't have (like a lot of users keep screaming about wanting an edit button), the answer is increasingly "just use a different app on the same network." Apps like mu.social or Skywalker read the exact same posts and followers, and they do have the edit button Bluesky lacks. Same data, a different view, different features. And it isn't only microblogging. Any app can add a new kind of content type to the cabinet, so it can hold almost anything: writing, photos, films you've rated, events, even a code repo. One app shows your photos, another your writing, another your reviews. Some apps even show you multiple content types. And all are just looking into the same cabinet. (Episode 4 gets into how.) Sidenote: The cabinet and everything in it is yours: what you make, and your identity. But you don't have to own the building it sits in: most people let a host keep the cabinet (often free), some self-host. Either way you can move the whole thing elsewhere whenever you want. It still feels like a bit of magic, even after years in closed systems: you can move all your content to a new host, yet your links don't break, and every app you use keeps working, nothing to change. And if you ever tried to do this with Mastodon and are afraid this is going to be hard: the UX is actually surprisingly good and simple. That's the opposite of a vault like LinkedIn or Instagram, where your stuff sits in their building, behind their lock: you can leave, but they keep all your contacts and content. One company runs most of this today Before this turns into a sales pitch: today, one company (Bluesky PBC) created and still runs most of the atproto infrastructure, the main data server, the relay, the app most people use. The protocol is decentralized in its architecture. The operation, right now, isn't. The whole bet of this series is that this changes, that the protocol outlives any single company. If you watched email get swallowed by a handful of inboxes, that skepticism is earned, and I'm not going to argue you out of it. But it's already changing fast: Blacksky already hosts over 35K accounts, Eurosky is a European non-profit that hosts over 20K accounts, now runs its own independent slice of the stack and also shipped mu.social, a full replacement for the Bluesky app. And they all can just do this without asking anyone (including Bluesky) for permission. That's the thing about a protocol: nobody has to. Concrete alternative infrastructure is running right now, governed by people who aren't the original company. The bet's starting to pay out. Of course atproto isn't the only attempt at an open social web: The fediverse (Mastodon and friends) runs on an older protocol, ActivityPub, and has been at it longer. I build on atproto, so that's what this series follows. My bet's on it because, in my view, it does two things better: your account is portable (take it, contacts and all, to another provider without starting over), and a whole range of apps read and write the same data instead of each walling off its own. Episode 7 compares them in more detail. What changes when you own the cabinet When your data and your contacts live in a place you actually control, a few important things change: - Your contacts are yours, not the platform's, and can be shared between apps. - Apps compete on how good the view is, not on how well they onboard you and trap your data so you won't leave. - When an app dies (and apps die), your data always survives it. You can feel the incentive shift in small things. On most platforms like LinkedIn and X, posting a link quietly costs you reach, because they'd rather you didn't send users elsewhere. Bluesky's COO Rose Wang put it the other way round: "we don't de-promote your links. Post all the links you want, Bluesky is a lobby to the open web." When an app doesn't own your audience, it has less reason to hold it hostage. Another concrete example: I'm building Sifa ID, a professional profile on atproto, the useful parts of LinkedIn (your work history, your skills, your contacts) living in your own cabinet, not in Sifa's database. If Sifa disappears tomorrow, you keep your profile, your CV and your contacts, and any other app can still read them. That's how building on this protocol works, and it's pretty much the opposite of the LinkedIn problem in the opening above. Episode 4 walks through the wider ecosystem of apps already doing this. Still early, and worth watching This is all still young: Bluesky only opened to the public in February 2024, and the protocol under it dates to 2023. Early enough that the momentum is hard to look away from, and early enough that plenty still needs fixing. The rest of this series digs into both. This also brings us to an interesting next step that is getting some heated discussions lately: who are you actually? If your posts and contacts are yours, what actually proves you're you, and not someone who grabbed your username? That's where this whole thing could either fall apart or hold together. Let's talk about that in Part 2. --- Part 1 of 7. Full series at /series/atproto/. I'm building two products on atproto (details on the series page).Jun 25, 2026Outsource your GitHub CI to a VPS: cheaper, faster, and a free backup server tooI spent $60 on GitHub Actions minutes last month. The CI run on my biggest repo was crawling at 12 minutes per PR, long enough that I'd context-switch and lose the thread before it finished. So instead of throwing more money at GitHub, I rented a small VPS for about half the price and pointed my workflows at it. CI now finishes in 3 minutes. Same workflows, same tests, just running on a different box. As a bonus, that same VPS can now also double as an encrypted backup target. If you're already comfortable with GitHub Actions and currently paying €30+/month for hosted minutes (or just waiting too long for green checks), this guide is for you 👇 What's actually happening here GitHub Actions has two kinds of runners: - GitHub-hosted runners: the default ubuntu-latest VMs. Convenient, but on private repos you pay per minute, and the 2-core/8GB shape is modest for anything beyond toy projects. - Self-hosted runners: your own machine, registered with GitHub. The runner agent polls GitHub for jobs, executes them locally, and reports results back. No inbound ports. No managed-service complexity. GitHub doesn't charge you for self-hosted runner minutes today. They floated a $0.002/min platform fee for self-hosted earlier this year but postponed it past the announced March 2026 start. So right now: a self-hosted runner costs you exactly what the box costs. A "box" here can be a refurbished mini PC under your desk, a Raspberry Pi cluster, your homelab, or (easiest) a cheap VPS. I went with the VPS route because I wanted something always-on, with predictable network performance. Quick note if you're on Tangled instead of GitHub If you've already moved your code to Tangled (the atproto-native git forge): you also have this option. You just run a Spindle on it instead of a GitHub Actions runner. Spindles are Tangled's CI runners, self-hosted by design: they subscribe to pipeline events from your knot over a websocket, spin up a Docker container per run, and pull dependencies from nixpkgs. The same "rent a small VPS, run the runner there" maths works exactly the same way. Setup is in the official Spindle blog post, and the YAML syntax is close enough to GitHub Actions that porting workflows is mostly mechanical. If you want to keep using something other than Spindle's native pipelines, take a look at mitchellh.com/tack, which helps you stitch arbitrary CI into Tangled. The rest of this guide is GitHub-specific, but the sizing, security, and "what else to do with the box" sections are the same. The problem with paying GitHub for hosted minutes Four things that bit me: - The price stacks up fast if you actually use it. I blow through the allotted 3,000 minutes (that come with the paid plan) in a few busy days, then pay $0.008/min compute + $0.002/min platform fee for every additional minute on a 2-core runner. Bigger runners cost more. For context, last month (May 2026) my org burned 14,987 Linux minutes across active repos: $89.92 gross, $55.28 net after the included minutes. The bulk of that ($60) came from one repo with a heavy Next.js build + test suite. That's heavy active development, not "a few PRs a day", but the maths scales linearly: cut your usage in half and you're still well past the free tier on any non-toy project. - GitHub's ubuntu-latest is small. 2 cores, 8GB RAM. Fine for linting, painful for a Next.js build plus a typecheck plus a vitest suite plus an audit job. - Wall-clock is bounded by node-startup overhead. Even when your actual job is fast, GitHub has to pick up the job, allocate a runner, and bring it online before any of your steps execute. On a hot self-hosted runner, that startup is near zero. - GitHub's reliability is not great lately. Trying to make myself more and more independent of it is just a smart way to go about it imho... The result: I pay more, wait longer, and have less control over the runtime. What I did instead I rented a single 8 vCPU / 16 GB RAM Hetzner Cloud VPS (CPX42, AMD EPYC, 320GB NVMe storage, €32/month at the time of writing). Hetzner adjusted prices on 1 April 2026, so check the current rate. If you are happy to host outside the EU, cheaper options are available. On that box I run four parallel runner agents, all registered to the same self-hosted pool with a shared label. Each runner picks up one job at a time, so the box can chew through four CI jobs concurrently. That matters a lot once you split your test suite into shards. The CI workflow then asks for that pool by label, and the GitHub-hosted aggregator step only kicks in at the end to fan-in the results. Most of the speed-up comes from dropping the "one CI job at a time" default: once you control the box, you can run several jobs in parallel and shard slow suites across them. End result on my biggest repo: 12 minutes down to 3-4 minutes wall-clock, for about half the monthly cost. What you need to make this work Before you start, make sure you have: - A VPS or any always-on Linux box. I'll use Hetzner Cloud as the concrete example, but Scaleway, OVH, Netcup, Hostinger, your homelab Proxmox, or that old Intel NUC in a drawer all work the same way. Sizing: 4 vCPU / 8 GB RAM is ok for non-trivial JS/TS projects. 8 vCPU / 16 GB lets you run more parallel runners. - Admin access on your GitHub repo or org: you'll need to register the runner under Repository Settings, then Actions, then Runners. Org-level if you want to share runners across repos. - SSH access to the box, and basic comfort with systemd, ufw, and Docker (or a capable LLM to do that for you). - A workflow you can change. If your CI is locked down by policy, talk to whoever owns it before pointing it at infrastructure you control. A note on security: a self-hosted runner runs whatever your workflow tells it to run. For private repos this is fine, because only people who can push to the repo can trigger jobs. Do not connect a self-hosted runner to a public repo unless you really know what you're doing. A malicious PR can execute arbitrary code on your box. GitHub warns about this explicitly. The setup, step by step Here's the setup step by step for you to execute, or to point your LLM to. In my experience, agents can do a pretty good job of handling this much faster than you can manually. 1. Provision the VPS I use Hetzner Cloud, which is a few clicks: Ubuntu 24.04, the size you want, an SSH key. Same idea on any box/provider. Once it's up, harden it the usual way: bash As root, the moment the box is reachable adduser deploy usermod -aG sudo deploy rsync --archive --chown=deploy:deploy /.ssh /home/deploy Lock down SSH (PermitRootLogin no, PasswordAuthentication no) sed -i 's/^#\?PermitRootLogin./PermitRootLogin no/' /etc/ssh/sshdconfig sed -i 's/^#\?PasswordAuthentication./PasswordAuthentication no/' /etc/ssh/sshdconfig systemctl restart ssh Firewall: nothing inbound except SSH. The runner is outbound-only. ufw allow OpenSSH ufw --force enable The runner doesn't need any open inbound ports, it polls GitHub over HTTPS. Nice security property: the VPS has no public attack surface beyond SSH. 2. Install whatever your jobs need Whatever was implicit on ubuntu-latest you now have to install explicitly. For a typical JS/TS project that means: bash Node (via your favourite manager: fnm, nvm, or apt) curl -fsSL https://fnm.vercel.app/install | bash fnm install 22 && fnm default 22 pnpm/npm. Note that Node 26+ dropped corepack from default installs, so don't assume corepack enable works on a fresh box. npm install -g pnpm@10 Git, build tools apt-get install -y git build-essential Docker, if your tests use containers (e.g. Postgres for integration tests) curl -fsSL https://get.docker.com | sh usermod -aG docker deploy Don't underestimate this part. Every transitive dependency the GitHub-hosted image bundled for you (ImageMagick, Chrome, headless browsers, language runtimes) you may need to install or pull on demand. Take note of what your workflow currently uses. 3. Register one runner In GitHub: open Repo (or Org) Settings, then Actions, then Runners, then "New self-hosted runner". Pick Linux x64. GitHub shows you a download and configure block that looks roughly like this: bash mkdir -p /opt/actions-runner-1 && cd /opt/actions-runner-1 curl -o actions-runner-linux-x64.tar.gz -L \ https://github.com/actions/runner/releases/download/vX.Y.Z/actions-runner-linux-x64-X.Y.Z.tar.gz tar xzf actions-runner-linux-x64.tar.gz ./config.sh \ --url https://github.com/YOURORG/YOURREPO \ --token YOURREGISTRATIONTOKEN \ --name runner-1 \ --labels self-hosted-ci \ --unattended The label matters: it's how your workflow targets this pool. Pick something specific to your team, not the generic self-hosted. Then install it as a systemd service so it survives reboots: bash ./svc.sh install deploy ./svc.sh start You should now see "runner-1, Idle" on the GitHub Settings page. That alone is enough to run jobs. 4. Run multiple runners on the same box This is where the speed-up really comes from ⚡. A 16GB box can comfortably host 3-4 concurrent JS/TS jobs. Repeat step 3 with different directories and names: bash mkdir -p /opt/actions-runner-{2,3,4} Get a fresh registration token from GitHub for each ./config.sh ... --name runner-2 ... ./svc.sh install deploy && ./svc.sh start All four runners share the self-hosted-ci label. When a CI run kicks off four matrix jobs, GitHub hands one to each idle runner. They execute in parallel, on the same box, no coordination needed. Reality check on sizing: each Node pnpm install + pnpm build can briefly spike RAM hard. On a 16GB box with 4 runners, I've occasionally seen one shard get OOM-killed during peak. If you see that, drop to 3 runners or move to a bigger box. CPU isn't usually the bottleneck, memory is. 5. Point your workflow at the runner pool In your workflow file: yaml jobs: test: runs-on: ${{ vars.CIRUNNER || 'self-hosted-ci' }} strategy: fail-fast: false matrix: shard: [1, 2, 3] steps: - uses: actions/checkout@v4 - uses: ./.github/actions/setup - run: pnpm vitest run --shard=${{ matrix.shard }}/3 Two things to notice. The vars.CIRUNNER fallback. This reads a repository variable if it's set, otherwise defaults to your self-hosted label. If your VPS dies at 2am, you set CIRUNNER=ubuntu-latest in repo settings and every workflow falls back to GitHub-hosted runners on the next push. No code change, no PR. This one variable buys you a lot of sleep. The shard matrix. Vitest, Jest, Playwright, and most modern test runners support --shard=N/total. With four runners idle and a 3-way shard, your test job runs in roughly a third of the previous wall-clock. Tune the shard count to the slowest job, not the average. 6. Keep one job on GitHub-hosted as a safety net In my setup, every job moved to self-hosted except the final aggregator: yaml check: needs: [lint, typecheck, test, build, audit] runs-on: ubuntu-latest intentionally stays GitHub-hosted if: always() steps: - name: Fail if any dependency failed or was cancelled if: contains(needs..result, 'failure') || contains(needs..result, 'cancelled') run: exit 1 - name: Success run: echo "All jobs passed" I did this because the aggregator is the required check that gates merges. If your self-hosted box goes down mid-run, jobs that haven't started yet get stuck in "queued" forever, but the aggregator on ubuntu-latest will still resolve and at least give you a clean failure signal. It's also a near-zero-cost job: GitHub-hosted minutes for a 5-second exit 0 are noise on the bill. 7. (Optional) Keep e2e on GitHub-hosted My Playwright e2e workflow still runs on ubuntu-latest. It's a separate workflow file, runs nightly, and the marginal cost is small. Keeping it isolated means flaky browser tests don't tie up my CI runner pool during the day. Pick which jobs go where based on frequency times duration, no need for aJun 1, 2026

On Bluesky

Dan Szabo
@dan.mu.social ·

Hi Paula, It's the classic 2048 tile game that's in the ATmosphere that populates the pieces with people you follow on Bluesky. Everytime you play the game it changes the pieces. It's at 2048.social