Log

Seven clients, and what each one refuses to pretend

May added four platforms in ten days: Codeberg and the Gitea family in 0.7.13, Sourcehut in 0.7.15, Radicle in 0.7.16, Bitbucket Cloud in 0.7.17, and Azure…

May added four platforms in ten days: Codeberg and the Gitea family in 0.7.13, Sourcehut in 0.7.15, Radicle in 0.7.16, Bitbucket Cloud in 0.7.17, and Azure DevOps in 0.7.18. That makes seven clients over nine hosts, and it is worth writing down how the routing works before the list gets any longer.

git remote -v git@gitlab.com:paskidev/… host detection + platforms.toml gitea → Gitea · Codeberg · Forgejo github · gitlab · bitbucket sourcehut · radicle · azure every client answers the same five: pr · issue · pipeline · release · package where a platform has no such concept, the answer is an explicit error, not a pretence: bitbucket has no release object · radicle has no CI · sourcehut takes patches by email --remote NAME picks which one answers when the repository is mirrored

The URL decides

You never name the platform. torii pr list looks at the remote it is about to talk to, matches the host, and dispatches to the client for it. dev.azure.com and the legacy *.visualstudio.com both mean Azure; rad:// means Radicle; git.sr.ht means Sourcehut.

Self-hosted installations break that, because the host is whatever you called it. From 0.8.0, ~/.config/torii/platforms.toml is where you say so: a host, a platform kind, and the detection routes it like any other.

One client, three hosts

Gitea, Codeberg and Forgejo share a single client, because Codeberg is Gitea and Forgejo is a fork that kept the API. Three names in torii auth, one implementation underneath, and resolve_gitea_token tries the three in order. That is why the site quotes seven clients and nine hosts as different numbers: they are.

Where the abstraction stops

Every client answers the same five questions — pull requests, issues, pipelines, releases, packages — and this is where it would be easy to lie. Bitbucket Cloud has no release object and no package registry. Radicle has no CI, no release page, and identifies its patches by content hash rather than by the numeric id the traits take. Sourcehut takes patches by email, not as a merge request.

None of those return an empty list. An empty list means "there are none", and the truth is "this platform has no such thing" — so they return an error that says exactly that, and points at what the platform does instead. A tool that quietly returns nothing teaches you to distrust every empty result it ever gives you.

Mirrored repositories

Once a repository lives on more than one platform, "the platform" is ambiguous: each backend has its own pipelines, its own releases, its own packages. --remote NAME picks one:

torii pipeline list --remote origin
torii release edit v0.13.0 --notes new.md --remote github-paskidev

Each also has its own token, so operating on both means both are configured. The flag is global within its command, which means torii pipeline --remote NAME list and torii pipeline list --remote NAME are the same sentence with the words in a different order, and both work.

What is still owed

Repository visibility — flipping public to private — is wired for GitHub and GitLab only. The Gitea family and Bitbucket expose the same call and are not connected yet; Azure puts visibility on the project rather than the repository, so there the honest answer is an error pointing you at the project settings. It is on the roadmap, and until it lands the table on the comparison page says so.