Judge of pull requests. One inbox for your PRs — GitHub and every Gitea, Forgejo, or Codeberg server you use, including self-hosted instances on your own network. Review the diff, read the conversation, check CI, comment, approve, request changes, and merge — from your phone, in seconds.
Available on the App Store · free, no account, no analytics.
ios/— the SwiftUI app. Talks directly to GitHub and Gitea-family APIs with tokens that never leave the device Keychain.app.py— an optional self-hosted proxy (FastAPI). Lets the app reach a git server that isn't exposed to the internet: the proxy sits next to your server and is published behind Cloudflare Access (or any service-token-style gate). Also includes a stateless push gateway (/api/push) that forwards new-PR webhook events to APNs without storing anything.relay/— tiny webhook relay templates (Cloudflare Worker, AWS Lambda, Azure Function) so push notifications work without running the proxy at all.
Most people only need the app: add a GitHub or Gitea-family token in Settings and go. The server pieces are for the self-hosting crowd.
Requires Xcode and xcodegen:
cd ios
xcodegen generate
open Minos.xcodeprojTokens are stored in the Keychain only, and sent only to the server they
belong to. No middleman: a GitHub token goes to api.github.com, a
Gitea-family token to the server address you enter. Privacy policy:
https://minos.botelle.org/privacy.
cp .env.example .env # server URL, token, repo list, allowed emails
podman build -t minos . # or docker
podman run --env-file .env -p 8790:8790 minosThe proxy fails closed (no allowed emails → 403 everything except
/healthz) and refuses merges server-side unless CI is green and the PR is
mergeable. It verifies the Cf-Access-Jwt-Assertion signature when
CF_TEAM_DOMAIN/CF_ACCESS_AUD are set, so even a misconfigured gate still
hits cryptographic auth. Publish it through whatever gate you trust; the app
sends Cloudflare Access service-token headers if you configure them in
Settings → Custom proxy.
When a base branch's protection rule requires branches to be up to date
before merging, merging PR 1 of a stack outdates PRs 2‑N — each then needs a
manual "update branch", a CI wait, and a merge retry. Set
AUTO_UPDATE_TRAIN=true and the proxy does that legwork: after every merge
it updates each other open PR targeting the same base, watches its CI, and
sends a push (same channel as new-PR notifications) once it's green or if it
fails. It also catches Forgejo's own "branch is out of date" merge rejection
and drives that one PR the same way instead of just returning an error. Off
by default.
Forgejo only retargets a stacked PR onto its grandparent branch when the
merged PR's base branch is deleted — otherwise every sibling PR is left
pointing at a branch that no longer exists. Set DELETE_BRANCH_ON_MERGE=true
to have the proxy ask Forgejo to delete the head branch on merge (skipped for
forks, whose branches aren't ours to delete), so a stack of PRs retargets
automatically instead of needing a manual rebase per PR. Off by default.
Point a repository webhook at one of the relay/ templates (or the proxy's
/webhook/github). The relay forwards repo name, PR number/title/author,
and your device token to APNs — nothing is stored anywhere. Setup is walked
through in the app: Settings → Notifications.
AGPL-3.0. Use it, fork it, sell services around it — but derivative work, including hosted versions, must stay open source.